]> git.proxmox.com Git - mirror_frr.git/blame - zebra/table_manager.c
bgpd: don't use BGP_ATTR_VNC(255) unless ENABLE_BGP_VNC_ATTR is defined
[mirror_frr.git] / zebra / table_manager.c
CommitLineData
50261279
PG
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
453844ab
QY
19#include "zebra.h"
20
50261279
PG
21#include <stdio.h>
22#include <string.h>
23#include <sys/types.h>
24
50261279
PG
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
453844ab
QY
34#include "zebra/zserv.h"
35#include "zebra/zebra_vrf.h"
36#include "zebra/label_manager.h" /* for NO_PROTO */
37#include "zebra/table_manager.h"
43e52561 38#include "zebra/zebra_errors.h"
50261279
PG
39
40/* routing table identifiers
41 *
42 */
43#ifdef SUNOS_5
44/* SunOS
45 */
46#else
47#if !defined(GNU_LINUX) && !defined(SUNOS_5)
48/* BSD systems
49 */
50#else
51/* Linux Systems
52 */
53#define RT_TABLE_ID_LOCAL 255
54#define RT_TABLE_ID_MAIN 254
55#define RT_TABLE_ID_DEFAULT 253
56#define RT_TABLE_ID_COMPAT 252
57#define RT_TABLE_ID_UNSPEC 0
58#endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
59#endif /* SUNOS_5 */
60#define RT_TABLE_ID_UNRESERVED_MIN 1
61#define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
62
63struct table_manager tbl_mgr;
64
65DEFINE_MGROUP(TABLE_MGR, "Table Manager");
66DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
67
68static void delete_table_chunk(void *val)
69{
70 XFREE(MTYPE_TM_CHUNK, val);
71}
72
73/**
74 * Init table manager
75 */
76void table_manager_enable(ns_id_t ns_id)
77{
78 if (ns_id != NS_DEFAULT)
79 return;
80 tbl_mgr.lc_list = list_new();
81 tbl_mgr.lc_list->del = delete_table_chunk;
21ccc0cf 82 hook_register(zserv_client_close, release_daemon_table_chunks);
50261279
PG
83}
84
85/**
86 * Core function, assigns table chunks
87 *
88 * It first searches through the list to check if there's one available
89 * (previously released). Otherwise it creates and assigns a new one
90 *
91 * @param proto Daemon protocol of client, to identify the owner
92 * @param instance Instance, to identify the owner
93 * @para size Size of the table chunk
94 * @return Pointer to the assigned table chunk
95 */
96struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
97 uint32_t size)
98{
99 struct table_manager_chunk *tmc;
100 struct listnode *node;
101 uint32_t start;
102
103 /* first check if there's one available */
104 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
105 if (tmc->proto == NO_PROTO
106 && tmc->end - tmc->start + 1 == size) {
107 tmc->proto = proto;
108 tmc->instance = instance;
109 return tmc;
110 }
111 }
112 /* otherwise create a new one */
113 tmc = XCALLOC(MTYPE_TM_CHUNK, sizeof(struct table_manager_chunk));
114 if (!tmc)
115 return NULL;
116
117 /* table RT IDs range are [1;252] and [256;0xffffffff]
118 * - check if the requested range can be within the first range,
119 * otherwise elect second one
120 * - TODO : vrf-lites have their own table identifier.
121 * In that case, table_id should be removed from the table range.
122 */
123 if (list_isempty(tbl_mgr.lc_list))
124 start = RT_TABLE_ID_UNRESERVED_MIN;
125 else
126 start = ((struct table_manager_chunk *)listgetdata(
127 listtail(tbl_mgr.lc_list)))->end + 1;
128
129#ifdef SUNOS_5
130/* SunOS
131 */
132#else
133#if !defined(GNU_LINUX) && !defined(SUNOS_5)
134/* BSD systems
135 */
136#else
137/* Linux Systems
138 */
139 /* if not enough room space between MIN and COMPAT,
140 * then begin after LOCAL
141 */
142 if (start < RT_TABLE_ID_COMPAT && (size >
143 RT_TABLE_ID_COMPAT
144 - RT_TABLE_ID_UNRESERVED_MIN))
145 start = RT_TABLE_ID_LOCAL + 1;
146#endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
147#endif /* SUNOS_5 */
148 tmc->start = start;
149 if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
af4c2728 150 flog_err(ZEBRA_ERR_TM_EXHAUSTED_IDS,
43e52561
QY
151 "Reached max table id. Start/Size %u/%u", start,
152 size);
50261279
PG
153 XFREE(MTYPE_TM_CHUNK, tmc);
154 return NULL;
155 }
156 tmc->end = tmc->start + size - 1;
157 tmc->proto = proto;
158 tmc->instance = instance;
159 listnode_add(tbl_mgr.lc_list, tmc);
160
161 return tmc;
162}
163
164/**
165 * Core function, release no longer used table chunks
166 *
167 * @param proto Daemon protocol of client, to identify the owner
168 * @param instance Instance, to identify the owner
169 * @param start First table RT ID of the chunk
170 * @param end Last table RT ID of the chunk
171 * @return 0 on success, -1 otherwise
172 */
173int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
174 uint32_t end)
175{
176 struct listnode *node;
177 struct table_manager_chunk *tmc;
178 int ret = -1;
179
180 /* check that size matches */
181 zlog_debug("Releasing table chunk: %u - %u", start, end);
182 /* find chunk and disown */
183 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
184 if (tmc->start != start)
185 continue;
186 if (tmc->end != end)
187 continue;
188 if (tmc->proto != proto || tmc->instance != instance) {
af4c2728 189 flog_err(ZEBRA_ERR_TM_DAEMON_MISMATCH,
43e52561 190 "%s: Daemon mismatch!!", __func__);
50261279
PG
191 continue;
192 }
193 tmc->proto = NO_PROTO;
194 tmc->instance = 0;
195 ret = 0;
196 break;
197 }
198 if (ret != 0)
af4c2728 199 flog_err(ZEBRA_ERR_TM_UNRELEASED_CHUNK,
43e52561 200 "%s: Table chunk not released!!", __func__);
50261279
PG
201
202 return ret;
203}
204
205/**
206 * Release table chunks from a client.
207 *
208 * Called on client disconnection or reconnection. It only releases chunks
209 * with empty keep value.
210 *
453844ab 211 * @param client the client to release chunks from
50261279
PG
212 * @return Number of chunks released
213 */
453844ab 214int release_daemon_table_chunks(struct zserv *client)
50261279 215{
453844ab
QY
216 uint8_t proto = client->proto;
217 uint16_t instance = client->instance;
50261279
PG
218 struct listnode *node;
219 struct table_manager_chunk *tmc;
220 int count = 0;
221 int ret;
222
223 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
224 if (tmc->proto == proto && tmc->instance == instance) {
225 ret = release_table_chunk(tmc->proto, tmc->instance,
226 tmc->start, tmc->end);
227 if (ret == 0)
228 count++;
229 }
230 }
231
232 zlog_debug("%s: Released %d table chunks", __func__, count);
233
234 return count;
235}
236
237void table_manager_disable(ns_id_t ns_id)
238{
239 if (ns_id != NS_DEFAULT)
240 return;
241 list_delete_and_null(&tbl_mgr.lc_list);
242}