]> git.proxmox.com Git - mirror_frr.git/blame - zebra/table_manager.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / zebra / table_manager.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
50261279
PG
2/* zebra table Manager for routing table identifier management
3 * Copyright (C) 2018 6WIND
50261279
PG
4 */
5
453844ab
QY
6#include "zebra.h"
7
50261279
PG
8#include <stdio.h>
9#include <string.h>
10#include <sys/types.h>
11
50261279
PG
12#include "lib/log.h"
13#include "lib/memory.h"
14#include "lib/table.h"
15#include "lib/network.h"
16#include "lib/stream.h"
17#include "lib/zclient.h"
18#include "lib/libfrr.h"
19#include "lib/vrf.h"
20
453844ab
QY
21#include "zebra/zserv.h"
22#include "zebra/zebra_vrf.h"
23#include "zebra/label_manager.h" /* for NO_PROTO */
24#include "zebra/table_manager.h"
43e52561 25#include "zebra/zebra_errors.h"
50261279
PG
26
27/* routing table identifiers
28 *
29 */
cae8bc96 30#if !defined(GNU_LINUX)
50261279
PG
31/* BSD systems
32 */
33#else
34/* Linux Systems
35 */
36#define RT_TABLE_ID_LOCAL 255
37#define RT_TABLE_ID_MAIN 254
38#define RT_TABLE_ID_DEFAULT 253
39#define RT_TABLE_ID_COMPAT 252
40#define RT_TABLE_ID_UNSPEC 0
cae8bc96 41#endif /* !def(GNU_LINUX) */
50261279
PG
42#define RT_TABLE_ID_UNRESERVED_MIN 1
43#define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
44
50261279
PG
45DEFINE_MGROUP(TABLE_MGR, "Table Manager");
46DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
42d4b30e 47DEFINE_MTYPE_STATIC(TABLE_MGR, TM_TABLE, "Table Manager Context");
50261279
PG
48
49static void delete_table_chunk(void *val)
50{
51 XFREE(MTYPE_TM_CHUNK, val);
52}
53
54/**
55 * Init table manager
56 */
42d4b30e 57void table_manager_enable(struct zebra_vrf *zvrf)
50261279 58{
42d4b30e
PG
59
60 if (zvrf->tbl_mgr)
50261279 61 return;
9742796f
IR
62 if (!vrf_is_backend_netns()
63 && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
42d4b30e
PG
64 struct zebra_vrf *def = zebra_vrf_lookup_by_id(VRF_DEFAULT);
65
66 if (def)
67 zvrf->tbl_mgr = def->tbl_mgr;
68 return;
69 }
70 zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager));
71 zvrf->tbl_mgr->lc_list = list_new();
72 zvrf->tbl_mgr->lc_list->del = delete_table_chunk;
50261279
PG
73}
74
75/**
76 * Core function, assigns table chunks
77 *
78 * It first searches through the list to check if there's one available
79 * (previously released). Otherwise it creates and assigns a new one
80 *
81 * @param proto Daemon protocol of client, to identify the owner
82 * @param instance Instance, to identify the owner
83 * @para size Size of the table chunk
84 * @return Pointer to the assigned table chunk
85 */
86struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
42d4b30e
PG
87 uint32_t size,
88 struct zebra_vrf *zvrf)
50261279
PG
89{
90 struct table_manager_chunk *tmc;
91 struct listnode *node;
92 uint32_t start;
42d4b30e
PG
93 bool manual_conf = false;
94
95 if (!zvrf)
96 return NULL;
50261279
PG
97
98 /* first check if there's one available */
42d4b30e 99 for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
50261279
PG
100 if (tmc->proto == NO_PROTO
101 && tmc->end - tmc->start + 1 == size) {
102 tmc->proto = proto;
103 tmc->instance = instance;
104 return tmc;
105 }
106 }
107 /* otherwise create a new one */
108 tmc = XCALLOC(MTYPE_TM_CHUNK, sizeof(struct table_manager_chunk));
50261279 109
42d4b30e
PG
110 if (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)
111 manual_conf = true;
50261279
PG
112 /* table RT IDs range are [1;252] and [256;0xffffffff]
113 * - check if the requested range can be within the first range,
114 * otherwise elect second one
115 * - TODO : vrf-lites have their own table identifier.
116 * In that case, table_id should be removed from the table range.
117 */
42d4b30e
PG
118 if (list_isempty(zvrf->tbl_mgr->lc_list)) {
119 if (!manual_conf)
120 start = RT_TABLE_ID_UNRESERVED_MIN;
121 else
122 start = zvrf->tbl_mgr->start;
123 } else
50261279 124 start = ((struct table_manager_chunk *)listgetdata(
42d4b30e
PG
125 listtail(zvrf->tbl_mgr->lc_list)))
126 ->end
127 + 1;
128
129 if (!manual_conf) {
50261279 130
cae8bc96 131#if !defined(GNU_LINUX)
50261279
PG
132/* BSD systems
133 */
134#else
135/* Linux Systems
136 */
42d4b30e
PG
137 /* if not enough room space between MIN and COMPAT,
138 * then begin after LOCAL
139 */
140 if (start < RT_TABLE_ID_COMPAT
141 && (size > RT_TABLE_ID_COMPAT - RT_TABLE_ID_UNRESERVED_MIN))
142 start = RT_TABLE_ID_LOCAL + 1;
cae8bc96 143#endif /* !def(GNU_LINUX) */
42d4b30e
PG
144 tmc->start = start;
145 if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
146 flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
147 "Reached max table id. Start/Size %u/%u",
148 start, size);
149 XFREE(MTYPE_TM_CHUNK, tmc);
150 return NULL;
151 }
152 } else {
153 tmc->start = start;
154 if (zvrf->tbl_mgr->end - size + 1 < start) {
155 flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
156 "Reached max table id. Start/Size %u/%u",
157 start, size);
158 XFREE(MTYPE_TM_CHUNK, tmc);
159 return NULL;
160 }
50261279
PG
161 }
162 tmc->end = tmc->start + size - 1;
163 tmc->proto = proto;
164 tmc->instance = instance;
42d4b30e 165 listnode_add(zvrf->tbl_mgr->lc_list, tmc);
50261279
PG
166
167 return tmc;
168}
169
170/**
171 * Core function, release no longer used table chunks
172 *
173 * @param proto Daemon protocol of client, to identify the owner
174 * @param instance Instance, to identify the owner
175 * @param start First table RT ID of the chunk
176 * @param end Last table RT ID of the chunk
177 * @return 0 on success, -1 otherwise
178 */
179int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
42d4b30e 180 uint32_t end, struct zebra_vrf *zvrf)
50261279
PG
181{
182 struct listnode *node;
183 struct table_manager_chunk *tmc;
184 int ret = -1;
42d4b30e
PG
185 struct table_manager *tbl_mgr;
186
187 if (!zvrf)
188 return -1;
50261279 189
42d4b30e
PG
190 tbl_mgr = zvrf->tbl_mgr;
191 if (!tbl_mgr)
192 return ret;
50261279
PG
193 /* check that size matches */
194 zlog_debug("Releasing table chunk: %u - %u", start, end);
195 /* find chunk and disown */
42d4b30e 196 for (ALL_LIST_ELEMENTS_RO(tbl_mgr->lc_list, node, tmc)) {
50261279
PG
197 if (tmc->start != start)
198 continue;
199 if (tmc->end != end)
200 continue;
201 if (tmc->proto != proto || tmc->instance != instance) {
e914ccbe 202 flog_err(EC_ZEBRA_TM_DAEMON_MISMATCH,
1c50c1c0 203 "%s: Daemon mismatch!!", __func__);
50261279
PG
204 continue;
205 }
206 tmc->proto = NO_PROTO;
207 tmc->instance = 0;
208 ret = 0;
209 break;
210 }
211 if (ret != 0)
e914ccbe 212 flog_err(EC_ZEBRA_TM_UNRELEASED_CHUNK,
1c50c1c0 213 "%s: Table chunk not released!!", __func__);
50261279
PG
214
215 return ret;
216}
217
218/**
219 * Release table chunks from a client.
220 *
221 * Called on client disconnection or reconnection. It only releases chunks
222 * with empty keep value.
223 *
453844ab 224 * @param client the client to release chunks from
50261279
PG
225 * @return Number of chunks released
226 */
453844ab 227int release_daemon_table_chunks(struct zserv *client)
50261279 228{
453844ab
QY
229 uint8_t proto = client->proto;
230 uint16_t instance = client->instance;
50261279
PG
231 struct listnode *node;
232 struct table_manager_chunk *tmc;
233 int count = 0;
234 int ret;
42d4b30e
PG
235 struct vrf *vrf;
236 struct zebra_vrf *zvrf;
50261279 237
42d4b30e
PG
238 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
239 zvrf = vrf->info;
240
241 if (!zvrf)
242 continue;
243 if (!vrf_is_backend_netns() && vrf->vrf_id != VRF_DEFAULT)
244 continue;
245 for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
246 if (tmc->proto == proto && tmc->instance == instance) {
247 ret = release_table_chunk(
248 tmc->proto, tmc->instance, tmc->start,
249 tmc->end, zvrf);
250 if (ret == 0)
251 count++;
252 }
50261279
PG
253 }
254 }
50261279
PG
255 zlog_debug("%s: Released %d table chunks", __func__, count);
256
257 return count;
258}
259
42d4b30e
PG
260static void table_range_add(struct zebra_vrf *zvrf, uint32_t start,
261 uint32_t end)
262{
263 if (!zvrf->tbl_mgr)
264 return;
265 zvrf->tbl_mgr->start = start;
266 zvrf->tbl_mgr->end = end;
267}
268
269void table_manager_disable(struct zebra_vrf *zvrf)
50261279 270{
42d4b30e
PG
271 if (!zvrf->tbl_mgr)
272 return;
9742796f
IR
273 if (!vrf_is_backend_netns()
274 && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
42d4b30e 275 zvrf->tbl_mgr = NULL;
50261279 276 return;
42d4b30e
PG
277 }
278 list_delete(&zvrf->tbl_mgr->lc_list);
279 XFREE(MTYPE_TM_TABLE, zvrf->tbl_mgr);
280 zvrf->tbl_mgr = NULL;
281}
282
283int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf,
284 const char *start_table_str, const char *end_table_str)
285{
286 uint32_t start;
287 uint32_t end;
288
289 if (add) {
290 if (!start_table_str || !end_table_str) {
291 vty_out(vty, "%% Labels not specified\n");
292 return CMD_WARNING_CONFIG_FAILED;
293 }
294 start = atoi(start_table_str);
295 end = atoi(end_table_str);
296 if (end < start) {
297 vty_out(vty, "%% End table is less than Start table\n");
298 return CMD_WARNING_CONFIG_FAILED;
299 }
300
301#if !defined(GNU_LINUX)
302/* BSD systems
303 */
304#else
305 /* Linux Systems
306 */
307 if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL)
308 || (end >= RT_TABLE_ID_COMPAT
309 && end <= RT_TABLE_ID_LOCAL)) {
310 vty_out(vty, "%% Values forbidden in range [%u;%u]\n",
311 RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
312 return CMD_WARNING_CONFIG_FAILED;
313 }
314 if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) {
315 vty_out(vty,
316 "%% Range overlaps range [%u;%u] forbidden\n",
317 RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
318 return CMD_WARNING_CONFIG_FAILED;
319 }
320#endif
321 if (zvrf->tbl_mgr
322 && ((zvrf->tbl_mgr->start && zvrf->tbl_mgr->start != start)
323 || (zvrf->tbl_mgr->end && zvrf->tbl_mgr->end != end))) {
324 vty_out(vty,
325 "%% New range will be taken into account at restart\n");
326 }
327 table_range_add(zvrf, start, end);
328 } else
329 table_range_add(zvrf, 0, 0);
330 return CMD_SUCCESS;
50261279 331}