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
21 #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_vrf.h"
35 #include "label_manager.h" /* for NO_PROTO */
36 #include "table_manager.h"
38 /* routing table identifiers
45 #if !defined(GNU_LINUX) && !defined(SUNOS_5)
51 #define RT_TABLE_ID_LOCAL 255
52 #define RT_TABLE_ID_MAIN 254
53 #define RT_TABLE_ID_DEFAULT 253
54 #define RT_TABLE_ID_COMPAT 252
55 #define RT_TABLE_ID_UNSPEC 0
56 #endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
58 #define RT_TABLE_ID_UNRESERVED_MIN 1
59 #define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
61 struct table_manager tbl_mgr
;
63 DEFINE_MGROUP(TABLE_MGR
, "Table Manager");
64 DEFINE_MTYPE_STATIC(TABLE_MGR
, TM_CHUNK
, "Table Manager Chunk");
66 static void delete_table_chunk(void *val
)
68 XFREE(MTYPE_TM_CHUNK
, val
);
74 void table_manager_enable(ns_id_t ns_id
)
76 if (ns_id
!= NS_DEFAULT
)
78 tbl_mgr
.lc_list
= list_new();
79 tbl_mgr
.lc_list
->del
= delete_table_chunk
;
83 * Core function, assigns table chunks
85 * It first searches through the list to check if there's one available
86 * (previously released). Otherwise it creates and assigns a new one
88 * @param proto Daemon protocol of client, to identify the owner
89 * @param instance Instance, to identify the owner
90 * @para size Size of the table chunk
91 * @return Pointer to the assigned table chunk
93 struct table_manager_chunk
*assign_table_chunk(uint8_t proto
, uint16_t instance
,
96 struct table_manager_chunk
*tmc
;
97 struct listnode
*node
;
100 /* first check if there's one available */
101 for (ALL_LIST_ELEMENTS_RO(tbl_mgr
.lc_list
, node
, tmc
)) {
102 if (tmc
->proto
== NO_PROTO
103 && tmc
->end
- tmc
->start
+ 1 == size
) {
105 tmc
->instance
= instance
;
109 /* otherwise create a new one */
110 tmc
= XCALLOC(MTYPE_TM_CHUNK
, sizeof(struct table_manager_chunk
));
114 /* table RT IDs range are [1;252] and [256;0xffffffff]
115 * - check if the requested range can be within the first range,
116 * otherwise elect second one
117 * - TODO : vrf-lites have their own table identifier.
118 * In that case, table_id should be removed from the table range.
120 if (list_isempty(tbl_mgr
.lc_list
))
121 start
= RT_TABLE_ID_UNRESERVED_MIN
;
123 start
= ((struct table_manager_chunk
*)listgetdata(
124 listtail(tbl_mgr
.lc_list
)))->end
+ 1;
130 #if !defined(GNU_LINUX) && !defined(SUNOS_5)
136 /* if not enough room space between MIN and COMPAT,
137 * then begin after LOCAL
139 if (start
< RT_TABLE_ID_COMPAT
&& (size
>
141 - RT_TABLE_ID_UNRESERVED_MIN
))
142 start
= RT_TABLE_ID_LOCAL
+ 1;
143 #endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
146 if (RT_TABLE_ID_UNRESERVED_MAX
- size
+ 1 < start
) {
147 zlog_err("Reached max table id. Start/Size %u/%u",
149 XFREE(MTYPE_TM_CHUNK
, tmc
);
152 tmc
->end
= tmc
->start
+ size
- 1;
154 tmc
->instance
= instance
;
155 listnode_add(tbl_mgr
.lc_list
, tmc
);
161 * Core function, release no longer used table chunks
163 * @param proto Daemon protocol of client, to identify the owner
164 * @param instance Instance, to identify the owner
165 * @param start First table RT ID of the chunk
166 * @param end Last table RT ID of the chunk
167 * @return 0 on success, -1 otherwise
169 int release_table_chunk(uint8_t proto
, uint16_t instance
, uint32_t start
,
172 struct listnode
*node
;
173 struct table_manager_chunk
*tmc
;
176 /* check that size matches */
177 zlog_debug("Releasing table chunk: %u - %u", start
, end
);
178 /* find chunk and disown */
179 for (ALL_LIST_ELEMENTS_RO(tbl_mgr
.lc_list
, node
, tmc
)) {
180 if (tmc
->start
!= start
)
184 if (tmc
->proto
!= proto
|| tmc
->instance
!= instance
) {
185 zlog_err("%s: Daemon mismatch!!", __func__
);
188 tmc
->proto
= NO_PROTO
;
194 zlog_err("%s: Table chunk not released!!", __func__
);
200 * Release table chunks from a client.
202 * Called on client disconnection or reconnection. It only releases chunks
203 * with empty keep value.
205 * @param proto Daemon protocol of client, to identify the owner
206 * @param instance Instance, to identify the owner
207 * @return Number of chunks released
209 int release_daemon_table_chunks(uint8_t proto
, uint16_t instance
)
211 struct listnode
*node
;
212 struct table_manager_chunk
*tmc
;
216 for (ALL_LIST_ELEMENTS_RO(tbl_mgr
.lc_list
, node
, tmc
)) {
217 if (tmc
->proto
== proto
&& tmc
->instance
== instance
) {
218 ret
= release_table_chunk(tmc
->proto
, tmc
->instance
,
219 tmc
->start
, tmc
->end
);
225 zlog_debug("%s: Released %d table chunks", __func__
, count
);
230 void table_manager_disable(ns_id_t ns_id
)
232 if (ns_id
!= NS_DEFAULT
)
234 list_delete_and_null(&tbl_mgr
.lc_list
);