]> git.proxmox.com Git - mirror_frr.git/blob - zebra/table_manager.c
Merge pull request #1985 from sfionov/fpm_pb_optional_scalar
[mirror_frr.git] / zebra / table_manager.c
1 /* zebra table Manager for routing table identifier management
2 * Copyright (C) 2018 6WIND
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/types.h>
22
23 #include "zebra.h"
24 #include "zserv.h"
25 #include "lib/log.h"
26 #include "lib/memory.h"
27 #include "lib/table.h"
28 #include "lib/network.h"
29 #include "lib/stream.h"
30 #include "lib/zclient.h"
31 #include "lib/libfrr.h"
32 #include "lib/vrf.h"
33
34 #include "zebra_vrf.h"
35 #include "label_manager.h" /* for NO_PROTO */
36 #include "table_manager.h"
37
38 /* routing table identifiers
39 *
40 */
41 #ifdef SUNOS_5
42 /* SunOS
43 */
44 #else
45 #if !defined(GNU_LINUX) && !defined(SUNOS_5)
46 /* BSD systems
47 */
48 #else
49 /* Linux Systems
50 */
51 #define RT_TABLE_ID_LOCAL 255
52 #define RT_TABLE_ID_MAIN 254
53 #define RT_TABLE_ID_DEFAULT 253
54 #define RT_TABLE_ID_COMPAT 252
55 #define RT_TABLE_ID_UNSPEC 0
56 #endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
57 #endif /* SUNOS_5 */
58 #define RT_TABLE_ID_UNRESERVED_MIN 1
59 #define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
60
61 struct table_manager tbl_mgr;
62
63 DEFINE_MGROUP(TABLE_MGR, "Table Manager");
64 DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
65
66 static void delete_table_chunk(void *val)
67 {
68 XFREE(MTYPE_TM_CHUNK, val);
69 }
70
71 /**
72 * Init table manager
73 */
74 void table_manager_enable(ns_id_t ns_id)
75 {
76 if (ns_id != NS_DEFAULT)
77 return;
78 tbl_mgr.lc_list = list_new();
79 tbl_mgr.lc_list->del = delete_table_chunk;
80 }
81
82 /**
83 * Core function, assigns table chunks
84 *
85 * It first searches through the list to check if there's one available
86 * (previously released). Otherwise it creates and assigns a new one
87 *
88 * @param proto Daemon protocol of client, to identify the owner
89 * @param instance Instance, to identify the owner
90 * @para size Size of the table chunk
91 * @return Pointer to the assigned table chunk
92 */
93 struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
94 uint32_t size)
95 {
96 struct table_manager_chunk *tmc;
97 struct listnode *node;
98 uint32_t start;
99
100 /* first check if there's one available */
101 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
102 if (tmc->proto == NO_PROTO
103 && tmc->end - tmc->start + 1 == size) {
104 tmc->proto = proto;
105 tmc->instance = instance;
106 return tmc;
107 }
108 }
109 /* otherwise create a new one */
110 tmc = XCALLOC(MTYPE_TM_CHUNK, sizeof(struct table_manager_chunk));
111 if (!tmc)
112 return NULL;
113
114 /* table RT IDs range are [1;252] and [256;0xffffffff]
115 * - check if the requested range can be within the first range,
116 * otherwise elect second one
117 * - TODO : vrf-lites have their own table identifier.
118 * In that case, table_id should be removed from the table range.
119 */
120 if (list_isempty(tbl_mgr.lc_list))
121 start = RT_TABLE_ID_UNRESERVED_MIN;
122 else
123 start = ((struct table_manager_chunk *)listgetdata(
124 listtail(tbl_mgr.lc_list)))->end + 1;
125
126 #ifdef SUNOS_5
127 /* SunOS
128 */
129 #else
130 #if !defined(GNU_LINUX) && !defined(SUNOS_5)
131 /* BSD systems
132 */
133 #else
134 /* Linux Systems
135 */
136 /* if not enough room space between MIN and COMPAT,
137 * then begin after LOCAL
138 */
139 if (start < RT_TABLE_ID_COMPAT && (size >
140 RT_TABLE_ID_COMPAT
141 - RT_TABLE_ID_UNRESERVED_MIN))
142 start = RT_TABLE_ID_LOCAL + 1;
143 #endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
144 #endif /* SUNOS_5 */
145 tmc->start = start;
146 if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
147 zlog_err("Reached max table id. Start/Size %u/%u",
148 start, size);
149 XFREE(MTYPE_TM_CHUNK, tmc);
150 return NULL;
151 }
152 tmc->end = tmc->start + size - 1;
153 tmc->proto = proto;
154 tmc->instance = instance;
155 listnode_add(tbl_mgr.lc_list, tmc);
156
157 return tmc;
158 }
159
160 /**
161 * Core function, release no longer used table chunks
162 *
163 * @param proto Daemon protocol of client, to identify the owner
164 * @param instance Instance, to identify the owner
165 * @param start First table RT ID of the chunk
166 * @param end Last table RT ID of the chunk
167 * @return 0 on success, -1 otherwise
168 */
169 int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
170 uint32_t end)
171 {
172 struct listnode *node;
173 struct table_manager_chunk *tmc;
174 int ret = -1;
175
176 /* check that size matches */
177 zlog_debug("Releasing table chunk: %u - %u", start, end);
178 /* find chunk and disown */
179 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
180 if (tmc->start != start)
181 continue;
182 if (tmc->end != end)
183 continue;
184 if (tmc->proto != proto || tmc->instance != instance) {
185 zlog_err("%s: Daemon mismatch!!", __func__);
186 continue;
187 }
188 tmc->proto = NO_PROTO;
189 tmc->instance = 0;
190 ret = 0;
191 break;
192 }
193 if (ret != 0)
194 zlog_err("%s: Table chunk not released!!", __func__);
195
196 return ret;
197 }
198
199 /**
200 * Release table chunks from a client.
201 *
202 * Called on client disconnection or reconnection. It only releases chunks
203 * with empty keep value.
204 *
205 * @param proto Daemon protocol of client, to identify the owner
206 * @param instance Instance, to identify the owner
207 * @return Number of chunks released
208 */
209 int release_daemon_table_chunks(uint8_t proto, uint16_t instance)
210 {
211 struct listnode *node;
212 struct table_manager_chunk *tmc;
213 int count = 0;
214 int ret;
215
216 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
217 if (tmc->proto == proto && tmc->instance == instance) {
218 ret = release_table_chunk(tmc->proto, tmc->instance,
219 tmc->start, tmc->end);
220 if (ret == 0)
221 count++;
222 }
223 }
224
225 zlog_debug("%s: Released %d table chunks", __func__, count);
226
227 return count;
228 }
229
230 void table_manager_disable(ns_id_t ns_id)
231 {
232 if (ns_id != NS_DEFAULT)
233 return;
234 list_delete_and_null(&tbl_mgr.lc_list);
235 }