mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-10-17 08:05:49 +00:00
Merge pull request #6451 from Orange-OpenSource/dev_isis_sr
ISISd: Add Segment Routing local block (SRLB)
This commit is contained in:
commit
3f3391e5f4
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -1433,14 +1433,12 @@ int isis_instance_segment_routing_enabled_modify(
|
||||
if (IS_DEBUG_ISIS(DEBUG_EVENTS))
|
||||
zlog_debug("SR: Segment Routing: OFF -> ON");
|
||||
|
||||
if (isis_sr_start(area) == 0)
|
||||
area->srdb.enabled = true;
|
||||
isis_sr_start(area);
|
||||
} else {
|
||||
if (IS_DEBUG_ISIS(DEBUG_EVENTS))
|
||||
zlog_debug("SR: Segment Routing: ON -> OFF");
|
||||
|
||||
isis_sr_stop(area);
|
||||
area->srdb.enabled = false;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
@ -1449,26 +1447,49 @@ 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)
|
||||
{
|
||||
struct isis_area *area;
|
||||
uint32_t lower_bound, upper_bound;
|
||||
int ret;
|
||||
|
||||
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");
|
||||
|
||||
ret = isis_sr_cfg_srgb_update(area, lower_bound, upper_bound);
|
||||
if (area->srdb.config.enabled) {
|
||||
if (ret == 0)
|
||||
area->srdb.enabled = true;
|
||||
else {
|
||||
isis_sr_stop(area);
|
||||
area->srdb.enabled = false;
|
||||
}
|
||||
}
|
||||
isis_sr_cfg_srgb_update(area, lower_bound, upper_bound);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1521,6 +1542,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
|
||||
*/
|
||||
|
426
isisd/isis_sr.c
426
isisd/isis_sr.c
@ -52,6 +52,10 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
|
||||
|
||||
static void sr_prefix_uninstall(struct sr_prefix *srp);
|
||||
static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break);
|
||||
static void sr_local_block_delete(struct isis_area *area);
|
||||
static int sr_local_block_init(struct isis_area *area);
|
||||
static void sr_adj_sid_update(struct sr_adjacency *sra,
|
||||
struct sr_local_block *srlb);
|
||||
|
||||
/* --- RB-Tree Management functions ----------------------------------------- */
|
||||
|
||||
@ -135,12 +139,23 @@ 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)
|
||||
isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
|
||||
/* Just store new SRGB values if Label Manager is not available.
|
||||
* SRGB will be configured later when SR start */
|
||||
if (!isis_zebra_label_manager_ready()) {
|
||||
srdb->config.srgb_lower_bound = lower_bound;
|
||||
srdb->config.srgb_upper_bound = upper_bound;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Label Manager is ready, start by releasing the old SRGB. */
|
||||
if (srdb->srgb_active) {
|
||||
isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
|
||||
srdb->config.srgb_upper_bound);
|
||||
srdb->srgb_active = false;
|
||||
}
|
||||
|
||||
srdb->config.srgb_lower_bound = lower_bound;
|
||||
srdb->config.srgb_upper_bound = upper_bound;
|
||||
@ -148,14 +163,18 @@ 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))
|
||||
- srdb->config.srgb_lower_bound + 1) < 0) {
|
||||
srdb->srgb_active = false;
|
||||
return -1;
|
||||
} else
|
||||
srdb->srgb_active = true;
|
||||
|
||||
sr_debug(" |- Got new SRGB %u/%u",
|
||||
|
||||
sr_debug(" |- Got new SRGB [%u/%u]",
|
||||
srdb->config.srgb_lower_bound,
|
||||
srdb->config.srgb_upper_bound);
|
||||
|
||||
@ -170,8 +189,61 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
} else if (srdb->config.enabled) {
|
||||
/* Try to enable SR again using the new SRGB. */
|
||||
if (isis_sr_start(area) == 0)
|
||||
area->srdb.enabled = true;
|
||||
isis_sr_start(area);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
|
||||
area->area_tag, lower_bound, upper_bound);
|
||||
|
||||
/* Just store new SRLB values if Label Manager is not available.
|
||||
* SRLB will be configured later when SR start */
|
||||
if (!isis_zebra_label_manager_ready()) {
|
||||
srdb->config.srlb_lower_bound = lower_bound;
|
||||
srdb->config.srlb_upper_bound = upper_bound;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LM is ready, start by deleting the old SRLB */
|
||||
sr_local_block_delete(area);
|
||||
|
||||
srdb->config.srlb_lower_bound = lower_bound;
|
||||
srdb->config.srlb_upper_bound = upper_bound;
|
||||
|
||||
if (srdb->enabled) {
|
||||
/* Initialize new SRLB */
|
||||
if (sr_local_block_init(area) != 0)
|
||||
return -1;
|
||||
|
||||
/* 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 and Flood LSP */
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
} else if (srdb->config.enabled) {
|
||||
/* Try to enable SR again using the new SRLB. */
|
||||
isis_sr_start(area);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -404,15 +476,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 +956,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 +999,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 +1008,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 +1337,163 @@ 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 int sr_local_block_init(struct isis_area *area)
|
||||
{
|
||||
struct isis_sr_db *srdb = &area->srdb;
|
||||
struct sr_local_block *srlb = &srdb->srlb;
|
||||
|
||||
/* Check if SRLB is not already configured */
|
||||
if (srlb->active)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
srlb->active = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
srlb->active = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/* Check if SRLB is not already delete */
|
||||
if (!srlb->active)
|
||||
return;
|
||||
|
||||
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);
|
||||
srlb->active = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +1545,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 +1607,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 +1654,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 +2018,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 +2026,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. */
|
||||
@ -1781,6 +2073,26 @@ DEFUN(show_sr_node, show_sr_node_cmd,
|
||||
|
||||
/* --- IS-IS Segment Routing Management function ---------------------------- */
|
||||
|
||||
/**
|
||||
* Thread function to re-attempt connection to the Label Manager and thus be
|
||||
* able to start Segment Routing.
|
||||
*
|
||||
* @param start Thread structure that contains area as argument
|
||||
*
|
||||
* @return 1 on success
|
||||
*/
|
||||
static int sr_start_label_manager(struct thread *start)
|
||||
{
|
||||
struct isis_area *area;
|
||||
|
||||
area = THREAD_ARG(start);
|
||||
|
||||
/* re-attempt to start SR & Label Manager connection */
|
||||
isis_sr_start(area);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable SR on the given IS-IS area.
|
||||
*
|
||||
@ -1794,16 +2106,36 @@ int isis_sr_start(struct isis_area *area)
|
||||
struct isis_circuit *circuit;
|
||||
struct listnode *node;
|
||||
|
||||
/*
|
||||
* Request SGRB to the label manager. If the allocation fails, return
|
||||
* an error to disable SR until a new SRGB is successfully allocated.
|
||||
*/
|
||||
if (isis_zebra_request_label_range(
|
||||
srdb->config.srgb_lower_bound,
|
||||
srdb->config.srgb_upper_bound
|
||||
- srdb->config.srgb_lower_bound + 1))
|
||||
/* First start Label Manager if not ready */
|
||||
if (!isis_zebra_label_manager_ready())
|
||||
if (isis_zebra_label_manager_connect() < 0) {
|
||||
/* Re-attempt to connect to Label Manager in 1 sec. */
|
||||
thread_add_timer(master, sr_start_label_manager, area,
|
||||
1, &srdb->t_start_lm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Label Manager is ready, initialize the SRLB */
|
||||
if (sr_local_block_init(area) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Request SGRB to the label manager if not already active. If the
|
||||
* allocation fails, return an error to disable SR until a new SRGB
|
||||
* is successfully allocated.
|
||||
*/
|
||||
if (!srdb->srgb_active) {
|
||||
if (isis_zebra_request_label_range(
|
||||
srdb->config.srgb_lower_bound,
|
||||
srdb->config.srgb_upper_bound
|
||||
- srdb->config.srgb_lower_bound + 1)
|
||||
< 0) {
|
||||
srdb->srgb_active = false;
|
||||
return -1;
|
||||
} else
|
||||
srdb->srgb_active = true;
|
||||
}
|
||||
|
||||
sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
|
||||
area->area_tag);
|
||||
|
||||
@ -1838,6 +2170,8 @@ int isis_sr_start(struct isis_area *area)
|
||||
}
|
||||
}
|
||||
|
||||
area->srdb.enabled = true;
|
||||
|
||||
/* Regenerate LSPs to advertise Segment Routing capabilities. */
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
@ -1858,6 +2192,9 @@ void isis_sr_stop(struct isis_area *area)
|
||||
sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
|
||||
area->area_tag);
|
||||
|
||||
/* Disable any re-attempt to connect to Label Manager */
|
||||
THREAD_TIMER_OFF(srdb->t_start_lm);
|
||||
|
||||
/* Uninstall all local Adjacency-SIDs. */
|
||||
for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
|
||||
sr_adj_sid_del(sra);
|
||||
@ -1872,9 +2209,17 @@ void isis_sr_stop(struct isis_area *area)
|
||||
}
|
||||
}
|
||||
|
||||
/* Release SRGB. */
|
||||
isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
|
||||
srdb->config.srgb_upper_bound);
|
||||
/* Release SRGB if active. */
|
||||
if (srdb->srgb_active) {
|
||||
isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
|
||||
srdb->config.srgb_upper_bound);
|
||||
srdb->srgb_active = false;
|
||||
}
|
||||
|
||||
/* Delete SRLB */
|
||||
sr_local_block_delete(area);
|
||||
|
||||
area->srdb.enabled = false;
|
||||
|
||||
/* Regenerate LSPs to advertise that the Node is no more SR enable. */
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
@ -1894,7 +2239,6 @@ void isis_sr_area_init(struct isis_area *area)
|
||||
|
||||
/* Initialize Segment Routing Data Base */
|
||||
memset(srdb, 0, sizeof(*srdb));
|
||||
srdb->enabled = false;
|
||||
srdb->adj_sids = list_new();
|
||||
|
||||
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
|
||||
@ -1909,10 +2253,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);
|
||||
|
@ -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,17 @@ 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 {
|
||||
bool active;
|
||||
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,
|
||||
@ -211,6 +224,9 @@ struct isis_sr_db {
|
||||
/* Global Operational status of Segment Routing. */
|
||||
bool enabled;
|
||||
|
||||
/* Thread timer to start Label Manager */
|
||||
struct thread *t_start_lm;
|
||||
|
||||
/* List of local Adjacency-SIDs. */
|
||||
struct list *adj_sids;
|
||||
|
||||
@ -220,6 +236,10 @@ struct isis_sr_db {
|
||||
/* Segment Routing Prefix-SIDs per IS-IS level. */
|
||||
struct srdb_area_prefix_head prefix_sids[ISIS_LEVELS];
|
||||
|
||||
/* Management of SRLB & SRGB allocation */
|
||||
struct sr_local_block srlb;
|
||||
bool srgb_active;
|
||||
|
||||
/* Area Segment Routing configuration. */
|
||||
struct {
|
||||
/* Administrative status of Segment Routing. */
|
||||
@ -229,6 +249,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 +264,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);
|
||||
|
@ -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,10 +2740,11 @@ 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;
|
||||
uint8_t sid_len;
|
||||
uint8_t size;
|
||||
|
||||
sbuf_push(log, indent, "Unpacking Router Capability TLV...\n");
|
||||
if (tlv_len < ISIS_ROUTER_CAP_SIZE) {
|
||||
@ -2741,47 +2761,61 @@ 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);
|
||||
/* Check that SRGB is correctly formated */
|
||||
if (length < SUBTLV_RANGE_LABEL_SIZE
|
||||
|| length > SUBTLV_RANGE_INDEX_SIZE) {
|
||||
stream_forward_getp(s, length);
|
||||
continue;
|
||||
}
|
||||
/* 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);
|
||||
size = stream_getc(s);
|
||||
if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
|
||||
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;
|
||||
}
|
||||
/* Only one range is supported. Skip subsequent one */
|
||||
size = length - (size + SUBTLV_SR_BLOCK_SIZE);
|
||||
if (size > 0)
|
||||
stream_forward_getp(s, length);
|
||||
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 +2823,57 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
|
||||
stream_forward_getp(
|
||||
s, length - SR_ALGORITHM_COUNT);
|
||||
break;
|
||||
case ISIS_SUBTLV_SRLB:
|
||||
/* Check that SRLB is correctly formated */
|
||||
if (length < SUBTLV_RANGE_LABEL_SIZE
|
||||
|| length > SUBTLV_RANGE_INDEX_SIZE) {
|
||||
stream_forward_getp(s, length);
|
||||
continue;
|
||||
}
|
||||
/* 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);
|
||||
size = stream_getc(s);
|
||||
if (size == 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;
|
||||
}
|
||||
/* Only one range is supported. Skip subsequent one */
|
||||
size = length - (size + SUBTLV_SR_BLOCK_SIZE);
|
||||
if (size > 0)
|
||||
stream_forward_getp(s, length);
|
||||
break;
|
||||
case ISIS_SUBTLV_NODE_MSD:
|
||||
/* Check that MSD is correctly formated */
|
||||
if (length < MSD_TLV_SIZE) {
|
||||
stream_forward_getp(s, length);
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
/* Only one MSD is standardized. Skip others */
|
||||
if (length > MSD_TLV_SIZE)
|
||||
stream_forward_getp(s, length - MSD_TLV_SIZE);
|
||||
break;
|
||||
default:
|
||||
stream_forward_getp(s, length);
|
||||
@ -2802,6 +2881,7 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
|
||||
}
|
||||
subtlv_len = subtlv_len - length - 2;
|
||||
}
|
||||
tlvs->router_cap = rcap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -140,9 +140,12 @@ struct isis_threeway_adj {
|
||||
#define ISIS_SUBTLV_SRGB_FLAG_V 0x40
|
||||
#define IS_SR_IPV4(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I)
|
||||
#define IS_SR_IPV6(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V)
|
||||
#define SUBTLV_SR_BLOCK_SIZE 6
|
||||
#define SUBTLV_RANGE_INDEX_SIZE 10
|
||||
#define SUBTLV_RANGE_LABEL_SIZE 9
|
||||
|
||||
/* 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;
|
||||
@ -209,15 +212,18 @@ struct isis_lan_adj_sid {
|
||||
#define SR_ALGORITHM_STRICT_SPF 1
|
||||
#define SR_ALGORITHM_UNSET 255
|
||||
|
||||
#define MSD_TYPE_BASE_MPLS_IMPOSITION 0x01
|
||||
#define MSD_TLV_SIZE 2
|
||||
|
||||
struct isis_router_cap {
|
||||
struct in_addr router_id;
|
||||
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
|
||||
uint8_t msd;
|
||||
};
|
||||
|
||||
@ -398,10 +404,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 +438,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,
|
||||
|
@ -56,12 +56,6 @@
|
||||
struct zclient *zclient;
|
||||
static struct zclient *zclient_sync;
|
||||
|
||||
/* List of chunks of labels externally assigned by zebra. */
|
||||
static struct list *label_chunk_list;
|
||||
static struct listnode *current_label_chunk;
|
||||
|
||||
static void isis_zebra_label_manager_connect(void);
|
||||
|
||||
/* Router-id update message from zebra. */
|
||||
static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
@ -469,6 +463,16 @@ void isis_zebra_redistribute_unset(afi_t afi, int type)
|
||||
|
||||
/* Label Manager Functions */
|
||||
|
||||
/**
|
||||
* Check if Label Manager is Ready or not.
|
||||
*
|
||||
* @return True if Label Manager is ready, False otherwise
|
||||
*/
|
||||
bool isis_zebra_label_manager_ready(void)
|
||||
{
|
||||
return (zclient_sync->sock > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Label Range to the Label Manager.
|
||||
*
|
||||
@ -482,8 +486,8 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
|
||||
int ret;
|
||||
uint32_t start, end;
|
||||
|
||||
if (zclient_sync->sock == -1)
|
||||
isis_zebra_label_manager_connect();
|
||||
if (zclient_sync->sock < 0)
|
||||
return -1;
|
||||
|
||||
ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
|
||||
&end);
|
||||
@ -500,207 +504,63 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
|
||||
*
|
||||
* @param start start of label range to release
|
||||
* @param end end of label range to release
|
||||
*
|
||||
* @return 0 on success, -1 otherwise
|
||||
*/
|
||||
void isis_zebra_release_label_range(uint32_t start, uint32_t end)
|
||||
int isis_zebra_release_label_range(uint32_t start, uint32_t end)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (zclient_sync->sock == -1)
|
||||
isis_zebra_label_manager_connect();
|
||||
if (zclient_sync->sock < 0)
|
||||
return -1;
|
||||
|
||||
ret = lm_release_label_chunk(zclient_sync, start, end);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
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.
|
||||
*
|
||||
* @return 0 on success, -1 otherwise
|
||||
*/
|
||||
static void isis_zebra_label_manager_connect(void)
|
||||
int isis_zebra_label_manager_connect(void)
|
||||
{
|
||||
/* Connect to label manager. */
|
||||
while (zclient_socket_connect(zclient_sync) < 0) {
|
||||
zlog_warn("%s: re-attempt connecting synchronous zclient!",
|
||||
if (zclient_socket_connect(zclient_sync) < 0) {
|
||||
zlog_warn("%s: failed connecting synchronous zclient!",
|
||||
__func__);
|
||||
sleep(1);
|
||||
return -1;
|
||||
}
|
||||
/* make socket non-blocking */
|
||||
set_nonblocking(zclient_sync->sock);
|
||||
|
||||
/* Send hello to notify zebra this is a synchronous client */
|
||||
while (zclient_send_hello(zclient_sync) < 0) {
|
||||
zlog_warn(
|
||||
"%s: re-attempt sending hello for synchronous zclient!",
|
||||
__func__);
|
||||
sleep(1);
|
||||
if (zclient_send_hello(zclient_sync) < 0) {
|
||||
zlog_warn("%s: failed sending hello for synchronous zclient!",
|
||||
__func__);
|
||||
close(zclient_sync->sock);
|
||||
zclient_sync->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (lm_label_manager_connect(zclient_sync, 0) != 0) {
|
||||
zlog_warn("%s: failed connecting to label manager!", __func__);
|
||||
if (zclient_sync->sock > 0) {
|
||||
close(zclient_sync->sock);
|
||||
zclient_sync->sock = -1;
|
||||
}
|
||||
return -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__);
|
||||
sleep(1);
|
||||
}
|
||||
sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void isis_zebra_connected(struct zclient *zclient)
|
||||
@ -738,6 +598,8 @@ void isis_zebra_init(struct thread_master *master, int instance)
|
||||
|
||||
void isis_zebra_stop(void)
|
||||
{
|
||||
zclient_stop(zclient_sync);
|
||||
zclient_free(zclient_sync);
|
||||
zclient_stop(zclient);
|
||||
zclient_free(zclient);
|
||||
frr_fini();
|
||||
|
@ -53,9 +53,9 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
|
||||
int isis_distribute_list_update(int routetype);
|
||||
void isis_zebra_redistribute_set(afi_t afi, int type);
|
||||
void isis_zebra_redistribute_unset(afi_t afi, int type);
|
||||
bool isis_zebra_label_manager_ready(void);
|
||||
int isis_zebra_label_manager_connect(void);
|
||||
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);
|
||||
int isis_zebra_release_label_range(uint32_t start, uint32_t end);
|
||||
|
||||
#endif /* _ZEBRA_ISIS_ZEBRA_H */
|
||||
|
@ -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.";
|
||||
|
Loading…
Reference in New Issue
Block a user