1 /* zebra table Manager for routing table identifier management
2 * Copyright (C) 2018 6WIND
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)
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
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
23 #include <sys/types.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"
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"
39 /* routing table identifiers
46 #if !defined(GNU_LINUX) && !defined(SUNOS_5)
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) */
59 #define RT_TABLE_ID_UNRESERVED_MIN 1
60 #define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
62 struct table_manager tbl_mgr
;
64 DEFINE_MGROUP(TABLE_MGR
, "Table Manager");
65 DEFINE_MTYPE_STATIC(TABLE_MGR
, TM_CHUNK
, "Table Manager Chunk");
67 static void delete_table_chunk(void *val
)
69 XFREE(MTYPE_TM_CHUNK
, val
);
75 void table_manager_enable(ns_id_t ns_id
)
77 if (ns_id
!= NS_DEFAULT
)
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
);
85 * Core function, assigns table chunks
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
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
95 struct table_manager_chunk
*assign_table_chunk(uint8_t proto
, uint16_t instance
,
98 struct table_manager_chunk
*tmc
;
99 struct listnode
*node
;
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
) {
107 tmc
->instance
= instance
;
111 /* otherwise create a new one */
112 tmc
= XCALLOC(MTYPE_TM_CHUNK
, sizeof(struct table_manager_chunk
));
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.
122 if (list_isempty(tbl_mgr
.lc_list
))
123 start
= RT_TABLE_ID_UNRESERVED_MIN
;
125 start
= ((struct table_manager_chunk
*)listgetdata(
126 listtail(tbl_mgr
.lc_list
)))->end
+ 1;
132 #if !defined(GNU_LINUX) && !defined(SUNOS_5)
138 /* if not enough room space between MIN and COMPAT,
139 * then begin after LOCAL
141 if (start
< RT_TABLE_ID_COMPAT
&& (size
>
143 - RT_TABLE_ID_UNRESERVED_MIN
))
144 start
= RT_TABLE_ID_LOCAL
+ 1;
145 #endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
148 if (RT_TABLE_ID_UNRESERVED_MAX
- size
+ 1 < start
) {
149 zlog_err("Reached max table id. Start/Size %u/%u",
151 XFREE(MTYPE_TM_CHUNK
, tmc
);
154 tmc
->end
= tmc
->start
+ size
- 1;
156 tmc
->instance
= instance
;
157 listnode_add(tbl_mgr
.lc_list
, tmc
);
163 * Core function, release no longer used table chunks
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
171 int release_table_chunk(uint8_t proto
, uint16_t instance
, uint32_t start
,
174 struct listnode
*node
;
175 struct table_manager_chunk
*tmc
;
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
)
186 if (tmc
->proto
!= proto
|| tmc
->instance
!= instance
) {
187 zlog_err("%s: Daemon mismatch!!", __func__
);
190 tmc
->proto
= NO_PROTO
;
196 zlog_err("%s: Table chunk not released!!", __func__
);
202 * Release table chunks from a client.
204 * Called on client disconnection or reconnection. It only releases chunks
205 * with empty keep value.
207 * @param client the client to release chunks from
208 * @return Number of chunks released
210 int release_daemon_table_chunks(struct zserv
*client
)
212 uint8_t proto
= client
->proto
;
213 uint16_t instance
= client
->instance
;
214 struct listnode
*node
;
215 struct table_manager_chunk
*tmc
;
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
);
228 zlog_debug("%s: Released %d table chunks", __func__
, count
);
233 void table_manager_disable(ns_id_t ns_id
)
235 if (ns_id
!= NS_DEFAULT
)
237 list_delete_and_null(&tbl_mgr
.lc_list
);