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