summaryrefslogtreecommitdiff
path: root/zebra/table_manager.c
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2021-07-23 16:56:28 +0200
committerPhilippe Guibert <philippe.guibert@6wind.com>2021-09-21 18:37:30 +0200
commit42d4b30e00131923691ef260ed8b1ff11bf3f33c (patch)
tree2dbd7d0025c49dfe2605f53ad4d89fcf0fe57212 /zebra/table_manager.c
parentf334c88ed9675eab624728ecd6eaaff3a9b41255 (diff)
zebra: extend table manager per vrf, add vty configuration
Because vrf backend may be based on namespaces, each vrf can use in the [16-(2^32-1)] range table identifier for daemons that request it. Extend the table manager to be hosted by vrf. That possibility is disabled in the case the vrf backend is vrflite. In that case, all vrf context use the same table manager instance. Add a configuration command to be able to configure the wished range of tables to use. This is a solution that permits to give chunks to bgp daemon when it works with bgp flowspec entries and wants to use specific iptables that do not override vrf tables. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
Diffstat (limited to 'zebra/table_manager.c')
-rw-r--r--zebra/table_manager.c190
1 files changed, 152 insertions, 38 deletions
diff --git a/zebra/table_manager.c b/zebra/table_manager.c
index bb060588d2..9f3b44f944 100644
--- a/zebra/table_manager.c
+++ b/zebra/table_manager.c
@@ -55,10 +55,9 @@
#define RT_TABLE_ID_UNRESERVED_MIN 1
#define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
-struct table_manager tbl_mgr;
-
DEFINE_MGROUP(TABLE_MGR, "Table Manager");
DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
+DEFINE_MTYPE_STATIC(TABLE_MGR, TM_TABLE, "Table Manager Context");
static void delete_table_chunk(void *val)
{
@@ -68,12 +67,21 @@ static void delete_table_chunk(void *val)
/**
* Init table manager
*/
-void table_manager_enable(ns_id_t ns_id)
+void table_manager_enable(struct zebra_vrf *zvrf)
{
- if (ns_id != NS_DEFAULT)
+
+ if (zvrf->tbl_mgr)
return;
- tbl_mgr.lc_list = list_new();
- tbl_mgr.lc_list->del = delete_table_chunk;
+ if (!vrf_is_backend_netns() && zvrf_id(zvrf) != VRF_DEFAULT) {
+ struct zebra_vrf *def = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+
+ if (def)
+ zvrf->tbl_mgr = def->tbl_mgr;
+ return;
+ }
+ zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager));
+ zvrf->tbl_mgr->lc_list = list_new();
+ zvrf->tbl_mgr->lc_list->del = delete_table_chunk;
hook_register(zserv_client_close, release_daemon_table_chunks);
}
@@ -89,14 +97,19 @@ void table_manager_enable(ns_id_t ns_id)
* @return Pointer to the assigned table chunk
*/
struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
- uint32_t size)
+ uint32_t size,
+ struct zebra_vrf *zvrf)
{
struct table_manager_chunk *tmc;
struct listnode *node;
uint32_t start;
+ bool manual_conf = false;
+
+ if (!zvrf)
+ return NULL;
/* first check if there's one available */
- for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+ for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
if (tmc->proto == NO_PROTO
&& tmc->end - tmc->start + 1 == size) {
tmc->proto = proto;
@@ -109,17 +122,26 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
if (!tmc)
return NULL;
+ if (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)
+ manual_conf = true;
/* table RT IDs range are [1;252] and [256;0xffffffff]
* - check if the requested range can be within the first range,
* otherwise elect second one
* - TODO : vrf-lites have their own table identifier.
* In that case, table_id should be removed from the table range.
*/
- if (list_isempty(tbl_mgr.lc_list))
- start = RT_TABLE_ID_UNRESERVED_MIN;
- else
+ if (list_isempty(zvrf->tbl_mgr->lc_list)) {
+ if (!manual_conf)
+ start = RT_TABLE_ID_UNRESERVED_MIN;
+ else
+ start = zvrf->tbl_mgr->start;
+ } else
start = ((struct table_manager_chunk *)listgetdata(
- listtail(tbl_mgr.lc_list)))->end + 1;
+ listtail(zvrf->tbl_mgr->lc_list)))
+ ->end
+ + 1;
+
+ if (!manual_conf) {
#if !defined(GNU_LINUX)
/* BSD systems
@@ -127,25 +149,35 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
#else
/* Linux Systems
*/
- /* if not enough room space between MIN and COMPAT,
- * then begin after LOCAL
- */
- if (start < RT_TABLE_ID_COMPAT && (size >
- RT_TABLE_ID_COMPAT
- - RT_TABLE_ID_UNRESERVED_MIN))
- start = RT_TABLE_ID_LOCAL + 1;
+ /* if not enough room space between MIN and COMPAT,
+ * then begin after LOCAL
+ */
+ if (start < RT_TABLE_ID_COMPAT
+ && (size > RT_TABLE_ID_COMPAT - RT_TABLE_ID_UNRESERVED_MIN))
+ start = RT_TABLE_ID_LOCAL + 1;
#endif /* !def(GNU_LINUX) */
- tmc->start = start;
- if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
- flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
- "Reached max table id. Start/Size %u/%u", start, size);
- XFREE(MTYPE_TM_CHUNK, tmc);
- return NULL;
+ tmc->start = start;
+ if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
+ flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
+ "Reached max table id. Start/Size %u/%u",
+ start, size);
+ XFREE(MTYPE_TM_CHUNK, tmc);
+ return NULL;
+ }
+ } else {
+ tmc->start = start;
+ if (zvrf->tbl_mgr->end - size + 1 < start) {
+ flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
+ "Reached max table id. Start/Size %u/%u",
+ start, size);
+ XFREE(MTYPE_TM_CHUNK, tmc);
+ return NULL;
+ }
}
tmc->end = tmc->start + size - 1;
tmc->proto = proto;
tmc->instance = instance;
- listnode_add(tbl_mgr.lc_list, tmc);
+ listnode_add(zvrf->tbl_mgr->lc_list, tmc);
return tmc;
}
@@ -160,16 +192,23 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
* @return 0 on success, -1 otherwise
*/
int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
- uint32_t end)
+ uint32_t end, struct zebra_vrf *zvrf)
{
struct listnode *node;
struct table_manager_chunk *tmc;
int ret = -1;
+ struct table_manager *tbl_mgr;
+
+ if (!zvrf)
+ return -1;
+ tbl_mgr = zvrf->tbl_mgr;
+ if (!tbl_mgr)
+ return ret;
/* check that size matches */
zlog_debug("Releasing table chunk: %u - %u", start, end);
/* find chunk and disown */
- for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+ for (ALL_LIST_ELEMENTS_RO(tbl_mgr->lc_list, node, tmc)) {
if (tmc->start != start)
continue;
if (tmc->end != end)
@@ -208,24 +247,99 @@ int release_daemon_table_chunks(struct zserv *client)
struct table_manager_chunk *tmc;
int count = 0;
int ret;
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
- for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
- if (tmc->proto == proto && tmc->instance == instance) {
- ret = release_table_chunk(tmc->proto, tmc->instance,
- tmc->start, tmc->end);
- if (ret == 0)
- count++;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ zvrf = vrf->info;
+
+ if (!zvrf)
+ continue;
+ if (!vrf_is_backend_netns() && vrf->vrf_id != VRF_DEFAULT)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
+ if (tmc->proto == proto && tmc->instance == instance) {
+ ret = release_table_chunk(
+ tmc->proto, tmc->instance, tmc->start,
+ tmc->end, zvrf);
+ if (ret == 0)
+ count++;
+ }
}
}
-
zlog_debug("%s: Released %d table chunks", __func__, count);
return count;
}
-void table_manager_disable(ns_id_t ns_id)
+static void table_range_add(struct zebra_vrf *zvrf, uint32_t start,
+ uint32_t end)
+{
+ if (!zvrf->tbl_mgr)
+ return;
+ zvrf->tbl_mgr->start = start;
+ zvrf->tbl_mgr->end = end;
+}
+
+void table_manager_disable(struct zebra_vrf *zvrf)
{
- if (ns_id != NS_DEFAULT)
+ if (!zvrf->tbl_mgr)
+ return;
+ if (!vrf_is_backend_netns() && zvrf_id(zvrf) != VRF_DEFAULT) {
+ zvrf->tbl_mgr = NULL;
return;
- list_delete(&tbl_mgr.lc_list);
+ }
+ list_delete(&zvrf->tbl_mgr->lc_list);
+ XFREE(MTYPE_TM_TABLE, zvrf->tbl_mgr);
+ zvrf->tbl_mgr = NULL;
+}
+
+int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf,
+ const char *start_table_str, const char *end_table_str)
+{
+ uint32_t start;
+ uint32_t end;
+
+ if (add) {
+ if (!start_table_str || !end_table_str) {
+ vty_out(vty, "%% Labels not specified\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ start = atoi(start_table_str);
+ end = atoi(end_table_str);
+ if (end < start) {
+ vty_out(vty, "%% End table is less than Start table\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+#if !defined(GNU_LINUX)
+/* BSD systems
+ */
+#else
+ /* Linux Systems
+ */
+ if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL)
+ || (end >= RT_TABLE_ID_COMPAT
+ && end <= RT_TABLE_ID_LOCAL)) {
+ vty_out(vty, "%% Values forbidden in range [%u;%u]\n",
+ RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) {
+ vty_out(vty,
+ "%% Range overlaps range [%u;%u] forbidden\n",
+ RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+#endif
+ if (zvrf->tbl_mgr
+ && ((zvrf->tbl_mgr->start && zvrf->tbl_mgr->start != start)
+ || (zvrf->tbl_mgr->end && zvrf->tbl_mgr->end != end))) {
+ vty_out(vty,
+ "%% New range will be taken into account at restart\n");
+ }
+ table_range_add(zvrf, start, end);
+ } else
+ table_range_add(zvrf, 0, 0);
+ return CMD_SUCCESS;
}