diff options
| author | Renato Westphal <renato@opensourcerouting.org> | 2020-06-24 02:20:12 -0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-24 02:20:12 -0300 | 
| commit | 3f3391e5f43eacf08eb5d57a2ecfdb1c8d6e98fa (patch) | |
| tree | 3da5da43991733d7a538cb38025f211133b0215f | |
| parent | 2fb1599f65192d3b95ec7b0d17e1551c58a36518 (diff) | |
| parent | e075df3a05397a4623bbe07b63551e458bb89b65 (diff) | |
Merge pull request #6451 from Orange-OpenSource/dev_isis_sr
ISISd: Add Segment Routing local block (SRLB)
| -rw-r--r-- | doc/user/isisd.rst | 10 | ||||
| -rw-r--r-- | isisd/isis_cli.c | 56 | ||||
| -rw-r--r-- | isisd/isis_lsp.c | 9 | ||||
| -rw-r--r-- | isisd/isis_nb.c | 21 | ||||
| -rw-r--r-- | isisd/isis_nb.h | 12 | ||||
| -rw-r--r-- | isisd/isis_nb_config.c | 145 | ||||
| -rw-r--r-- | isisd/isis_sr.c | 424 | ||||
| -rw-r--r-- | isisd/isis_sr.h | 26 | ||||
| -rw-r--r-- | isisd/isis_tlvs.c | 144 | ||||
| -rw-r--r-- | isisd/isis_tlvs.h | 19 | ||||
| -rw-r--r-- | isisd/isis_zebra.c | 218 | ||||
| -rw-r--r-- | isisd/isis_zebra.h | 6 | ||||
| -rw-r--r-- | yang/frr-isisd.yang | 17 | 
13 files changed, 832 insertions, 275 deletions
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index dc598ea5bf..200d00821f 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -493,7 +493,15 @@ Known limitations:  .. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575)     Set the Segment Routing Global Block i.e. the label range used by MPLS -   to store label in the MPLS FIB. +   to store label in the MPLS FIB for Prefix SID. Note that the block size +   may not exceed 65535. + +.. index:: [no] segment-routing local-block (0-1048575) (0-1048575) +.. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575) + +   Set the Segment Routing Local Block i.e. the label range used by MPLS +   to store label in the MPLS FIB for Adjacency SID. Note that the block size +   may not exceed 65535.  .. index:: [no] segment-routing node-msd (1-16)  .. clicmd:: [no] segment-routing node-msd (1-16) diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index c421750a82..df69b1c7be 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1400,8 +1400,8 @@ DEFPY (isis_sr_global_block_label_range,         "segment-routing global-block (16-1048575)$lower_bound (16-1048575)$upper_bound",         SR_STR         "Segment Routing Global Block label range\n" -       "The lower bound of SRGB (16-1048575)\n" -       "The upper bound of SRGB (16-1048575)\n") +       "The lower bound of the block\n" +       "The upper bound of the block (block size may not exceed 65535)\n")  {  	nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound",  			      NB_OP_MODIFY, lower_bound_str); @@ -1413,12 +1413,12 @@ DEFPY (isis_sr_global_block_label_range,  DEFPY (no_isis_sr_global_block_label_range,         no_isis_sr_global_block_label_range_cmd, -       "no segment-routing global-block [(0-1048575) (0-1048575)]", +       "no segment-routing global-block [(16-1048575) (16-1048575)]",         NO_STR         SR_STR         "Segment Routing Global Block label range\n" -       "The lower bound of SRGB (16-1048575)\n" -       "The upper bound of SRGB (block size may not exceed 65535)\n") +       "The lower bound of the block\n" +       "The upper bound of the block (block size may not exceed 65535)\n")  {  	nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound",  			      NB_OP_MODIFY, NULL); @@ -1437,6 +1437,50 @@ void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode,  }  /* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb + */ +DEFPY (isis_sr_local_block_label_range, +       isis_sr_local_block_label_range_cmd, +       "segment-routing local-block (16-1048575)$lower_bound (16-1048575)$upper_bound", +       SR_STR +       "Segment Routing Local Block label range\n" +       "The lower bound of the block\n" +       "The upper bound of the block (block size may not exceed 65535)\n") +{ +	nb_cli_enqueue_change(vty, "./segment-routing/srlb/lower-bound", +			      NB_OP_MODIFY, lower_bound_str); +	nb_cli_enqueue_change(vty, "./segment-routing/srlb/upper-bound", +			      NB_OP_MODIFY, upper_bound_str); + +	return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (no_isis_sr_local_block_label_range, +       no_isis_sr_local_block_label_range_cmd, +       "no segment-routing local-block [(16-1048575) (16-1048575)]", +       NO_STR +       SR_STR +       "Segment Routing Local Block label range\n" +       "The lower bound of the block\n" +       "The upper bound of the block (block size may not exceed 65535)\n") +{ +	nb_cli_enqueue_change(vty, "./segment-routing/srlb/lower-bound", +			      NB_OP_MODIFY, NULL); +	nb_cli_enqueue_change(vty, "./segment-routing/srlb/upper-bound", +			      NB_OP_MODIFY, NULL); + +	return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_srlb(struct vty *vty, struct lyd_node *dnode, +			bool show_defaults) +{ +	vty_out(vty, " segment-routing local-block %s %s\n", +		yang_dnode_get_string(dnode, "./lower-bound"), +		yang_dnode_get_string(dnode, "./upper-bound")); +} + +/*   * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd   */  DEFPY (isis_sr_node_msd, @@ -2308,6 +2352,8 @@ void isis_cli_init(void)  	install_element(ISIS_NODE, &no_isis_sr_enable_cmd);  	install_element(ISIS_NODE, &isis_sr_global_block_label_range_cmd);  	install_element(ISIS_NODE, &no_isis_sr_global_block_label_range_cmd); +	install_element(ISIS_NODE, &isis_sr_local_block_label_range_cmd); +	install_element(ISIS_NODE, &no_isis_sr_local_block_label_range_cmd);  	install_element(ISIS_NODE, &isis_sr_node_msd_cmd);  	install_element(ISIS_NODE, &no_isis_sr_node_msd_cmd);  	install_element(ISIS_NODE, &isis_sr_prefix_sid_cmd); diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index e578f616f4..9b04eef6a2 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -933,14 +933,23 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)  			struct isis_sr_db *srdb = &area->srdb;  			uint32_t range_size; +			/* SRGB first */  			range_size = srdb->config.srgb_upper_bound  				     - srdb->config.srgb_lower_bound + 1;  			cap.srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I  					 | ISIS_SUBTLV_SRGB_FLAG_V;  			cap.srgb.range_size = range_size;  			cap.srgb.lower_bound = srdb->config.srgb_lower_bound; +			/* Then Algorithm */  			cap.algo[0] = SR_ALGORITHM_SPF;  			cap.algo[1] = SR_ALGORITHM_UNSET; +			/* SRLB */ +			cap.srlb.flags = 0; +			range_size = srdb->config.srlb_upper_bound +				     - srdb->config.srlb_lower_bound + 1; +			cap.srlb.range_size = range_size; +			cap.srlb.lower_bound = srdb->config.srlb_lower_bound; +			/* And finally MSD */  			cap.msd = srdb->config.msd;  		} diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index f1f183cc59..1d842eb13b 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -465,6 +465,7 @@ const struct frr_yang_module_info frr_isisd_info = {  			.xpath = "/frr-isisd:isis/instance/segment-routing/srgb",  			.cbs = {  				.apply_finish = isis_instance_segment_routing_srgb_apply_finish, +				.pre_validate = isis_instance_segment_routing_srgb_pre_validate,  				.cli_show = cli_show_isis_srgb,  			},  		}, @@ -481,6 +482,26 @@ const struct frr_yang_module_info frr_isisd_info = {  			},  		},  		{ +			.xpath = "/frr-isisd:isis/instance/segment-routing/srlb", +			.cbs = { +				.apply_finish = isis_instance_segment_routing_srlb_apply_finish, +				.pre_validate = isis_instance_segment_routing_srlb_pre_validate, +				.cli_show = cli_show_isis_srlb, +			}, +		}, +		{ +			.xpath = "/frr-isisd:isis/instance/segment-routing/srlb/lower-bound", +			.cbs = { +				.modify = isis_instance_segment_routing_srlb_lower_bound_modify, +			}, +		}, +		{ +			.xpath = "/frr-isisd:isis/instance/segment-routing/srlb/upper-bound", +			.cbs = { +				.modify = isis_instance_segment_routing_srlb_upper_bound_modify, +			}, +		}, +		{  			.xpath = "/frr-isisd:isis/instance/segment-routing/msd/node-msd",  			.cbs = {  				.modify = isis_instance_segment_routing_msd_node_msd_modify, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 36dbc2d619..e887b1a388 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -180,6 +180,10 @@ int isis_instance_segment_routing_srgb_lower_bound_modify(  	struct nb_cb_modify_args *args);  int isis_instance_segment_routing_srgb_upper_bound_modify(  	struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srlb_lower_bound_modify( +	struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srlb_upper_bound_modify( +	struct nb_cb_modify_args *args);  int isis_instance_segment_routing_msd_node_msd_modify(  	struct nb_cb_modify_args *args);  int isis_instance_segment_routing_msd_node_msd_destroy( @@ -289,6 +293,10 @@ lib_interface_state_isis_event_counters_authentication_fails_get_elem(  /* Optional 'pre_validate' callbacks. */  int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate(  	struct nb_cb_pre_validate_args *args); +int isis_instance_segment_routing_srgb_pre_validate( +	struct nb_cb_pre_validate_args *args); +int isis_instance_segment_routing_srlb_pre_validate( +	struct nb_cb_pre_validate_args *args);  /* Optional 'apply_finish' callbacks. */  void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args); @@ -304,6 +312,8 @@ void redistribute_ipv4_apply_finish(struct nb_cb_apply_finish_args *args);  void redistribute_ipv6_apply_finish(struct nb_cb_apply_finish_args *args);  void isis_instance_segment_routing_srgb_apply_finish(  	struct nb_cb_apply_finish_args *args); +void isis_instance_segment_routing_srlb_apply_finish( +	struct nb_cb_apply_finish_args *args);  void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish(  	struct nb_cb_apply_finish_args *args); @@ -370,6 +380,8 @@ void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode,  			      bool show_defaults);  void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode,  			bool show_defaults); +void cli_show_isis_srlb(struct vty *vty, struct lyd_node *dnode, +			bool show_defaults);  void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode,  			    bool show_defaults);  void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 9633e46415..8a37035c9b 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -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);  }  /* @@ -1522,6 +1543,104 @@ int isis_instance_segment_routing_srgb_upper_bound_modify(  }  /* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb + */ +int isis_instance_segment_routing_srlb_pre_validate( +	struct nb_cb_pre_validate_args *args) +{ +	uint32_t srgb_lbound; +	uint32_t srgb_ubound; +	uint32_t srlb_lbound; +	uint32_t srlb_ubound; + +	srgb_lbound = yang_dnode_get_uint32(args->dnode, "../srgb/lower-bound"); +	srgb_ubound = yang_dnode_get_uint32(args->dnode, "../srgb/upper-bound"); +	srlb_lbound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); +	srlb_ubound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + +	/* Check that the block size does not exceed 65535 */ +	if ((srlb_ubound - srlb_lbound + 1) > 65535) { +		zlog_warn( +			"New SR Local Block (%u/%u) exceed the limit of 65535", +			srlb_lbound, srlb_ubound); +		return NB_ERR_VALIDATION; +	} + +	/* Validate SRLB against SRGB */ +	if (!((srlb_ubound < srgb_lbound) || (srlb_lbound > srgb_ubound))) { +		zlog_warn( +			"New SR Local Block (%u/%u) conflict with Global Block (%u/%u)", +			srlb_lbound, srlb_ubound, srgb_lbound, srgb_ubound); +		return NB_ERR_VALIDATION; +	} + +	return NB_OK; +} + +void isis_instance_segment_routing_srlb_apply_finish( +	struct nb_cb_apply_finish_args *args) +{ +	struct isis_area *area; +	uint32_t lower_bound, upper_bound; + +	area = nb_running_get_entry(args->dnode, NULL, true); +	lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); +	upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + +	isis_sr_cfg_srlb_update(area, lower_bound, upper_bound); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb/lower-bound + */ +int isis_instance_segment_routing_srlb_lower_bound_modify( +	struct nb_cb_modify_args *args) +{ +	uint32_t lower_bound = yang_dnode_get_uint32(args->dnode, NULL); + +	switch (args->event) { +	case NB_EV_VALIDATE: +		if (!IS_MPLS_UNRESERVED_LABEL(lower_bound)) { +			zlog_warn("Invalid SRLB lower bound: %" PRIu32, +				  lower_bound); +			return NB_ERR_VALIDATION; +		} +		break; +	case NB_EV_PREPARE: +	case NB_EV_ABORT: +	case NB_EV_APPLY: +		break; +	} + +	return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/srlb/upper-bound + */ +int isis_instance_segment_routing_srlb_upper_bound_modify( +	struct nb_cb_modify_args *args) +{ +	uint32_t upper_bound = yang_dnode_get_uint32(args->dnode, NULL); + +	switch (args->event) { +	case NB_EV_VALIDATE: +		if (!IS_MPLS_UNRESERVED_LABEL(upper_bound)) { +			zlog_warn("Invalid SRLB upper bound: %" PRIu32, +				  upper_bound); +			return NB_ERR_VALIDATION; +		} +		break; +	case NB_EV_PREPARE: +	case NB_EV_ABORT: +	case NB_EV_APPLY: +		break; +	} + +	return NB_OK; +} + +/*   * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd   */  int isis_instance_segment_routing_msd_node_msd_modify( diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index c24c0608b2..f27aca991f 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -52,6 +52,10 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")  static void sr_prefix_uninstall(struct sr_prefix *srp);  static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break); +static void sr_local_block_delete(struct isis_area *area); +static int sr_local_block_init(struct isis_area *area); +static void sr_adj_sid_update(struct sr_adjacency *sra, +			      struct sr_local_block *srlb);  /* --- RB-Tree Management functions ----------------------------------------- */ @@ -135,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); @@ -887,6 +957,26 @@ static inline void sr_prefix_reinstall(struct sr_prefix *srp,  /* --- IS-IS LSP Parse functions -------------------------------------------- */  /** + * Compare Router Capabilities. Only Flags, SRGB and Algorithm are used for the + * comparison. MSD and SRLB modification must not trigger and SR-Prefix update. + * + * @param r1	First Router Capabilities to compare + * @param r2	Second Router Capabilities to compare + * @return	0 if r1 and r2 are equal or -1 otherwise + */ +static int router_cap_cmp(const struct isis_router_cap *r1, +			  const struct isis_router_cap *r2) +{ +	if (r1->flags == r2->flags +	    && r1->srgb.lower_bound == r2->srgb.lower_bound +	    && r1->srgb.range_size == r2->srgb.range_size +	    && r1->algo[0] == r2->algo[0]) +		return 0; +	else +		return -1; +} + +/**   * Parse all SR-related information from the given Router Capabilities TLV.   *   * @param area		IS-IS area @@ -909,8 +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. */ @@ -1782,6 +2074,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.   *   * @param area	IS-IS area @@ -1794,15 +2106,35 @@ int isis_sr_start(struct isis_area *area)  	struct isis_circuit *circuit;  	struct listnode *node; +	/* 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 the allocation fails, return -	 * an error to disable SR until a new SRGB is successfully allocated. +	 * 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 (isis_zebra_request_label_range( -		    srdb->config.srgb_lower_bound, -		    srdb->config.srgb_upper_bound -			    - srdb->config.srgb_lower_bound + 1)) -		return -1; +	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); diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h index dec329ab48..4379a1dcba 100644 --- a/isisd/isis_sr.h +++ b/isisd/isis_sr.h @@ -53,6 +53,8 @@  #define SRGB_LOWER_BOUND               16000  #define SRGB_UPPER_BOUND               23999 +#define SRLB_LOWER_BOUND               15000 +#define SRLB_UPPER_BOUND               15999  /* Segment Routing Data Base (SRDB) RB-Tree structure */  PREDECL_RBTREE_UNIQ(srdb_node) @@ -60,6 +62,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); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 923956fa6d..f3c9c47691 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -2620,30 +2620,35 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,  	/* Segment Routing Global Block as per RFC8667 section #3.1 */  	if (router_cap->srgb.range_size != 0) -		sbuf_push(buf, indent, -			"  Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n", +		sbuf_push( +			buf, indent, +			"  Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",  			IS_SR_IPV4(router_cap->srgb) ? "1" : "0",  			IS_SR_IPV6(router_cap->srgb) ? "1" : "0",  			router_cap->srgb.lower_bound,  			router_cap->srgb.range_size); +	/* Segment Routing Local Block as per RFC8667 section #3.3 */ +	if (router_cap->srlb.range_size != 0) +		sbuf_push(buf, indent, "  SR Local Block Base: %u Range: %u\n", +			  router_cap->srlb.lower_bound, +			  router_cap->srlb.range_size); +  	/* Segment Routing Algorithms as per RFC8667 section #3.2 */  	if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { -		sbuf_push(buf, indent, "    Algorithm: %s", -			  router_cap->algo[0] == 0 ? "0: SPF" -						   : "0: Strict SPF"); -		for (int i = 1; i < SR_ALGORITHM_COUNT; i++) +		sbuf_push(buf, indent, "  SR Algorithm:\n"); +		for (int i = 0; i < SR_ALGORITHM_COUNT; i++)  			if (router_cap->algo[i] != SR_ALGORITHM_UNSET) -				sbuf_push(buf, indent, " %s", -					  router_cap->algo[1] == 0 -						  ? "0: SPF" -						  : "0: Strict SPF"); -		sbuf_push(buf, indent, "\n"); +				sbuf_push(buf, indent, "    %u: %s\n", i, +					  router_cap->algo[i] == 0 +						  ? "SPF" +						  : "Strict SPF");  	}  	/* Segment Routing Node MSD as per RFC8491 section #2 */  	if (router_cap->msd != 0) -		sbuf_push(buf, indent, "    Node MSD: %d\n", router_cap->msd); +		sbuf_push(buf, indent, "  Node Maximum SID Depth: %u\n", +			  router_cap->msd);  }  static void free_tlv_router_cap(struct isis_router_cap *router_cap) @@ -2699,6 +2704,20 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,  			for (int i = 0; i < nb_algo; i++)  				stream_putc(s, router_cap->algo[i]);  		} + +		/* Local Block if defined as per RFC8667 section #3.3 */ +		if ((router_cap->srlb.range_size != 0) +		    && (router_cap->srlb.lower_bound != 0)) { +			stream_putc(s, ISIS_SUBTLV_SRLB); +			stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE); +			/* No Flags are defined for SRLB */ +			stream_putc(s, 0); +			stream_put3(s, router_cap->srlb.range_size); +			stream_putc(s, ISIS_SUBTLV_SID_LABEL); +			stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE); +			stream_put3(s, router_cap->srlb.lower_bound); +		} +  		/* And finish with MSD if set as per RFC8491 section #2 */  		if (router_cap->msd != 0) {  			stream_putc(s, ISIS_SUBTLV_NODE_MSD); @@ -2721,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;  } diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index f468d85bbd..1c0d97f2c3 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -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, diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 502a598523..a80a18d887 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -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)  { @@ -470,6 +464,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.   *   * @param base		base label of the label range to request @@ -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,130 +504,19 @@ 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 - */ -void isis_zebra_release_label_range(uint32_t start, uint32_t end) -{ -	int ret; - -	if (zclient_sync->sock == -1) -		isis_zebra_label_manager_connect(); - -	ret = lm_release_label_chunk(zclient_sync, start, end); -	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 + * @return		0 on success, -1 otherwise   */ -static int isis_zebra_get_label_chunk(void) +int isis_zebra_release_label_range(uint32_t start, uint32_t end)  {  	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); +	if (zclient_sync->sock < 0)  		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__); +		zlog_warn("%s: error releasing label range!", __func__);  		return -1;  	} @@ -631,76 +524,43 @@ static int isis_zebra_release_label_chunk(uint32_t start, uint32_t end)  }  /** - * 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(); diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 2fb54a6291..4449b63c2e 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -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 */ diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 445a59bc8a..befdc3467d 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1213,6 +1213,23 @@ module frr-isisd {                  "Upper value in the label range.";            }          } +        container srlb { +          description +            "Local blocks to be advertised."; +          must "./upper-bound > ./lower-bound"; +          leaf lower-bound { +              type uint32; +              default "15000"; +              description +                "Lower value in the label range."; +          } +          leaf upper-bound { +              type uint32; +              default "15999"; +              description +                "Upper value in the label range."; +          } +        }          container msd {            description              "MSD configuration.";  | 
