]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: Add Segment Routing Local Block support
authorOlivier Dugeon <olivier.dugeon@orange.com>
Wed, 20 May 2020 09:18:31 +0000 (11:18 +0200)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Tue, 23 Jun 2020 14:36:56 +0000 (16:36 +0200)
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>
13 files changed:
doc/user/isisd.rst
isisd/isis_cli.c
isisd/isis_lsp.c
isisd/isis_nb.c
isisd/isis_nb.h
isisd/isis_nb_config.c
isisd/isis_sr.c
isisd/isis_sr.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_zebra.c
isisd/isis_zebra.h
yang/frr-isisd.yang

index dc598ea5bf9721674ec8ab401e6e34a616c5dcfc..200d00821f47da4c86df5e94b7bb7156b8d15c1a 100644 (file)
@@ -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)
index c421750a825a54bb25cd2e0ef7d6eda249b82893..df69b1c7bee3d630b9d2911c55b60b52aaa92773 100644 (file)
@@ -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);
@@ -1436,6 +1436,50 @@ void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode,
                yang_dnode_get_string(dnode, "./upper-bound"));
 }
 
+/*
+ * 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
  */
@@ -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);
index e578f616f4a0180d3e6245d05e6d4a76ecddc88d..9b04eef6a2fc17c36780ecc4da8bcc3d59a3033d 100644 (file)
@@ -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;
                }
 
index f1f183cc5953025cfa98058197ff0a609ea0f95b..1d842eb13bebc716dd7150577b58152cc899072c 100644 (file)
@@ -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,
                        },
                },
@@ -480,6 +481,26 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_segment_routing_srgb_upper_bound_modify,
                        },
                },
+               {
+                       .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 = {
index 36dbc2d619e3e6a0d7b948b0709495be2aeb2d48..e887b1a3881a5d2b0c22540b4bd02d3de0814a34 100644 (file)
@@ -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,
index 9633e46415fe0997196c0610e7197da1efc0fc3d..fafa22b4927c0a57aa652a0447b8f48a203823d1 100644 (file)
@@ -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)
 {
@@ -1521,6 +1553,104 @@ int isis_instance_segment_routing_srgb_upper_bound_modify(
        return NB_OK;
 }
 
+/*
+ * 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
  */
index c24c0608b23d9800eefa5c2b1a89121ead1ba77a..32de71cca61cd74650895e0bbf51caad0d17e0be 100644 (file)
@@ -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);
 
@@ -177,6 +182,54 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
        return 0;
 }
 
+/**
+ * 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.
  *
@@ -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);
@@ -886,6 +937,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.
  *
@@ -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);
index dec329ab48bf5c512d096ba1fdcaeb57790b9303..45728f1eb15424f83a2468342a8098aa2e0fdd57 100644 (file)
@@ -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);
index 923956fa6d7cefa4c2a916ed091da40f2687fd60..a58038b327ba1ceb0314f53dae88e019f294535d 100644 (file)
@@ -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;
 }
 
index f468d85bbde1dcfe871687c03eb8b381dede7779..0cf49b526f07a96aeae562a44793737b1bca40c2 100644 (file)
@@ -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,
index e0bf0cee14b65e751f18ae84894ea3cc37f25a19..fa108c3637b57864797407fd65378a2a32f6f293 100644 (file)
 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. */
@@ -511,160 +507,6 @@ void isis_zebra_release_label_range(uint32_t start, uint32_t end)
                zlog_warn("%s: error releasing label range!", __func__);
 }
 
-/**
- * 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.
  */
@@ -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);
        }
 }
index b143d34626bd9d7643260837d27c173869e831b6..e853ce34d9c801b8423d75de7f05bd6b06a7473f 100644 (file)
@@ -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 */
index 445a59bc8a3b6f89e1566c81653d844094447892..befdc3467dcb5309873db886113aa76ac1fd4bc7 100644 (file)
@@ -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.";