diff options
Diffstat (limited to 'zebra/table_manager.c')
| -rw-r--r-- | zebra/table_manager.c | 190 |
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; } |
