]> git.proxmox.com Git - mirror_frr.git/blob - zebra/table_manager.c
Merge pull request #3465 from donaldsharp/nexthop_active_update
[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 #include "zebra/zebra_errors.h"
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
63 struct table_manager tbl_mgr;
64
65 DEFINE_MGROUP(TABLE_MGR, "Table Manager");
66 DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
67
68 static void delete_table_chunk(void *val)
69 {
70 XFREE(MTYPE_TM_CHUNK, val);
71 }
72
73 /**
74 * Init table manager
75 */
76 void 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;
82 hook_register(zserv_client_close, release_daemon_table_chunks);
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 */
96 struct 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) {
150 flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
151 "Reached max table id. Start/Size %u/%u", start, size);
152 XFREE(MTYPE_TM_CHUNK, tmc);
153 return NULL;
154 }
155 tmc->end = tmc->start + size - 1;
156 tmc->proto = proto;
157 tmc->instance = instance;
158 listnode_add(tbl_mgr.lc_list, tmc);
159
160 return tmc;
161 }
162
163 /**
164 * Core function, release no longer used table chunks
165 *
166 * @param proto Daemon protocol of client, to identify the owner
167 * @param instance Instance, to identify the owner
168 * @param start First table RT ID of the chunk
169 * @param end Last table RT ID of the chunk
170 * @return 0 on success, -1 otherwise
171 */
172 int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
173 uint32_t end)
174 {
175 struct listnode *node;
176 struct table_manager_chunk *tmc;
177 int ret = -1;
178
179 /* check that size matches */
180 zlog_debug("Releasing table chunk: %u - %u", start, end);
181 /* find chunk and disown */
182 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
183 if (tmc->start != start)
184 continue;
185 if (tmc->end != end)
186 continue;
187 if (tmc->proto != proto || tmc->instance != instance) {
188 flog_err(EC_ZEBRA_TM_DAEMON_MISMATCH,
189 "%s: Daemon mismatch!!", __func__);
190 continue;
191 }
192 tmc->proto = NO_PROTO;
193 tmc->instance = 0;
194 ret = 0;
195 break;
196 }
197 if (ret != 0)
198 flog_err(EC_ZEBRA_TM_UNRELEASED_CHUNK,
199 "%s: Table chunk not released!!", __func__);
200
201 return ret;
202 }
203
204 /**
205 * Release table chunks from a client.
206 *
207 * Called on client disconnection or reconnection. It only releases chunks
208 * with empty keep value.
209 *
210 * @param client the client to release chunks from
211 * @return Number of chunks released
212 */
213 int release_daemon_table_chunks(struct zserv *client)
214 {
215 uint8_t proto = client->proto;
216 uint16_t instance = client->instance;
217 struct listnode *node;
218 struct table_manager_chunk *tmc;
219 int count = 0;
220 int ret;
221
222 for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
223 if (tmc->proto == proto && tmc->instance == instance) {
224 ret = release_table_chunk(tmc->proto, tmc->instance,
225 tmc->start, tmc->end);
226 if (ret == 0)
227 count++;
228 }
229 }
230
231 zlog_debug("%s: Released %d table chunks", __func__, count);
232
233 return count;
234 }
235
236 void table_manager_disable(ns_id_t ns_id)
237 {
238 if (ns_id != NS_DEFAULT)
239 return;
240 list_delete(&tbl_mgr.lc_list);
241 }