summaryrefslogtreecommitdiff
path: root/zebra/label_manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/label_manager.c')
-rw-r--r--zebra/label_manager.c256
1 files changed, 213 insertions, 43 deletions
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index c77470a701..c97beb6af8 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -28,6 +28,8 @@
#include "zebra/zapi_msg.h"
#include "zebra/debug.h"
+#include "zebra/label_manager_clippy.c"
+
#define CONNECTION_DELAY 5
struct label_manager lbl_mgr;
@@ -49,10 +51,14 @@ DEFINE_HOOK(lm_get_chunk,
DEFINE_HOOK(lm_release_chunk,
(struct zserv *client, uint32_t start, uint32_t end),
(client, start, end));
+/* show running-config needs an API for dynamic-block */
+DEFINE_HOOK(lm_write_label_block_config,
+ (struct vty *vty, struct zebra_vrf *zvrf),
+ (vty, zvrf));
DEFINE_HOOK(lm_cbs_inited, (), ());
-/* define wrappers to be called in zapi_msg.c (as hooks must be called in
- * source file where they were defined)
+/* define wrappers to be called in zapi_msg.c or zebra_mpls_vty.c (as hooks
+ * must be called in source file where they were defined)
*/
void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id)
{
@@ -69,6 +75,11 @@ void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end)
hook_call(lm_release_chunk, client, start, end);
}
+int lm_write_label_block_config_call(struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return hook_call(lm_write_label_block_config, vty, zvrf);
+}
+
/* forward declarations of the static functions to be used for some hooks */
static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id);
static int label_manager_disconnect(struct zserv *client);
@@ -78,6 +89,8 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc,
vrf_id_t vrf_id);
static int label_manager_release_label_chunk(struct zserv *client,
uint32_t start, uint32_t end);
+static int label_manager_write_label_block_config(struct vty *vty,
+ struct zebra_vrf *zvrf);
void delete_label_chunk(void *val)
{
@@ -96,7 +109,7 @@ void delete_label_chunk(void *val)
*/
int release_daemon_label_chunks(struct zserv *client)
{
- struct listnode *node;
+ struct listnode *node, *nnode;
struct label_manager_chunk *lmc;
int count = 0;
int ret;
@@ -106,7 +119,7 @@ int release_daemon_label_chunks(struct zserv *client)
__func__, zebra_route_string(client->proto),
client->instance, client->session_id);
- for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+ for (ALL_LIST_ELEMENTS(lbl_mgr.lc_list, node, nnode, lmc)) {
if (lmc->proto == client->proto &&
lmc->instance == client->instance &&
lmc->session_id == client->session_id && lmc->keep == 0) {
@@ -136,6 +149,8 @@ void lm_hooks_register(void)
hook_register(lm_client_disconnect, label_manager_disconnect);
hook_register(lm_get_chunk, label_manager_get_chunk);
hook_register(lm_release_chunk, label_manager_release_label_chunk);
+ hook_register(lm_write_label_block_config,
+ label_manager_write_label_block_config);
}
void lm_hooks_unregister(void)
{
@@ -143,6 +158,127 @@ void lm_hooks_unregister(void)
hook_unregister(lm_client_disconnect, label_manager_disconnect);
hook_unregister(lm_get_chunk, label_manager_get_chunk);
hook_unregister(lm_release_chunk, label_manager_release_label_chunk);
+ hook_unregister(lm_write_label_block_config,
+ label_manager_write_label_block_config);
+}
+
+static json_object *lmc_json(struct label_manager_chunk *lmc)
+{
+ json_object *json = json_object_new_object();
+
+ json_object_string_add(json, "protocol", zebra_route_string(lmc->proto));
+ json_object_int_add(json, "instance", lmc->instance);
+ json_object_int_add(json, "sessionId", lmc->session_id);
+ json_object_int_add(json, "start", lmc->start);
+ json_object_int_add(json, "end", lmc->end);
+ json_object_boolean_add(json, "dynamic", lmc->is_dynamic);
+ return json;
+}
+
+DEFPY(show_label_table, show_label_table_cmd, "show debugging label-table [json$uj]",
+ SHOW_STR
+ DEBUG_STR
+ "Display allocated label chunks\n"
+ JSON_STR)
+{
+ struct label_manager_chunk *lmc;
+ struct listnode *node;
+ json_object *json_array = NULL, *json_global = NULL, *json_dyn_block;
+
+ if (uj) {
+ json_array = json_object_new_array();
+ json_global = json_object_new_object();
+ json_dyn_block = json_object_new_object();
+ json_object_int_add(json_dyn_block, "lowerBound",
+ lbl_mgr.dynamic_block_start);
+ json_object_int_add(json_dyn_block, "upperBound",
+ lbl_mgr.dynamic_block_end);
+ json_object_object_add(json_global, "dynamicBlock",
+ json_dyn_block);
+ } else
+ vty_out(vty, "Dynamic block: lower-bound %u, upper-bound %u\n",
+ lbl_mgr.dynamic_block_start, lbl_mgr.dynamic_block_end);
+
+ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+ if (uj) {
+ json_object_array_add(json_array, lmc_json(lmc));
+ continue;
+ }
+ vty_out(vty, "Proto %s: [%u/%u]\n",
+ zebra_route_string(lmc->proto), lmc->start, lmc->end);
+ }
+ if (uj) {
+ json_object_object_add(json_global, "chunks", json_array);
+ vty_json(vty, json_global);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFPY(mpls_label_dynamic_block, mpls_label_dynamic_block_cmd,
+ "[no$no] mpls label dynamic-block [(16-1048575)$start (16-1048575)$end]",
+ NO_STR
+ MPLS_STR
+ "Label configuration\n"
+ "Configure dynamic label block\n"
+ "Start label\n"
+ "End label\n")
+{
+ struct listnode *node;
+ struct label_manager_chunk *lmc;
+
+ /* unset dynamic range */
+ if (no ||
+ (start == MPLS_LABEL_UNRESERVED_MIN && end == MPLS_LABEL_MAX)) {
+ lbl_mgr.dynamic_block_start = MPLS_LABEL_UNRESERVED_MIN;
+ lbl_mgr.dynamic_block_end = MPLS_LABEL_MAX;
+ return CMD_SUCCESS;
+ }
+ if (!start || !end) {
+ vty_out(vty,
+ "%% label dynamic-block, range missing, aborting\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (start > end) {
+ vty_out(vty,
+ "%% label dynamic-block, wrong range (%ld > %ld), aborting\n",
+ start, end);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+ if (lmc->proto == NO_PROTO)
+ continue;
+ if (!lmc->is_dynamic && lmc->start >= (uint32_t)start &&
+ lmc->end <= (uint32_t)end) {
+ vty_out(vty,
+ "%% Found a static label chunk [%u-%u] for %s in conflict with the dynamic label block\n",
+ lmc->start, lmc->end,
+ zebra_route_string(lmc->proto));
+ return CMD_WARNING_CONFIG_FAILED;
+ } else if (lmc->is_dynamic && (lmc->end > (uint32_t)end ||
+ lmc->start < (uint32_t)start)) {
+ vty_out(vty,
+ "%% Found a dynamic label chunk [%u-%u] for %s outside the new dynamic label block, consider restart the service\n",
+ lmc->start, lmc->end,
+ zebra_route_string(lmc->proto));
+ }
+ }
+ lbl_mgr.dynamic_block_start = start;
+ lbl_mgr.dynamic_block_end = end;
+ return CMD_SUCCESS;
+}
+
+static int label_manager_write_label_block_config(struct vty *vty,
+ struct zebra_vrf *zvrf)
+{
+ if (zvrf_id(zvrf) != VRF_DEFAULT)
+ return 0;
+ if (lbl_mgr.dynamic_block_start == MPLS_LABEL_UNRESERVED_MIN &&
+ lbl_mgr.dynamic_block_end == MPLS_LABEL_MAX)
+ return 0;
+ vty_out(vty, "mpls label dynamic-block %u %u\n",
+ lbl_mgr.dynamic_block_start, lbl_mgr.dynamic_block_end);
+ return 1;
}
/**
@@ -152,6 +288,8 @@ void label_manager_init(void)
{
lbl_mgr.lc_list = list_new();
lbl_mgr.lc_list->del = delete_label_chunk;
+ lbl_mgr.dynamic_block_start = MPLS_LABEL_UNRESERVED_MIN;
+ lbl_mgr.dynamic_block_end = MPLS_LABEL_MAX;
hook_register(zserv_client_close, lm_client_disconnect_cb);
/* register default hooks for the label manager actions */
@@ -159,12 +297,20 @@ void label_manager_init(void)
/* notify any external module that we are done */
hook_call(lm_cbs_inited);
+
+ install_element(VIEW_NODE, &show_label_table_cmd);
+ install_element(CONFIG_NODE, &mpls_label_dynamic_block_cmd);
+}
+
+void label_manager_terminate(void)
+{
+ list_delete(&lbl_mgr.lc_list);
}
/* alloc and fill a label chunk */
struct label_manager_chunk *
create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
- uint8_t keep, uint32_t start, uint32_t end)
+ uint8_t keep, uint32_t start, uint32_t end, bool is_dynamic)
{
/* alloc chunk, fill it and return it */
struct label_manager_chunk *lmc =
@@ -176,6 +322,7 @@ create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
lmc->instance = instance;
lmc->session_id = session_id;
lmc->keep = keep;
+ lmc->is_dynamic = is_dynamic;
return lmc;
}
@@ -203,6 +350,15 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
return NULL;
}
+ if ((lbl_mgr.dynamic_block_start != MPLS_LABEL_UNRESERVED_MIN ||
+ lbl_mgr.dynamic_block_end != MPLS_LABEL_MAX) &&
+ base >= lbl_mgr.dynamic_block_start &&
+ end <= lbl_mgr.dynamic_block_end) {
+ zlog_warn("Invalid LM request arguments: base: %u, size: %u for %s in conflict with the dynamic label block",
+ base, size, zebra_route_string(proto));
+ return NULL;
+ }
+
/* Scan the existing chunks to see if the requested range of labels
* falls inside any of such chunks */
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
@@ -234,7 +390,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
/* insert chunk between existing chunks */
if (insert_node) {
lmc = create_label_chunk(proto, instance, session_id, keep,
- base, end);
+ base, end, false);
listnode_add_before(lbl_mgr.lc_list, insert_node, lmc);
return lmc;
}
@@ -257,7 +413,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
}
lmc = create_label_chunk(proto, instance, session_id, keep,
- base, end);
+ base, end, false);
if (last_node)
listnode_add_before(lbl_mgr.lc_list, last_node, lmc);
else
@@ -268,7 +424,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
/* create a new chunk past all the existing ones and link at
* tail */
lmc = create_label_chunk(proto, instance, session_id, keep,
- base, end);
+ base, end, false);
listnode_add(lbl_mgr.lc_list, lmc);
return lmc;
}
@@ -293,9 +449,13 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
{
struct label_manager_chunk *lmc;
struct listnode *node;
- uint32_t prev_end = MPLS_LABEL_UNRESERVED_MIN;
+ uint32_t prev_end = lbl_mgr.dynamic_block_start - 1;
+ struct label_manager_chunk *lmc_block_last = NULL;
- /* handle chunks request with a specific base label */
+ /* handle chunks request with a specific base label
+ * - static label requests: BGP hardset value, Pathd
+ * - segment routing label requests
+ */
if (base != MPLS_LABEL_BASE_ANY)
return assign_specific_label_chunk(proto, instance, session_id,
keep, size, base);
@@ -305,37 +465,44 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
/* first check if there's one available */
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
- if (lmc->proto == NO_PROTO
- && lmc->end - lmc->start + 1 == size) {
+ if (lmc->start <= prev_end)
+ continue;
+ if (lmc->proto == NO_PROTO &&
+ lmc->end - lmc->start + 1 == size &&
+ lmc->end <= lbl_mgr.dynamic_block_end) {
lmc->proto = proto;
lmc->instance = instance;
lmc->session_id = session_id;
lmc->keep = keep;
+ lmc->is_dynamic = true;
return lmc;
}
/* check if we hadve a "hole" behind us that we can squeeze into
*/
- if ((lmc->start > prev_end) && (lmc->start - prev_end > size)) {
+ if (lmc->start - prev_end > size &&
+ prev_end + 1 + size <= lbl_mgr.dynamic_block_end) {
lmc = create_label_chunk(proto, instance, session_id,
keep, prev_end + 1,
- prev_end + size);
+ prev_end + size, true);
listnode_add_before(lbl_mgr.lc_list, node, lmc);
return lmc;
}
prev_end = lmc->end;
+
+ /* check if we have a chunk that goes over the end block */
+ if (lmc->end > lbl_mgr.dynamic_block_end)
+ continue;
+ lmc_block_last = lmc;
}
/* otherwise create a new one */
uint32_t start_free;
- if (list_isempty(lbl_mgr.lc_list))
- start_free = MPLS_LABEL_UNRESERVED_MIN;
+ if (lmc_block_last == NULL)
+ start_free = lbl_mgr.dynamic_block_start;
else
- start_free = ((struct label_manager_chunk *)listgetdata(
- listtail(lbl_mgr.lc_list)))
- ->end
- + 1;
+ start_free = lmc_block_last->end + 1;
- if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
+ if (start_free > lbl_mgr.dynamic_block_end - size + 1) {
flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS,
"Reached max labels. Start: %u, size: %u", start_free,
size);
@@ -344,7 +511,7 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
/* create chunk and link at tail */
lmc = create_label_chunk(proto, instance, session_id, keep, start_free,
- start_free + size - 1);
+ start_free + size - 1, true);
listnode_add(lbl_mgr.lc_list, lmc);
return lmc;
}
@@ -399,13 +566,14 @@ int release_label_chunk(uint8_t proto, unsigned short instance,
"%s: Daemon mismatch!!", __func__);
continue;
}
- lmc->proto = NO_PROTO;
- lmc->instance = 0;
- lmc->session_id = 0;
- lmc->keep = 0;
ret = 0;
break;
}
+ if (lmc) {
+ list_delete_node(lbl_mgr.lc_list, node);
+ delete_label_chunk(lmc);
+ }
+
if (ret != 0)
flog_err(EC_ZEBRA_LM_UNRELEASED_CHUNK,
"%s: Label chunk not released!!", __func__);
@@ -435,7 +603,25 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc,
{
*lmc = assign_label_chunk(client->proto, client->instance,
client->session_id, keep, size, base);
- return lm_get_chunk_response(*lmc, client, vrf_id);
+ /* Respond to a get_chunk request */
+ if (!*lmc) {
+ if (base == MPLS_LABEL_BASE_ANY)
+ flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
+ "Unable to assign Label Chunk size %u to %s instance %u",
+ size, zebra_route_string(client->proto),
+ client->instance);
+ else
+ flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
+ "Unable to assign Label Chunk %u - %u to %s instance %u",
+ base, base + size - 1,
+ zebra_route_string(client->proto),
+ client->instance);
+ } else if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
+ (*lmc)->start, (*lmc)->end,
+ zebra_route_string(client->proto), client->instance);
+
+ return zsend_assign_label_chunk_response(client, vrf_id, *lmc);
}
/* Respond to a connect request */
@@ -454,22 +640,6 @@ int lm_client_connect_response(uint8_t proto, uint16_t instance,
return zsend_label_manager_connect_response(client, vrf_id, result);
}
-/* Respond to a get_chunk request */
-int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client,
- vrf_id_t vrf_id)
-{
- if (!lmc)
- flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
- "Unable to assign Label Chunk to %s instance %u",
- zebra_route_string(client->proto), client->instance);
- else if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
- lmc->start, lmc->end,
- zebra_route_string(client->proto), client->instance);
-
- return zsend_assign_label_chunk_response(client, vrf_id, lmc);
-}
-
void label_manager_close(void)
{
list_delete(&lbl_mgr.lc_list);