summaryrefslogtreecommitdiff
path: root/zebra/table_manager.c
diff options
context:
space:
mode:
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;
}