diff options
author | Olivier Dugeon <olivier.dugeon@orange.com> | 2020-05-20 11:18:31 +0200 |
---|---|---|
committer | Olivier Dugeon <olivier.dugeon@orange.com> | 2020-06-23 16:36:56 +0200 |
commit | d8391312733858591cd13f36f6ba6e5411f34a69 (patch) | |
tree | be6dcc9a136f7a9ee05bf19bc464289b5dd6a07f | |
parent | Merge pull request #6390 from opensourcerouting/bfd-cp-fix (diff) | |
download | frr-d8391312733858591cd13f36f6ba6e5411f34a69.tar.xz frr-d8391312733858591cd13f36f6ba6e5411f34a69.zip |
isisd: Add Segment Routing Local Block support
Segment Routing Local Block (SRLB) is part of RFC8667. This change introduces
the possibility for isisd to advertize SRLB in LSP. Base and Range of SRLB
could be configured through CLI or Yang.
Adjacency-SID are now using this SRLB for label allocation. SRLB could also
be used for SID-Binding (e.g. LDP to SR).
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
-rw-r--r-- | doc/user/isisd.rst | 10 | ||||
-rw-r--r-- | isisd/isis_cli.c | 56 | ||||
-rw-r--r-- | isisd/isis_lsp.c | 9 | ||||
-rw-r--r-- | isisd/isis_nb.c | 21 | ||||
-rw-r--r-- | isisd/isis_nb.h | 12 | ||||
-rw-r--r-- | isisd/isis_nb_config.c | 130 | ||||
-rw-r--r-- | isisd/isis_sr.c | 313 | ||||
-rw-r--r-- | isisd/isis_sr.h | 21 | ||||
-rw-r--r-- | isisd/isis_tlvs.c | 110 | ||||
-rw-r--r-- | isisd/isis_tlvs.h | 12 | ||||
-rw-r--r-- | isisd/isis_zebra.c | 168 | ||||
-rw-r--r-- | isisd/isis_zebra.h | 2 | ||||
-rw-r--r-- | yang/frr-isisd.yang | 17 |
13 files changed, 653 insertions, 228 deletions
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index dc598ea5b..200d00821 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -493,7 +493,15 @@ Known limitations: .. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575) Set the Segment Routing Global Block i.e. the label range used by MPLS - to store label in the MPLS FIB. + to store label in the MPLS FIB for Prefix SID. Note that the block size + may not exceed 65535. + +.. index:: [no] segment-routing local-block (0-1048575) (0-1048575) +.. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575) + + Set the Segment Routing Local Block i.e. the label range used by MPLS + to store label in the MPLS FIB for Adjacency SID. Note that the block size + may not exceed 65535. .. index:: [no] segment-routing node-msd (1-16) .. clicmd:: [no] segment-routing node-msd (1-16) diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index c421750a8..df69b1c7b 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1400,8 +1400,8 @@ DEFPY (isis_sr_global_block_label_range, "segment-routing global-block (16-1048575)$lower_bound (16-1048575)$upper_bound", SR_STR "Segment Routing Global Block label range\n" - "The lower bound of SRGB (16-1048575)\n" - "The upper bound of SRGB (16-1048575)\n") + "The lower bound of the block\n" + "The upper bound of the block (block size may not exceed 65535)\n") { nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound", NB_OP_MODIFY, lower_bound_str); @@ -1413,12 +1413,12 @@ DEFPY (isis_sr_global_block_label_range, DEFPY (no_isis_sr_global_block_label_range, no_isis_sr_global_block_label_range_cmd, - "no segment-routing global-block [(0-1048575) (0-1048575)]", + "no segment-routing global-block [(16-1048575) (16-1048575)]", NO_STR SR_STR "Segment Routing Global Block label range\n" - "The lower bound of SRGB (16-1048575)\n" - "The upper bound of SRGB (block size may not exceed 65535)\n") + "The lower bound of the block\n" + "The upper bound of the block (block size may not exceed 65535)\n") { nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound", NB_OP_MODIFY, NULL); @@ -1437,6 +1437,50 @@ void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode, } /* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb + */ +DEFPY (isis_sr_local_block_label_range, + isis_sr_local_block_label_range_cmd, + "segment-routing local-block (16-1048575)$lower_bound (16-1048575)$upper_bound", + SR_STR + "Segment Routing Local Block label range\n" + "The lower bound of the block\n" + "The upper bound of the block (block size may not exceed 65535)\n") +{ + nb_cli_enqueue_change(vty, "./segment-routing/srlb/lower-bound", + NB_OP_MODIFY, lower_bound_str); + nb_cli_enqueue_change(vty, "./segment-routing/srlb/upper-bound", + NB_OP_MODIFY, upper_bound_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (no_isis_sr_local_block_label_range, + no_isis_sr_local_block_label_range_cmd, + "no segment-routing local-block [(16-1048575) (16-1048575)]", + NO_STR + SR_STR + "Segment Routing Local Block label range\n" + "The lower bound of the block\n" + "The upper bound of the block (block size may not exceed 65535)\n") +{ + nb_cli_enqueue_change(vty, "./segment-routing/srlb/lower-bound", + NB_OP_MODIFY, NULL); + nb_cli_enqueue_change(vty, "./segment-routing/srlb/upper-bound", + NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_srlb(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " segment-routing local-block %s %s\n", + yang_dnode_get_string(dnode, "./lower-bound"), + yang_dnode_get_string(dnode, "./upper-bound")); +} + +/* * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd */ DEFPY (isis_sr_node_msd, @@ -2308,6 +2352,8 @@ void isis_cli_init(void) install_element(ISIS_NODE, &no_isis_sr_enable_cmd); install_element(ISIS_NODE, &isis_sr_global_block_label_range_cmd); install_element(ISIS_NODE, &no_isis_sr_global_block_label_range_cmd); + install_element(ISIS_NODE, &isis_sr_local_block_label_range_cmd); + install_element(ISIS_NODE, &no_isis_sr_local_block_label_range_cmd); install_element(ISIS_NODE, &isis_sr_node_msd_cmd); install_element(ISIS_NODE, &no_isis_sr_node_msd_cmd); install_element(ISIS_NODE, &isis_sr_prefix_sid_cmd); diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index e578f616f..9b04eef6a 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -933,14 +933,23 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) struct isis_sr_db *srdb = &area->srdb; uint32_t range_size; + /* SRGB first */ range_size = srdb->config.srgb_upper_bound - srdb->config.srgb_lower_bound + 1; cap.srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I | ISIS_SUBTLV_SRGB_FLAG_V; cap.srgb.range_size = range_size; cap.srgb.lower_bound = srdb->config.srgb_lower_bound; + /* Then Algorithm */ cap.algo[0] = SR_ALGORITHM_SPF; cap.algo[1] = SR_ALGORITHM_UNSET; + /* SRLB */ + cap.srlb.flags = 0; + range_size = srdb->config.srlb_upper_bound + - srdb->config.srlb_lower_bound + 1; + cap.srlb.range_size = range_size; + cap.srlb.lower_bound = srdb->config.srlb_lower_bound; + /* And finally MSD */ cap.msd = srdb->config.msd; } diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index f1f183cc5..1d842eb13 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -465,6 +465,7 @@ const struct frr_yang_module_info frr_isisd_info = { .xpath = "/frr-isisd:isis/instance/segment-routing/srgb", .cbs = { .apply_finish = isis_instance_segment_routing_srgb_apply_finish, + .pre_validate = isis_instance_segment_routing_srgb_pre_validate, .cli_show = cli_show_isis_srgb, }, }, @@ -481,6 +482,26 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-isisd:isis/instance/segment-routing/srlb", + .cbs = { + .apply_finish = isis_instance_segment_routing_srlb_apply_finish, + .pre_validate = isis_instance_segment_routing_srlb_pre_validate, + .cli_show = cli_show_isis_srlb, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing/srlb/lower-bound", + .cbs = { + .modify = isis_instance_segment_routing_srlb_lower_bound_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing/srlb/upper-bound", + .cbs = { + .modify = isis_instance_segment_routing_srlb_upper_bound_modify, + }, + }, + { .xpath = "/frr-isisd:isis/instance/segment-routing/msd/node-msd", .cbs = { .modify = isis_instance_segment_routing_msd_node_msd_modify, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 36dbc2d61..e887b1a38 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -180,6 +180,10 @@ int isis_instance_segment_routing_srgb_lower_bound_modify( struct nb_cb_modify_args *args); int isis_instance_segment_routing_srgb_upper_bound_modify( struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srlb_lower_bound_modify( + struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srlb_upper_bound_modify( + struct nb_cb_modify_args *args); int isis_instance_segment_routing_msd_node_msd_modify( struct nb_cb_modify_args *args); int isis_instance_segment_routing_msd_node_msd_destroy( @@ -289,6 +293,10 @@ lib_interface_state_isis_event_counters_authentication_fails_get_elem( /* Optional 'pre_validate' callbacks. */ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate( struct nb_cb_pre_validate_args *args); +int isis_instance_segment_routing_srgb_pre_validate( + struct nb_cb_pre_validate_args *args); +int isis_instance_segment_routing_srlb_pre_validate( + struct nb_cb_pre_validate_args *args); /* Optional 'apply_finish' callbacks. */ void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args); @@ -304,6 +312,8 @@ void redistribute_ipv4_apply_finish(struct nb_cb_apply_finish_args *args); void redistribute_ipv6_apply_finish(struct nb_cb_apply_finish_args *args); void isis_instance_segment_routing_srgb_apply_finish( struct nb_cb_apply_finish_args *args); +void isis_instance_segment_routing_srlb_apply_finish( + struct nb_cb_apply_finish_args *args); void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish( struct nb_cb_apply_finish_args *args); @@ -370,6 +380,8 @@ void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void cli_show_isis_srlb(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 9633e4641..fafa22b49 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -1449,6 +1449,38 @@ int isis_instance_segment_routing_enabled_modify( /* * XPath: /frr-isisd:isis/instance/segment-routing/srgb */ +int isis_instance_segment_routing_srgb_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + uint32_t srgb_lbound; + uint32_t srgb_ubound; + uint32_t srlb_lbound; + uint32_t srlb_ubound; + + srgb_lbound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); + srgb_ubound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + srlb_lbound = yang_dnode_get_uint32(args->dnode, "../srlb/lower-bound"); + srlb_ubound = yang_dnode_get_uint32(args->dnode, "../srlb/upper-bound"); + + /* Check that the block size does not exceed 65535 */ + if ((srgb_ubound - srgb_lbound + 1) > 65535) { + zlog_warn( + "New SR Global Block (%u/%u) exceed the limit of 65535", + srgb_lbound, srgb_ubound); + return NB_ERR_VALIDATION; + } + + /* Validate SRGB against SRLB */ + if (!((srgb_ubound < srlb_lbound) || (srgb_lbound > srlb_ubound))) { + zlog_warn( + "New SR Global Block (%u/%u) conflict with Local Block (%u/%u)", + srgb_lbound, srgb_ubound, srlb_lbound, srlb_ubound); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + void isis_instance_segment_routing_srgb_apply_finish( struct nb_cb_apply_finish_args *args) { @@ -1522,6 +1554,104 @@ int isis_instance_segment_routing_srgb_upper_bound_modify( } /* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb + */ +int isis_instance_segment_routing_srlb_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + uint32_t srgb_lbound; + uint32_t srgb_ubound; + uint32_t srlb_lbound; + uint32_t srlb_ubound; + + srgb_lbound = yang_dnode_get_uint32(args->dnode, "../srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32(args->dnode, "../srgb/upper-bound"); + srlb_lbound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); + srlb_ubound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + + /* Check that the block size does not exceed 65535 */ + if ((srlb_ubound - srlb_lbound + 1) > 65535) { + zlog_warn( + "New SR Local Block (%u/%u) exceed the limit of 65535", + srlb_lbound, srlb_ubound); + return NB_ERR_VALIDATION; + } + + /* Validate SRLB against SRGB */ + if (!((srlb_ubound < srgb_lbound) || (srlb_lbound > srgb_ubound))) { + zlog_warn( + "New SR Local Block (%u/%u) conflict with Global Block (%u/%u)", + srlb_lbound, srlb_ubound, srgb_lbound, srgb_ubound); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +void isis_instance_segment_routing_srlb_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct isis_area *area; + uint32_t lower_bound, upper_bound; + + area = nb_running_get_entry(args->dnode, NULL, true); + lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); + upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + + isis_sr_cfg_srlb_update(area, lower_bound, upper_bound); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb/lower-bound + */ +int isis_instance_segment_routing_srlb_lower_bound_modify( + struct nb_cb_modify_args *args) +{ + uint32_t lower_bound = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!IS_MPLS_UNRESERVED_LABEL(lower_bound)) { + zlog_warn("Invalid SRLB lower bound: %" PRIu32, + lower_bound); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb/upper-bound + */ +int isis_instance_segment_routing_srlb_upper_bound_modify( + struct nb_cb_modify_args *args) +{ + uint32_t upper_bound = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!IS_MPLS_UNRESERVED_LABEL(upper_bound)) { + zlog_warn("Invalid SRLB upper bound: %" PRIu32, + upper_bound); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd */ int isis_instance_segment_routing_msd_node_msd_modify( diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index c24c0608b..32de71cca 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -52,6 +52,10 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information") static void sr_prefix_uninstall(struct sr_prefix *srp); static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break); +static void sr_local_block_delete(struct isis_area *area); +static int sr_local_block_init(struct isis_area *area); +static void sr_adj_sid_update(struct sr_adjacency *sra, + struct sr_local_block *srlb); /* --- RB-Tree Management functions ----------------------------------------- */ @@ -135,7 +139,8 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound, { struct isis_sr_db *srdb = &area->srdb; - sr_debug("ISIS-Sr (%s): Update SRGB", area->area_tag); + sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]", + area->area_tag, lower_bound, upper_bound); /* First release the old SRGB. */ if (srdb->config.enabled) @@ -148,14 +153,14 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound, if (srdb->enabled) { struct sr_prefix *srp; - /* Request new SRGB if SR is enabled. */ + /* then request new SRGB if SR is enabled. */ if (isis_zebra_request_label_range( srdb->config.srgb_lower_bound, srdb->config.srgb_upper_bound - srdb->config.srgb_lower_bound + 1)) return -1; - sr_debug(" |- Got new SRGB %u/%u", + sr_debug(" |- Got new SRGB [%u/%u]", srdb->config.srgb_lower_bound, srdb->config.srgb_upper_bound); @@ -178,6 +183,54 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound, } /** + * Update Segment Routing Local Block range which is reserved though the + * Label Manager. This function trigger the update of local Adjacency-SID + * installation. + * + * @param area IS-IS area + * @param lower_bound Lower bound of SRLB + * @param upper_bound Upper bound of SRLB + * + * @return 0 on success, -1 otherwise + */ +int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound, + uint32_t upper_bound) +{ + struct isis_sr_db *srdb = &area->srdb; + struct listnode *node, *nnode; + struct sr_adjacency *sra; + int rc; + + sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]", + area->area_tag, lower_bound, upper_bound); + + /* First Delete SRLB */ + sr_local_block_delete(area); + + srdb->config.srlb_lower_bound = lower_bound; + srdb->config.srlb_upper_bound = upper_bound; + + if (!srdb->enabled) + return 0; + + /* Initialize new SRLB */ + rc = sr_local_block_init(area); + if (rc !=0) + return rc; + + /* Reinstall local Adjacency-SIDs with new labels. */ + for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra)) + sr_adj_sid_update(sra, &srdb->srlb); + + /* Update Router Capability */ + + /* Update and Flood LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return 0; +} + +/** * Add new Prefix-SID configuration to the SRDB. * * @param area IS-IS area @@ -404,15 +457,13 @@ static struct sr_prefix *sr_prefix_find_by_node(struct sr_node *srn, * @return New Segment Routing Node structure */ static struct sr_node *sr_node_add(struct isis_area *area, int level, - const uint8_t *sysid, - const struct isis_router_cap *cap) + const uint8_t *sysid) { struct sr_node *srn; srn = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srn)); srn->level = level; memcpy(srn->sysid, sysid, ISIS_SYS_ID_LEN); - srn->cap = *cap; srn->area = area; srdb_node_prefix_init(&srn->prefix_sids); srdb_node_add(&area->srdb.sr_nodes[level - 1], srn); @@ -887,6 +938,26 @@ static inline void sr_prefix_reinstall(struct sr_prefix *srp, /* --- IS-IS LSP Parse functions -------------------------------------------- */ /** + * Compare Router Capabilities. Only Flags, SRGB and Algorithm are used for the + * comparison. MSD and SRLB modification must not trigger and SR-Prefix update. + * + * @param r1 First Router Capabilities to compare + * @param r2 Second Router Capabilities to compare + * @return 0 if r1 and r2 are equal or -1 otherwise + */ +static int router_cap_cmp(const struct isis_router_cap *r1, + const struct isis_router_cap *r2) +{ + if (r1->flags == r2->flags + && r1->srgb.lower_bound == r2->srgb.lower_bound + && r1->srgb.range_size == r2->srgb.range_size + && r1->algo[0] == r2->algo[0]) + return 0; + else + return -1; +} + +/** * Parse all SR-related information from the given Router Capabilities TLV. * * @param area IS-IS area @@ -909,8 +980,7 @@ parse_router_cap_tlv(struct isis_area *area, int level, const uint8_t *sysid, srn = sr_node_find(area, level, sysid); if (srn) { - if (memcmp(&srn->cap, router_cap, sizeof(srn->cap)) != 0) { - srn->cap = *router_cap; + if (router_cap_cmp(&srn->cap, router_cap) != 0) { srn->state = SRDB_STATE_MODIFIED; } else srn->state = SRDB_STATE_UNCHANGED; @@ -919,10 +989,16 @@ parse_router_cap_tlv(struct isis_area *area, int level, const uint8_t *sysid, : "Unchanged", sysid_print(srn->sysid)); } else { - srn = sr_node_add(area, level, sysid, router_cap); + srn = sr_node_add(area, level, sysid); srn->state = SRDB_STATE_NEW; } + /* + * Update Router Capabilities in any case as SRLB or MSD + * modification are not take into account for comparison. + */ + srn->cap = *router_cap; + return srn; } @@ -1242,6 +1318,150 @@ static int sr_route_update(struct isis_area *area, struct prefix *prefix, return 0; } +/* --- Segment Routing Local Block management functions --------------------- */ + +/** + * Initialize Segment Routing Local Block from SRDB configuration and reserve + * block of bits to manage label allocation. + * + * @param area IS-IS area + */ +static void sr_local_block_init(struct isis_area *area) +{ + struct isis_sr_db *srdb = &area->srdb; + struct sr_local_block *srlb = &srdb->srlb; + + /* + * Request SRLB to the label manager. If the allocation fails, return + * an error to disable SR until a new SRLB is successfully allocated. + */ + if (isis_zebra_request_label_range( + srdb->config.srlb_lower_bound, + srdb->config.srlb_upper_bound + - srdb->config.srlb_lower_bound + 1)) + return; + + sr_debug("ISIS-Sr (%s): Got new SRLB [%u/%u]", area->area_tag, + srdb->config.srlb_lower_bound, srdb->config.srlb_upper_bound); + + /* Initialize the SRLB */ + srlb->start = srdb->config.srlb_lower_bound; + srlb->end = srdb->config.srlb_upper_bound; + srlb->current = 0; + /* Compute the needed Used Mark number and allocate them */ + srlb->max_block = (srlb->end - srlb->start + 1) / SRLB_BLOCK_SIZE; + if (((srlb->end - srlb->start + 1) % SRLB_BLOCK_SIZE) != 0) + srlb->max_block++; + srlb->used_mark = XCALLOC(MTYPE_ISIS_SR_INFO, + srlb->max_block * SRLB_BLOCK_SIZE); +} + +/** + * Remove Segment Routing Local Block. + * + * @param area IS-IS area + */ +static void sr_local_block_delete(struct isis_area *area) +{ + struct isis_sr_db *srdb = &area->srdb; + struct sr_local_block *srlb = &srdb->srlb; + + sr_debug("ISIS-Sr (%s): Remove SRLB [%u/%u]", area->area_tag, + srlb->start, srlb->end); + + /* First release the label block */ + isis_zebra_release_label_range(srdb->config.srlb_lower_bound, + srdb->config.srlb_upper_bound); + + /* Then reset SRLB structure */ + if (srlb->used_mark != NULL) + XFREE(MTYPE_ISIS_SR_INFO, srlb->used_mark); + memset(srlb, 0, sizeof(struct sr_local_block)); +} + +/** + * Request a label from the Segment Routing Local Block. + * + * @param srlb Segment Routing Local Block + * + * @return First available label on success or MPLS_INVALID_LABEL if the + * block of labels is full + */ +static mpls_label_t sr_local_block_request_label(struct sr_local_block *srlb) +{ + + mpls_label_t label; + uint32_t index; + uint32_t pos; + + /* Check if we ran out of available labels */ + if (srlb->current >= srlb->end) + return MPLS_INVALID_LABEL; + + /* Get first available label and mark it used */ + label = srlb->current + srlb->start; + index = srlb->current / SRLB_BLOCK_SIZE; + pos = 1ULL << (srlb->current % SRLB_BLOCK_SIZE); + srlb->used_mark[index] |= pos; + + /* Jump to the next free position */ + srlb->current++; + pos = srlb->current % SRLB_BLOCK_SIZE; + while (srlb->current < srlb->end) { + if (pos == 0) + index++; + if (!((1ULL << pos) & srlb->used_mark[index])) + break; + else { + srlb->current++; + pos = srlb->current % SRLB_BLOCK_SIZE; + } + } + + return label; +} + +/** + * Release label in the Segment Routing Local Block. + * + * @param srlb Segment Routing Local Block + * @param label Label to be release + * + * @return 0 on success or -1 if label falls outside SRLB + */ +static int sr_local_block_release_label(struct sr_local_block *srlb, + mpls_label_t label) +{ + uint32_t index; + uint32_t pos; + + /* Check that label falls inside the SRLB */ + if ((label < srlb->start) || (label > srlb->end)) { + flog_warn(EC_ISIS_SID_OVERFLOW, + "%s: Returning label %u is outside SRLB [%u/%u]", + __func__, label, srlb->start, srlb->end); + return -1; + } + + index = (label - srlb->start) / SRLB_BLOCK_SIZE; + pos = 1ULL << ((label - srlb->start) % SRLB_BLOCK_SIZE); + srlb->used_mark[index] &= ~pos; + /* Reset current to the first available position */ + for (index = 0; index < srlb->max_block; index++) { + if (srlb->used_mark[index] != 0xFFFFFFFFFFFFFFFF) { + for (pos = 0; pos < SRLB_BLOCK_SIZE; pos++) + if (!((1ULL << pos) & srlb->used_mark[index])) { + srlb->current = + index * SRLB_BLOCK_SIZE + pos; + break; + } + break; + } + } + + return 0; +} + /* --- Segment Routing Adjacency-SID management functions ------------------- */ /** @@ -1293,7 +1513,11 @@ static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, if (backup) SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_BFLG); - input_label = isis_zebra_request_dynamic_label(); + /* Get a label from the SRLB for this Adjacency */ + input_label = sr_local_block_request_label(&area->srdb.srlb); + if (input_label == MPLS_INVALID_LABEL) + return; + if (circuit->ext == NULL) circuit->ext = isis_alloc_ext_subtlvs(); @@ -1351,6 +1575,36 @@ static void sr_adj_sid_add(struct isis_adjacency *adj, int family) sr_adj_sid_add_single(adj, family, true); } +static void sr_adj_sid_update(struct sr_adjacency *sra, + struct sr_local_block *srlb) +{ + struct isis_circuit *circuit = sra->adj->circuit; + + /* First remove the old MPLS Label */ + isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra); + + /* Got new label in the new SRLB */ + sra->nexthop.label = sr_local_block_request_label(srlb); + if (sra->nexthop.label == MPLS_INVALID_LABEL) + return; + + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + sra->u.ladj_sid->sid = sra->nexthop.label; + break; + case CIRCUIT_T_P2P: + sra->u.adj_sid->sid = sra->nexthop.label; + break; + default: + flog_warn(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u", + __func__, circuit->circ_type); + break; + } + + /* Finally configure the new MPLS Label */ + isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra); +} + /** * Delete local Adj-SID. * @@ -1368,11 +1622,13 @@ static void sr_adj_sid_del(struct sr_adjacency *sra) /* Release dynamic label and remove subTLVs */ switch (circuit->circ_type) { case CIRCUIT_T_BROADCAST: - isis_zebra_release_dynamic_label(sra->u.ladj_sid->sid); + sr_local_block_release_label(&area->srdb.srlb, + sra->u.ladj_sid->sid); isis_tlvs_del_lan_adj_sid(circuit->ext, sra->u.ladj_sid); break; case CIRCUIT_T_P2P: - isis_zebra_release_dynamic_label(sra->u.adj_sid->sid); + sr_local_block_release_label(&area->srdb.srlb, + sra->u.adj_sid->sid); isis_tlvs_del_adj_sid(circuit->ext, sra->u.adj_sid); break; default: @@ -1730,7 +1986,7 @@ static void show_node(struct vty *vty, struct isis_area *area, int level) /* Prepare table. */ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); - ttable_add_row(tt, "System ID|SRGB|Algorithm|MSD"); + ttable_add_row(tt, "System ID|SRGB|SRLB|Algorithm|MSD"); tt->style.cell.rpad = 2; tt->style.corner = '+'; ttable_restyle(tt); @@ -1738,13 +1994,17 @@ static void show_node(struct vty *vty, struct isis_area *area, int level) /* Process all SR-Node from the SRDB */ frr_each (srdb_node, &area->srdb.sr_nodes[level - 1], srn) { - ttable_add_row(tt, "%s|%u - %u|%s|%u", sysid_print(srn->sysid), - srn->cap.srgb.lower_bound, - srn->cap.srgb.lower_bound - + srn->cap.srgb.range_size - 1, - srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF" - : "S-SPF", - srn->cap.msd); + ttable_add_row( + tt, "%s|%u - %u|%u - %u|%s|%u", + sysid_print(srn->sysid), + srn->cap.srgb.lower_bound, + srn->cap.srgb.lower_bound + srn->cap.srgb.range_size + - 1, + srn->cap.srlb.lower_bound, + srn->cap.srlb.lower_bound + srn->cap.srlb.range_size + - 1, + srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF", + srn->cap.msd); } /* Dump the generated table. */ @@ -1794,6 +2054,10 @@ int isis_sr_start(struct isis_area *area) struct isis_circuit *circuit; struct listnode *node; + /* Initialize the SRLB */ + if (sr_local_block_init(area) != 0) + return -1; + /* * Request SGRB to the label manager. If the allocation fails, return * an error to disable SR until a new SRGB is successfully allocated. @@ -1876,6 +2140,9 @@ void isis_sr_stop(struct isis_area *area) isis_zebra_release_label_range(srdb->config.srgb_lower_bound, srdb->config.srgb_upper_bound); + /* Delete SRLB */ + sr_local_block_delete(area); + /* Regenerate LSPs to advertise that the Node is no more SR enable. */ lsp_regenerate_schedule(area, area->is_type, 0); } @@ -1909,10 +2176,16 @@ void isis_sr_area_init(struct isis_area *area) yang_get_default_uint32("%s/srgb/lower-bound", ISIS_SR); srdb->config.srgb_upper_bound = yang_get_default_uint32("%s/srgb/upper-bound", ISIS_SR); + srdb->config.srlb_lower_bound = + yang_get_default_uint32("%s/srlb/lower-bound", ISIS_SR); + srdb->config.srlb_upper_bound = + yang_get_default_uint32("%s/srlb/upper-bound", ISIS_SR); #else srdb->config.enabled = false; srdb->config.srgb_lower_bound = SRGB_LOWER_BOUND; srdb->config.srgb_upper_bound = SRGB_UPPER_BOUND; + srdb->config.srlb_lower_bound = SRLB_LOWER_BOUND; + srdb->config.srlb_upper_bound = SRLB_UPPER_BOUND; #endif srdb->config.msd = 0; srdb_prefix_cfg_init(&srdb->config.prefix_sids); diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h index dec329ab4..45728f1eb 100644 --- a/isisd/isis_sr.h +++ b/isisd/isis_sr.h @@ -53,6 +53,8 @@ #define SRGB_LOWER_BOUND 16000 #define SRGB_UPPER_BOUND 23999 +#define SRLB_LOWER_BOUND 15000 +#define SRLB_UPPER_BOUND 15999 /* Segment Routing Data Base (SRDB) RB-Tree structure */ PREDECL_RBTREE_UNIQ(srdb_node) @@ -60,6 +62,16 @@ PREDECL_RBTREE_UNIQ(srdb_node_prefix) PREDECL_RBTREE_UNIQ(srdb_area_prefix) PREDECL_RBTREE_UNIQ(srdb_prefix_cfg) +/* Segment Routing Local Block allocation */ +struct sr_local_block { + uint32_t start; + uint32_t end; + uint32_t current; + uint32_t max_block; + uint64_t *used_mark; +}; +#define SRLB_BLOCK_SIZE 64 + /* Segment Routing Adjacency-SID type. */ enum sr_adj_type { ISIS_SR_ADJ_NORMAL = 0, @@ -220,6 +232,9 @@ struct isis_sr_db { /* Segment Routing Prefix-SIDs per IS-IS level. */ struct srdb_area_prefix_head prefix_sids[ISIS_LEVELS]; + /* Management of SRLB allocation */ + struct sr_local_block srlb; + /* Area Segment Routing configuration. */ struct { /* Administrative status of Segment Routing. */ @@ -229,6 +244,10 @@ struct isis_sr_db { uint32_t srgb_lower_bound; uint32_t srgb_upper_bound; + /* Segment Routing Local Block lower & upper bound. */ + uint32_t srlb_lower_bound; + uint32_t srlb_upper_bound; + /* Maximum SID Depth supported by the node. */ uint8_t msd; @@ -240,6 +259,8 @@ struct isis_sr_db { /* Prototypes. */ extern int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound, uint32_t upper_bound); +extern int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound, + uint32_t upper_bound); extern struct sr_prefix_cfg * isis_sr_cfg_prefix_add(struct isis_area *area, const struct prefix *prefix); extern void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 923956fa6..a58038b32 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -2620,30 +2620,35 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap, /* Segment Routing Global Block as per RFC8667 section #3.1 */ if (router_cap->srgb.range_size != 0) - sbuf_push(buf, indent, - " Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n", + sbuf_push( + buf, indent, + " Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n", IS_SR_IPV4(router_cap->srgb) ? "1" : "0", IS_SR_IPV6(router_cap->srgb) ? "1" : "0", router_cap->srgb.lower_bound, router_cap->srgb.range_size); + /* Segment Routing Local Block as per RFC8667 section #3.3 */ + if (router_cap->srlb.range_size != 0) + sbuf_push(buf, indent, " SR Local Block Base: %u Range: %u\n", + router_cap->srlb.lower_bound, + router_cap->srlb.range_size); + /* Segment Routing Algorithms as per RFC8667 section #3.2 */ if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { - sbuf_push(buf, indent, " Algorithm: %s", - router_cap->algo[0] == 0 ? "0: SPF" - : "0: Strict SPF"); - for (int i = 1; i < SR_ALGORITHM_COUNT; i++) + sbuf_push(buf, indent, " SR Algorithm:\n"); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) if (router_cap->algo[i] != SR_ALGORITHM_UNSET) - sbuf_push(buf, indent, " %s", - router_cap->algo[1] == 0 - ? "0: SPF" - : "0: Strict SPF"); - sbuf_push(buf, indent, "\n"); + sbuf_push(buf, indent, " %u: %s\n", i, + router_cap->algo[i] == 0 + ? "SPF" + : "Strict SPF"); } /* Segment Routing Node MSD as per RFC8491 section #2 */ if (router_cap->msd != 0) - sbuf_push(buf, indent, " Node MSD: %d\n", router_cap->msd); + sbuf_push(buf, indent, " Node Maximum SID Depth: %u\n", + router_cap->msd); } static void free_tlv_router_cap(struct isis_router_cap *router_cap) @@ -2699,6 +2704,20 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap, for (int i = 0; i < nb_algo; i++) stream_putc(s, router_cap->algo[i]); } + + /* Local Block if defined as per RFC8667 section #3.3 */ + if ((router_cap->srlb.range_size != 0) + && (router_cap->srlb.lower_bound != 0)) { + stream_putc(s, ISIS_SUBTLV_SRLB); + stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE); + /* No Flags are defined for SRLB */ + stream_putc(s, 0); + stream_put3(s, router_cap->srlb.range_size); + stream_putc(s, ISIS_SUBTLV_SID_LABEL); + stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE); + stream_put3(s, router_cap->srlb.lower_bound); + } + /* And finish with MSD if set as per RFC8491 section #2 */ if (router_cap->msd != 0) { stream_putc(s, ISIS_SUBTLV_NODE_MSD); @@ -2721,6 +2740,7 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, void *dest, int indent) { struct isis_tlvs *tlvs = dest; + struct isis_router_cap *rcap; uint8_t type; uint8_t length; uint8_t subtlv_len; @@ -2741,47 +2761,51 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, } /* Allocate router cap structure and initialize SR Algorithms */ - tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap)); + rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap)); for (int i = 0; i < SR_ALGORITHM_COUNT; i++) - tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET; + rcap->algo[i] = SR_ALGORITHM_UNSET; /* Get Router ID and Flags */ - tlvs->router_cap->router_id.s_addr = stream_get_ipv4(s); - tlvs->router_cap->flags = stream_getc(s); + rcap->router_id.s_addr = stream_get_ipv4(s); + rcap->flags = stream_getc(s); /* Parse remaining part of the TLV if present */ subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE; while (subtlv_len > 2) { - struct isis_router_cap *rc = tlvs->router_cap; uint8_t msd_type; type = stream_getc(s); length = stream_getc(s); switch (type) { case ISIS_SUBTLV_SID_LABEL_RANGE: - rc->srgb.flags = stream_getc(s); - rc->srgb.range_size = stream_get3(s); + /* Only one SRGB is supported. Skip subsequent one */ + if (rcap->srgb.range_size != 0) { + stream_forward_getp(s, length); + continue; + } + rcap->srgb.flags = stream_getc(s); + rcap->srgb.range_size = stream_get3(s); /* Skip Type and get Length of SID Label */ stream_getc(s); sid_len = stream_getc(s); if (sid_len == ISIS_SUBTLV_SID_LABEL_SIZE) - rc->srgb.lower_bound = stream_get3(s); + rcap->srgb.lower_bound = stream_get3(s); else - rc->srgb.lower_bound = stream_getl(s); + rcap->srgb.lower_bound = stream_getl(s); /* SRGB sanity checks. */ - if (rc->srgb.range_size == 0 - || (rc->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX) - || ((rc->srgb.lower_bound + rc->srgb.range_size - 1) + if (rcap->srgb.range_size == 0 + || (rcap->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX) + || ((rcap->srgb.lower_bound + rcap->srgb.range_size - 1) > MPLS_LABEL_UNRESERVED_MAX)) { sbuf_push(log, indent, "Invalid label range. Reset SRGB\n"); - rc->srgb.lower_bound = 0; - rc->srgb.range_size = 0; + rcap->srgb.lower_bound = 0; + rcap->srgb.range_size = 0; } break; case ISIS_SUBTLV_ALGORITHM: /* Only 2 algorithms are supported: SPF & Strict SPF */ - stream_get(&rc->algo, s, + stream_get(&rcap->algo, s, length > SR_ALGORITHM_COUNT ? SR_ALGORITHM_COUNT : length); @@ -2789,12 +2813,39 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, stream_forward_getp( s, length - SR_ALGORITHM_COUNT); break; + case ISIS_SUBTLV_SRLB: + /* RFC 8667 section #3.3: Only one SRLB is authorized */ + if (rcap->srlb.range_size != 0) { + stream_forward_getp(s, length); + continue; + } + /* Ignore Flags which are not defined */ + stream_getc(s); + rcap->srlb.range_size = stream_get3(s); + /* Skip Type and get Length of SID Label */ + stream_getc(s); + sid_len = stream_getc(s); + if (sid_len == ISIS_SUBTLV_SID_LABEL_SIZE) + rcap->srlb.lower_bound = stream_get3(s); + else + rcap->srlb.lower_bound = stream_getl(s); + + /* SRLB sanity checks. */ + if (rcap->srlb.range_size == 0 + || (rcap->srlb.lower_bound <= MPLS_LABEL_RESERVED_MAX) + || ((rcap->srlb.lower_bound + rcap->srlb.range_size - 1) + > MPLS_LABEL_UNRESERVED_MAX)) { + sbuf_push(log, indent, "Invalid label range. Reset SRLB\n"); + rcap->srlb.lower_bound = 0; + rcap->srlb.range_size = 0; + } + break; case ISIS_SUBTLV_NODE_MSD: msd_type = stream_getc(s); - rc->msd = stream_getc(s); + rcap->msd = stream_getc(s); /* Only BMI-MSD type has been defined in RFC 8491 */ if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION) - rc->msd = 0; + rcap->msd = 0; break; default: stream_forward_getp(s, length); @@ -2802,6 +2853,7 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, } subtlv_len = subtlv_len - length - 2; } + tlvs->router_cap = rcap; return 0; } diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index f468d85bb..0cf49b526 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -141,8 +141,8 @@ struct isis_threeway_adj { #define IS_SR_IPV4(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I) #define IS_SR_IPV6(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V) -/* Structure aggregating SRGB info */ -struct isis_srgb { +/* Structure aggregating SR Global (SRGB) or Local (SRLB) Block info */ +struct isis_sr_block { uint8_t flags; uint32_t range_size; uint32_t lower_bound; @@ -214,7 +214,8 @@ struct isis_router_cap { uint8_t flags; /* RFC 8667 section #3 */ - struct isis_srgb srgb; + struct isis_sr_block srgb; + struct isis_sr_block srlb; uint8_t algo[SR_ALGORITHM_COUNT]; /* RFC 8491 */ #define MSD_TYPE_BASE_MPLS_IMPOSITION 0x01 @@ -398,10 +399,11 @@ enum isis_tlv_type { ISIS_SUBTLV_RAS = 24, ISIS_SUBTLV_RIP = 25, - /* RFC 8667 section #2 */ + /* RFC 8667 section #4 IANA allocation */ ISIS_SUBTLV_SID_LABEL = 1, ISIS_SUBTLV_SID_LABEL_RANGE = 2, ISIS_SUBTLV_ALGORITHM = 19, + ISIS_SUBTLV_SRLB = 22, ISIS_SUBTLV_PREFIX_SID = 3, ISIS_SUBTLV_ADJ_SID = 31, ISIS_SUBTLV_LAN_ADJ_SID = 32, @@ -431,7 +433,7 @@ enum ext_subtlv_size { /* RFC 8491 */ ISIS_SUBTLV_NODE_MSD_SIZE = 2, - /* RFC 8667 section #2 */ + /* RFC 8667 sections #2 & #3 */ ISIS_SUBTLV_SID_LABEL_SIZE = 3, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9, ISIS_SUBTLV_ALGORITHM_SIZE = 4, diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index e0bf0cee1..fa108c363 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -56,10 +56,6 @@ struct zclient *zclient; static struct zclient *zclient_sync; -/* List of chunks of labels externally assigned by zebra. */ -static struct list *label_chunk_list; -static struct listnode *current_label_chunk; - static void isis_zebra_label_manager_connect(void); /* Router-id update message from zebra. */ @@ -512,160 +508,6 @@ void isis_zebra_release_label_range(uint32_t start, uint32_t end) } /** - * Get a new Label Chunk from the Label Manager. The new Label Chunk is - * added to the Label Chunk list. - * - * @return 0 on success, -1 on failure - */ -static int isis_zebra_get_label_chunk(void) -{ - int ret; - uint32_t start, end; - struct label_chunk *new_label_chunk; - - if (zclient_sync->sock == -1) - isis_zebra_label_manager_connect(); - - ret = lm_get_label_chunk(zclient_sync, 0, MPLS_LABEL_BASE_ANY, - CHUNK_SIZE, &start, &end); - if (ret < 0) { - zlog_warn("%s: error getting label chunk!", __func__); - return -1; - } - - new_label_chunk = calloc(1, sizeof(struct label_chunk)); - if (!new_label_chunk) { - zlog_warn("%s: error trying to allocate label chunk %u - %u", - __func__, start, end); - return -1; - } - - new_label_chunk->start = start; - new_label_chunk->end = end; - new_label_chunk->used_mask = 0; - - listnode_add(label_chunk_list, (void *)new_label_chunk); - - /* let's update current if needed */ - if (!current_label_chunk) - current_label_chunk = listtail(label_chunk_list); - - return 0; -} - -/** - * Request a label from the Label Chunk list. - * - * @return valid label on success or MPLS_INVALID_LABEL on failure - */ -mpls_label_t isis_zebra_request_dynamic_label(void) -{ - struct label_chunk *label_chunk; - uint32_t i, size; - uint64_t pos; - uint32_t label = MPLS_INVALID_LABEL; - - while (current_label_chunk) { - label_chunk = listgetdata(current_label_chunk); - if (!label_chunk) - goto end; - - /* try to get next free label in currently used label chunk */ - size = label_chunk->end - label_chunk->start + 1; - for (i = 0, pos = 1; i < size; i++, pos <<= 1) { - if (!(pos & label_chunk->used_mask)) { - label_chunk->used_mask |= pos; - label = label_chunk->start + i; - goto end; - } - } - current_label_chunk = listnextnode(current_label_chunk); - } - -end: - /* - * we moved till the last chunk, or were not able to find a label, so - * let's ask for another one. - */ - if (!current_label_chunk - || current_label_chunk == listtail(label_chunk_list) - || label == MPLS_INVALID_LABEL) { - if (isis_zebra_get_label_chunk() != 0) - zlog_warn("%s: error getting label chunk!", __func__); - } - - return label; -} - -/** - * Delete a Label Chunk. - * - * @param val Pointer to the Label Chunk to free - */ -static void isis_zebra_del_label_chunk(void *val) -{ - free(val); -} - -/** - * Release a pre-allocated Label chunk to the Label Manager. - * - * @param start start of the label chunk to release - * @param end end of the label chunk to release - * - * @return 0 on success, -1 on failure - */ -static int isis_zebra_release_label_chunk(uint32_t start, uint32_t end) -{ - int ret; - - ret = lm_release_label_chunk(zclient_sync, start, end); - if (ret < 0) { - zlog_warn("%s: error releasing label chunk!", __func__); - return -1; - } - - return 0; -} - -/** - * Release a pre-attributes label to the Label Chunk list. - * - * @param label Label to be release - */ -void isis_zebra_release_dynamic_label(mpls_label_t label) -{ - struct listnode *node; - struct label_chunk *label_chunk; - uint64_t pos; - - for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) { - if (!(label <= label_chunk->end && label >= label_chunk->start)) - continue; - - pos = 1ULL << (label - label_chunk->start); - label_chunk->used_mask &= ~pos; - - /* - * If nobody is using this chunk and it's not - * current_label_chunk, then free it. - */ - if (!label_chunk->used_mask && (current_label_chunk != node)) { - if (isis_zebra_release_label_chunk(label_chunk->start, - label_chunk->end) - != 0) - zlog_warn("%s: error releasing label chunk!", - __func__); - else { - listnode_delete(label_chunk_list, label_chunk); - isis_zebra_del_label_chunk(label_chunk); - } - } - break; - } -} - -/** * Connect to the Label Manager. */ static void isis_zebra_label_manager_connect(void) @@ -689,14 +531,8 @@ static void isis_zebra_label_manager_connect(void) /* Connect to label manager */ while (lm_label_manager_connect(zclient_sync, 0) != 0) { - zlog_warn("%s: re-attempt connecting to label manager!", __func__); - sleep(1); - } - - label_chunk_list = list_new(); - label_chunk_list->del = isis_zebra_del_label_chunk; - while (isis_zebra_get_label_chunk() != 0) { - zlog_warn("%s: re-attempt getting first label chunk!", __func__); + zlog_warn("%s: re-attempt connecting to label manager!", + __func__); sleep(1); } } diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index b143d3462..e853ce34d 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -51,7 +51,5 @@ void isis_zebra_redistribute_set(afi_t afi, int type); void isis_zebra_redistribute_unset(afi_t afi, int type); int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size); void isis_zebra_release_label_range(uint32_t start, uint32_t end); -mpls_label_t isis_zebra_request_dynamic_label(void); -void isis_zebra_release_dynamic_label(mpls_label_t label); #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 445a59bc8..befdc3467 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1213,6 +1213,23 @@ module frr-isisd { "Upper value in the label range."; } } + container srlb { + description + "Local blocks to be advertised."; + must "./upper-bound > ./lower-bound"; + leaf lower-bound { + type uint32; + default "15000"; + description + "Lower value in the label range."; + } + leaf upper-bound { + type uint32; + default "15999"; + description + "Upper value in the label range."; + } + } container msd { description "MSD configuration."; |