.. 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)
"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);
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);
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
*/
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);
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;
}
.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,
},
},
.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 = {
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(
/* 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);
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);
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,
/*
* 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)
{
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
*/
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 ----------------------------------------- */
{
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)
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);
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.
*
* @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);
/* --- 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.
*
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;
: "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;
}
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 ------------------- */
/**
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();
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.
*
/* 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:
/* 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);
/* 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. */
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.
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);
}
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);
#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)
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,
/* 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. */
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;
/* 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);
/* 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)
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);
void *dest, int indent)
{
struct isis_tlvs *tlvs = dest;
+ struct isis_router_cap *rcap;
uint8_t type;
uint8_t length;
uint8_t subtlv_len;
}
/* 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);
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);
}
subtlv_len = subtlv_len - length - 2;
}
+ tlvs->router_cap = rcap;
return 0;
}
#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;
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
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,
/* 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,
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. */
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.
*/
/* 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);
}
}
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 */
"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.";