diff options
| author | Russ White <russ@riw.us> | 2024-07-02 08:32:05 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-02 08:32:05 -0400 | 
| commit | 410947f6a71abfeb6e51ae04c8f54202d5484641 (patch) | |
| tree | 3f4643e9af66cc9b6712f63bc5072f19de5f925e /isisd | |
| parent | 667715df130cc900e8f5aec02249f8ecd5321409 (diff) | |
| parent | fe5b03a10b583d0a95104a43389a9b60ca9bc397 (diff) | |
Merge pull request #15677 from cscarpitta/isis-srv6-sid-manager
isisd: Extend IS-IS to communicate with the SRv6 SID Manager to allocate/release SRv6 SIDs
Diffstat (limited to 'isisd')
| -rw-r--r-- | isisd/isis_lsp.c | 13 | ||||
| -rw-r--r-- | isisd/isis_nb_config.c | 6 | ||||
| -rw-r--r-- | isisd/isis_srv6.c | 201 | ||||
| -rw-r--r-- | isisd/isis_srv6.h | 14 | ||||
| -rw-r--r-- | isisd/isis_zebra.c | 428 | ||||
| -rw-r--r-- | isisd/isis_zebra.h | 7 | 
6 files changed, 395 insertions, 274 deletions
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c98cee06a5..13f5148d4a 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1222,17 +1222,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)  	}  	/* Add SRv6 Locator TLV. */ -	if (area->srv6db.config.enabled && -	    !list_isempty(area->srv6db.srv6_locator_chunks)) { +	if (area->srv6db.config.enabled && area->srv6db.srv6_locator) {  		struct isis_srv6_locator locator = {}; -		struct srv6_locator_chunk *chunk; - -		/* TODO: support more than one locator */ -		chunk = (struct srv6_locator_chunk *)listgetdata( -			listhead(area->srv6db.srv6_locator_chunks));  		locator.metric = 0; -		locator.prefix = chunk->prefix; +		locator.prefix = area->srv6db.srv6_locator->prefix;  		locator.flags = 0;  		locator.algorithm = 0; @@ -1252,7 +1246,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)  		isis_tlvs_add_ipv6_reach(lsp->tlvs,  					 isis_area_ipv6_topology(area), -					 &chunk->prefix, 0, false, NULL); +					 &area->srv6db.srv6_locator->prefix, 0, +					 false, NULL);  	}  	/* IPv4 address and TE router ID TLVs. diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 763b8b73d2..30c90baa54 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -3518,10 +3518,10 @@ int isis_instance_segment_routing_srv6_locator_modify(  	sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name,  		 area->area_tag); -	sr_debug("Trying to get a chunk from locator %s for IS-IS area %s", -		 loc_name, area->area_tag); +	sr_debug("Trying to get locator %s for IS-IS area %s", loc_name, +		 area->area_tag); -	if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) +	if (isis_zebra_srv6_manager_get_locator(loc_name) < 0)  		return NB_ERR;  	return NB_OK; diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 44fd599cbb..b5974b1a62 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area)  	struct srv6_locator_chunk *chunk;  	struct isis_srv6_sid *sid;  	struct srv6_adjacency *sra; +	struct srv6_sid_ctx ctx = {};  	if (strncmp(area->srv6db.config.srv6_locator_name, "",  		    sizeof(area->srv6db.config.srv6_locator_name)) == 0) { @@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area)  		 * Zebra */  		isis_zebra_srv6_sid_uninstall(area, sid); +		/* +		 * Inform the SID Manager that IS-IS will no longer use the SID, so +		 * that the SID Manager can remove the SID context ownership from IS-IS +		 * and release/free the SID context if it is not yes by other protocols. +		 */ +		ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; +		isis_zebra_release_srv6_sid(&ctx); +  		listnode_delete(area->srv6db.srv6_sids, sid);  		isis_srv6_sid_free(sid);  	}  	/* Uninstall all local Adjacency-SIDs. */ -	for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) +	for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) { +		/* +		 * Inform the SID Manager that IS-IS will no longer use the SID, so +		 * that the SID Manager can remove the SID context ownership from IS-IS +		 * and release/free the SID context if it is not yes by other protocols. +		 */ +		ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; +		ctx.nh6 = sra->nexthop; +		isis_zebra_release_srv6_sid(&ctx); +  		srv6_endx_sid_del(sra); +	}  	/* Inform Zebra that we are releasing the SRv6 locator */  	ret = isis_zebra_srv6_manager_release_locator_chunk( @@ -146,6 +165,10 @@ bool isis_srv6_locator_unset(struct isis_area *area)  		srv6_locator_chunk_free(&chunk);  	} +	/* Clear locator */ +	srv6_locator_free(area->srv6db.srv6_locator); +	area->srv6db.srv6_locator = NULL; +  	/* Clear locator name */  	memset(area->srv6db.config.srv6_locator_name, 0,  	       sizeof(area->srv6db.config.srv6_locator_name)); @@ -198,149 +221,35 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname)  }  /** - * Encode SID function in the SRv6 SID. - * - * @param sid - * @param func - * @param offset - * @param len - */ -static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset, -			    uint8_t len) -{ -	for (uint8_t idx = 0; idx < len; idx++) { -		uint8_t tidx = offset + idx; -		sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); -		if (func >> (len - 1 - idx) & 0x1) -			sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); -	} -} - -static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) -{ -	struct listnode *node; -	struct isis_srv6_sid *s; -	struct srv6_adjacency *sra; - -	for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s)) -		if (sid_same(&s->sid, sid)) -			return true; -	for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra)) -		if (sid_same(&sra->sid, sid)) -			return true; -	return false; -} - -/** - * Request a SID from the SRv6 locator. - * - * @param area		IS-IS area - * @param chunk		SRv6 locator chunk - * @param sid_func	The FUNCTION part of the SID to be allocated (a negative - * number will allocate the first available SID) - * - * @return	First available SID on success or in6addr_any if the SRv6 - * locator chunk is full - */ -static struct in6_addr -srv6_locator_request_sid(struct isis_area *area, -			 struct srv6_locator_chunk *chunk, int sid_func) -{ -	struct in6_addr sid; -	uint8_t offset = 0; -	uint8_t func_len = 0; -	uint32_t func_max; -	bool allocated = false; - -	if (!area || !chunk) -		return in6addr_any; - -	sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", -		 area->area_tag, chunk->locator_name); - -	/* Let's build the SID, step by step. A SID has the following structure -	(defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ - -	/* First, we encode the LOCATOR in the L most significant bits. */ -	sid = chunk->prefix.prefix; - -	/* The next part of the SID is the FUNCTION. Let's compute the length -	 * and the offset of the FUNCTION in the SID */ -	func_len = chunk->function_bits_length; -	offset = chunk->block_bits_length + chunk->node_bits_length; - -	/* Then, encode the FUNCTION */ -	if (sid_func >= 0) { -		/* SID FUNCTION has been specified. We need to allocate a SID -		 * with the requested FUNCTION. */ -		encode_sid_func(&sid, sid_func, offset, func_len); -		if (sid_exist(area, &sid)) { -			zlog_warn( -				"ISIS-SRv6 (%s): the requested SID %pI6 is already used", -				area->area_tag, &sid); -			return sid; -		} -		allocated = true; -	} else { -		/* SID FUNCTION not specified. We need to choose a FUNCTION that -		 * is not already used. So let's iterate through all possible -		 * functions and get the first available one. */ -		func_max = (1 << func_len) - 1; -		for (uint32_t func = 1; func < func_max; func++) { -			encode_sid_func(&sid, func, offset, func_len); -			if (sid_exist(area, &sid)) -				continue; -			allocated = true; -			break; -		} -	} - -	if (!allocated) { -		/* We ran out of available SIDs */ -		zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", -			  area->area_tag, chunk->locator_name); -		return in6addr_any; -	} - -	sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag, -		 &sid); - -	return sid; -} - -/**   * Allocate an SRv6 SID from an SRv6 locator.   *   * @param area		IS-IS area - * @param chunk		SRv6 locator chunk + * @param locator	SRv6 locator   * @param behavior	SRv6 Endpoint Behavior bound to the SID + * @param sid_value	SRv6 SID value   *   * @result the allocated SID on success, NULL otherwise   */  struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator,  		    enum srv6_endpoint_behavior_codepoint behavior, -		    int sid_func) +		    struct in6_addr *sid_value)  {  	struct isis_srv6_sid *sid = NULL; -	if (!area || !chunk) +	if (!area || !locator || !sid_value)  		return NULL;  	sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); -	sid->sid = srv6_locator_request_sid(area, chunk, sid_func); -	if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { -		isis_srv6_sid_free(sid); -		return NULL; -	} +	sid->sid = *sid_value;  	sid->behavior = behavior; -	sid->structure.loc_block_len = chunk->block_bits_length; -	sid->structure.loc_node_len = chunk->node_bits_length; -	sid->structure.func_len = chunk->function_bits_length; -	sid->structure.arg_len = chunk->argument_bits_length; -	sid->locator = chunk; +	sid->structure.loc_block_len = locator->block_bits_length; +	sid->structure.loc_node_len = locator->node_bits_length; +	sid->structure.func_len = locator->function_bits_length; +	sid->structure.arg_len = locator->argument_bits_length; +	sid->locator = locator;  	sid->area = area;  	return sid; @@ -376,9 +285,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level)   * @param adj	   IS-IS Adjacency   * @param backup   True to initialize backup Adjacency SID   * @param nexthops List of backup nexthops (for backup End.X SIDs only) + * @param sid_value SID value associated to be associated with the adjacency   */  void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, -			      struct list *nexthops) +			      struct list *nexthops, struct in6_addr *sid_value)  {  	struct isis_circuit *circuit = adj->circuit;  	struct isis_area *area = circuit->area; @@ -387,11 +297,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,  	struct isis_srv6_lan_endx_sid_subtlv *ladj_sid;  	struct in6_addr nexthop;  	uint8_t flags = 0; -	struct srv6_locator_chunk *chunk; +	struct srv6_locator *locator;  	uint32_t behavior; -	if (!area || !area->srv6db.srv6_locator_chunks || -	    list_isempty(area->srv6db.srv6_locator_chunks)) +	if (!area || !area->srv6db.srv6_locator)  		return;  	sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, @@ -401,10 +310,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,  	if (!circuit->ipv6_router || !adj->ll_ipv6_count)  		return; -	chunk = (struct srv6_locator_chunk *)listgetdata( -		listhead(area->srv6db.srv6_locator_chunks)); -	if (!chunk) -		return; +	locator = area->srv6db.srv6_locator;  	nexthop = adj->ll_ipv6_addrs[0]; @@ -415,25 +321,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,  	if (circuit->ext == NULL)  		circuit->ext = isis_alloc_ext_subtlvs(); -	behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) +	behavior = (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))  			   ? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID  			   : SRV6_ENDPOINT_BEHAVIOR_END_X;  	sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra));  	sra->type = backup ? ISIS_SRV6_ADJ_BACKUP : ISIS_SRV6_ADJ_NORMAL;  	sra->behavior = behavior; -	sra->locator = chunk; -	sra->structure.loc_block_len = chunk->block_bits_length; -	sra->structure.loc_node_len = chunk->node_bits_length; -	sra->structure.func_len = chunk->function_bits_length; -	sra->structure.arg_len = chunk->argument_bits_length; +	sra->locator = locator; +	sra->structure.loc_block_len = locator->block_bits_length; +	sra->structure.loc_node_len = locator->node_bits_length; +	sra->structure.func_len = locator->function_bits_length; +	sra->structure.arg_len = locator->argument_bits_length;  	sra->nexthop = nexthop; -	sra->sid = srv6_locator_request_sid(area, chunk, -1); -	if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { -		XFREE(MTYPE_ISIS_SRV6_INFO, sra); -		return; -	} +	sra->sid = *sid_value;  	switch (circuit->circ_type) {  	/* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ @@ -505,9 +407,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,   *   * @param adj	  IS-IS Adjacency   */ -void srv6_endx_sid_add(struct isis_adjacency *adj) +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value)  { -	srv6_endx_sid_add_single(adj, false, NULL); +	srv6_endx_sid_add_single(adj, false, NULL, sid_value);  }  /** @@ -610,7 +512,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family,  	    family != AF_INET6)  		return 0; -	srv6_endx_sid_add(adj); +	isis_zebra_request_srv6_sid_endx(adj);  	return 0;  } @@ -832,6 +734,9 @@ void isis_srv6_area_term(struct isis_area *area)  		srv6_locator_chunk_free(&chunk);  	list_delete(&srv6db->srv6_locator_chunks); +	srv6_locator_free(area->srv6db.srv6_locator); +	area->srv6db.srv6_locator = NULL; +  	/* Free SRv6 SIDs list */  	list_delete(&srv6db->srv6_sids);  	list_delete(&srv6db->srv6_endx_sids); diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 7f16712ae3..bde14965f6 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -44,7 +44,7 @@ struct isis_srv6_sid {  	struct isis_srv6_sid_structure structure;  	/* Parent SRv6 locator */ -	struct srv6_locator_chunk *locator; +	struct srv6_locator *locator;  	/* Backpointer to IS-IS area */  	struct isis_area *area; @@ -89,7 +89,7 @@ struct srv6_adjacency {  	struct isis_srv6_sid_structure structure;  	/* Parent SRv6 locator */ -	struct srv6_locator_chunk *locator; +	struct srv6_locator *locator;  	/* Adjacency-SID nexthop information */  	struct in6_addr nexthop; @@ -109,6 +109,8 @@ struct srv6_adjacency {  /* Per-area IS-IS SRv6 Data Base (SRv6 DB) */  struct isis_srv6_db { +	/* List of SRv6 Locator */ +	struct srv6_locator *srv6_locator;  	/* List of SRv6 Locator chunks */  	struct list *srv6_locator_chunks; @@ -149,9 +151,9 @@ bool isis_srv6_locator_unset(struct isis_area *area);  void isis_srv6_interface_set(struct isis_area *area, const char *ifname);  struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator,  		    enum srv6_endpoint_behavior_codepoint behavior, -		    int sid_func); +		    struct in6_addr *sid_value);  extern void isis_srv6_sid_free(struct isis_srv6_sid *sid);  extern void isis_srv6_area_init(struct isis_area *area); @@ -169,8 +171,8 @@ void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc,  			   struct isis_srv6_locator_tlv *loc_tlv);  void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, -			      struct list *nexthops); -void srv6_endx_sid_add(struct isis_adjacency *adj); +			      struct list *nexthops, struct in6_addr *sid_value); +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value);  void srv6_endx_sid_del(struct srv6_adjacency *sra);  struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj,  					       enum srv6_adj_type type); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 2412ec5e84..ce4eb74ec6 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -645,6 +645,70 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)  }  /** + * Request an End.X SID for an IS-IS adjacency. + * + * @param adj	   IS-IS Adjacency + */ +void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) +{ +	struct isis_circuit *circuit = adj->circuit; +	struct isis_area *area = circuit->area; +	struct in6_addr nexthop; +	struct srv6_sid_ctx ctx = {}; +	struct in6_addr sid_value = {}; +	bool ret; + +	if (!area || !area->srv6db.srv6_locator) +		return; + +	/* Determine nexthop IP address */ +	if (!circuit->ipv6_router || !adj->ll_ipv6_count) +		return; + +	nexthop = adj->ll_ipv6_addrs[0]; + +	ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; +	ctx.nh6 = nexthop; +	ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, +					  area->srv6db.config.srv6_locator_name); +	if (!ret) { +		zlog_err("%s: not allocated new End.X SID for IS-IS area %s", +			 __func__, area->area_tag); +		return; +	} +} + +static void request_srv6_sids(struct isis_area *area) +{ +	struct srv6_sid_ctx ctx = {}; +	struct in6_addr sid_value = {}; +	struct listnode *node; +	struct isis_adjacency *adj; +	bool ret; + +	if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator) +		return; + +	sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag); + +	/* Request new SRv6 End SID */ +	ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; +	ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, +					  area->srv6db.config.srv6_locator_name); +	if (!ret) { +		zlog_err("%s: not allocated new End SID for IS-IS area %s", +			 __func__, area->area_tag); +		return; +	} + +	/* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ +	for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { +		if (adj->ll_ipv6_count > 0) +			isis_zebra_request_srv6_sid_endx(adj); +	} +} + +/**   * Release Label Range to the Label Manager.   *   * @param start		start of label range to release @@ -1119,99 +1183,47 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra)  }  /** - * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). + * Internal function to process an SRv6 locator   * - * @result 0 on success, -1 otherwise + * @param locator The locator to be processed   */ -static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator)  {  	struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); -	struct stream *s = NULL; -	struct listnode *node;  	struct isis_area *area; -	struct srv6_locator_chunk *c; -	struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc(); -	struct isis_srv6_sid *sid; -	struct isis_adjacency *adj; -	enum srv6_endpoint_behavior_codepoint behavior; -	bool allocated = false; - -	if (!isis) { -		srv6_locator_chunk_free(&chunk); -		return -1; -	} +	struct listnode *node; -	/* Decode the received zebra message */ -	s = zclient->ibuf; -	if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { -		srv6_locator_chunk_free(&chunk); +	if (!isis || !locator)  		return -1; -	} -	sr_debug( -		"Received SRv6 locator chunk from zebra: name %s, " -		"prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", -		chunk->locator_name, &chunk->prefix, chunk->block_bits_length, -		chunk->node_bits_length, chunk->function_bits_length, -		chunk->argument_bits_length); +	zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u", +		  __func__, locator->name, &locator->prefix, +		  locator->block_bits_length, locator->node_bits_length, +		  locator->function_bits_length, locator->argument_bits_length);  	/* Walk through all areas of the ISIS instance */  	for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { -		if (strncmp(area->srv6db.config.srv6_locator_name, -			    chunk->locator_name, -			    sizeof(area->srv6db.config.srv6_locator_name)) != 0) +		/* +		 * Check if the IS-IS area is configured to use the received +		 * locator +		 */ +		if (strncmp(area->srv6db.config.srv6_locator_name, locator->name, +			    sizeof(area->srv6db.config.srv6_locator_name)) != 0) { +			zlog_err("%s: SRv6 Locator name unmatch %s:%s", +				 __func__, area->srv6db.config.srv6_locator_name, +				 locator->name);  			continue; - -		for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks, -					  node, c)) { -			if (!prefix_cmp(&c->prefix, &chunk->prefix)) { -				srv6_locator_chunk_free(&chunk); -				return 0; -			} -		} - -		sr_debug( -			"SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s", -			chunk->locator_name, &chunk->prefix, area->area_tag); - -		/* Add the SRv6 Locator chunk to the per-area chunks list */ -		listnode_add(area->srv6db.srv6_locator_chunks, chunk); - -		/* Decide which behavior to use,depending on the locator type -		 * (i.e. uSID vs classic locator) */ -		behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) -				   ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID -				   : SRV6_ENDPOINT_BEHAVIOR_END; - -		/* Allocate new SRv6 End SID */ -		sid = isis_srv6_sid_alloc(area, chunk, behavior, 0); -		if (!sid) -			return -1; - -		/* Install the new SRv6 End SID in the forwarding plane through -		 * Zebra */ -		isis_zebra_srv6_sid_install(area, sid); - -		/* Store the SID */ -		listnode_add(area->srv6db.srv6_sids, sid); - -		/* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ -		for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { -			if (adj->ll_ipv6_count > 0) -				srv6_endx_sid_add(adj);  		} -		/* Regenerate LSPs to advertise the new locator and the SID */ -		lsp_regenerate_schedule(area, area->is_type, 0); +		sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s", +			 locator->name, &locator->prefix, area->area_tag); -		allocated = true; -		break; -	} +		/* Store the locator in the IS-IS area */ +		area->srv6db.srv6_locator = srv6_locator_alloc(locator->name); +		srv6_locator_copy(area->srv6db.srv6_locator, locator); -	if (!allocated) { -		sr_debug("No IS-IS area configured for the locator %s", -			 chunk->locator_name); -		srv6_locator_chunk_free(&chunk); +		/* Request SIDs from the locator */ +		request_srv6_sids(area);  	}  	return 0; @@ -1226,8 +1238,6 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)  {  	struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);  	struct srv6_locator loc = {}; -	struct listnode *node; -	struct isis_area *area;  	if (!isis)  		return -1; @@ -1236,33 +1246,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)  	if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)  		return -1; -	sr_debug( -		"New SRv6 locator allocated in zebra: name %s, " -		"prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", -		loc.name, &loc.prefix, loc.block_bits_length, -		loc.node_bits_length, loc.function_bits_length, -		loc.argument_bits_length); - -	/* Lookup on the IS-IS areas */ -	for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { -		/* If SRv6 is enabled on this area and the configured locator -		 * corresponds to the new locator, then request a chunk from the -		 * locator */ -		if (area->srv6db.config.enabled && -		    strncmp(area->srv6db.config.srv6_locator_name, loc.name, -			    sizeof(area->srv6db.config.srv6_locator_name)) == 0) { -			sr_debug( -				"Sending a request to get a chunk from the SRv6 locator %s (%pFX) " -				"for IS-IS area %s", -				loc.name, &loc.prefix, area->area_tag); - -			if (isis_zebra_srv6_manager_get_locator_chunk( -				    loc.name) < 0) -				return -1; -		} -	} - -	return 0; +	return isis_zebra_process_srv6_locator_internal(&loc);  }  /** @@ -1335,6 +1319,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)  			}  		} +		srv6_locator_free(area->srv6db.srv6_locator); +		area->srv6db.srv6_locator = NULL; +  		/* Regenerate LSPs to advertise that the locator no longer  		 * exists */  		lsp_regenerate_schedule(area, area->is_type, 0); @@ -1368,6 +1355,232 @@ int isis_zebra_srv6_manager_release_locator_chunk(const char *name)  	return srv6_manager_release_locator_chunk(zclient, name);  } +/** + * Ask the SRv6 Manager (zebra) about a specific locator + * + * @param name Locator name + * @return 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_get_locator(const char *name) +{ +	if (!name) +		return -1; + +	/* +	 * Send the Get Locator request to the SRv6 Manager and return the +	 * result +	 */ +	return srv6_manager_get_locator(zclient, name); +} + +/** + * Ask the SRv6 Manager (zebra) to allocate a SID. + * + * Optionally, it is possible to provide an IPv6 address (sid_value parameter). + * + * When sid_value is provided, the SRv6 Manager allocates the requested SID + * address, if the request can be satisfied (explicit allocation). + * + * When sid_value is not provided, the SRv6 Manager allocates any available SID + * from the provided locator (dynamic allocation). + * + * @param ctx Context to be associated with the request SID + * @param sid_value IPv6 address to be associated with the requested SID (optional) + * @param locator_name Name of the locator from which the SID must be allocated + */ +bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, +				 struct in6_addr *sid_value, +				 const char *locator_name) +{ +	int ret; + +	if (!ctx || !locator_name) +		return false; + +	/* +	 * Send the Get SRv6 SID request to the SRv6 Manager and check the +	 * result +	 */ +	ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name, NULL); +	if (ret < 0) { +		zlog_warn("%s: error getting SRv6 SID!", __func__); +		return false; +	} + +	return true; +} + +/** + * Ask the SRv6 Manager (zebra) to release a previously allocated SID. + * + * This function is used to tell the SRv6 Manager that IS-IS no longer intends + * to use the SID. + * + * @param ctx Context to be associated with the SID to be released + */ +void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx) +{ +	int ret; + +	if (!ctx) +		return; + +	/* +	 * Send the Release SRv6 SID request to the SRv6 Manager and check the +	 * result +	 */ +	ret = srv6_manager_release_sid(zclient, ctx); +	if (ret < 0) { +		zlog_warn("%s: error releasing SRv6 SID!", __func__); +		return; +	} +} + +static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) +{ +	struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); +	struct srv6_sid_ctx ctx; +	struct in6_addr sid_addr; +	enum zapi_srv6_sid_notify note; +	uint32_t sid_func; +	struct isis_area *area; +	struct listnode *node, *nnode, *n; +	char buf[256]; +	struct srv6_locator *locator; +	struct prefix_ipv6 tmp_prefix; +	struct srv6_adjacency *sra; +	enum srv6_endpoint_behavior_codepoint behavior; +	struct isis_srv6_sid *sid; +	struct isis_adjacency *adj; + +	if (!isis) +		return -1; + +	/* Decode the received notification message */ +	if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, +					 &sid_func, NULL, ¬e, NULL)) { +		zlog_err("%s : error in msg decode", __func__); +		return -1; +	} + +	sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", +		 __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, +		 sid_func, zapi_srv6_sid_notify2str(note)); + +	for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { +		if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator) +			continue; + +		locator = area->srv6db.srv6_locator; + +		/* Verify that the received SID belongs to the configured locator */ +		if (note == ZAPI_SRV6_SID_ALLOCATED) { +			tmp_prefix.family = AF_INET6; +			tmp_prefix.prefixlen = IPV6_MAX_BITLEN; +			tmp_prefix.prefix = sid_addr; + +			if (!prefix_match((struct prefix *)&locator->prefix, +					  (struct prefix *)&tmp_prefix)) { +				sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match", +					 __func__, area->area_tag); +				continue; +			} +		} + +		/* Handle notification */ +		switch (note) { +		case ZAPI_SRV6_SID_ALLOCATED: +			sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, +				 srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + +			if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { +				/* Remove old End SIDs, if any */ +				for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, +						       node, nnode, sid)) { +					isis_zebra_srv6_sid_uninstall(area, sid); +					listnode_delete(area->srv6db.srv6_sids, +							sid); +				} + +				/* Allocate new SRv6 End SID */ +				behavior = +					(CHECK_FLAG(locator->flags, +						    SRV6_LOCATOR_USID)) +						? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID +						: SRV6_ENDPOINT_BEHAVIOR_END; +				sid = isis_srv6_sid_alloc(area, +							  area->srv6db +								  .srv6_locator, +							  behavior, &sid_addr); +				if (!sid) { +					zlog_warn("%s: isis_srv6_sid_alloc failed", +						  __func__); +					return -1; +				} + +				/* +				 * Install the new SRv6 End SID in the forwarding plane through +				 * Zebra +				 */ +				isis_zebra_srv6_sid_install(area, sid); + +				/* Store the SID */ +				listnode_add(area->srv6db.srv6_sids, sid); + +			} else if (ctx.behavior == +				   ZEBRA_SEG6_LOCAL_ACTION_END_X) { +				for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, +							  n, adj)) { +					/* Check if the End.X SID is for this adjacecny */ +					if (adj->ll_ipv6_count == 0 || +					    memcmp(&adj->ll_ipv6_addrs[0], +						   &ctx.nh6, +						   sizeof(struct in6_addr)) != 0) +						continue; + +					/* Remove old End.X SIDs, if any */ +					for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, +							       node, nnode, sra)) +						srv6_endx_sid_del(sra); + +					/* Allocate new End.X SID for the adjacency */ +					srv6_endx_sid_add_single(adj, false, +								 NULL, +								 &sid_addr); +				} +			} else { +				zlog_warn("%s: unsupported behavior %u", +					  __func__, ctx.behavior); +				return -1; +			} +			break; +		case ZAPI_SRV6_SID_RELEASED: +			sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr, +				 srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); +			break; +		case ZAPI_SRV6_SID_FAIL_ALLOC: +			sr_debug("SRv6 SID %pI6 %s: Failed to allocate", +				 &sid_addr, +				 srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + +			/* Error will be logged by zebra module */ +			break; +		case ZAPI_SRV6_SID_FAIL_RELEASE: +			zlog_warn("%s: SRv6 SID %pI6 %s failure to release", +				  __func__, &sid_addr, +				  srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + +			/* Error will be logged by zebra module */ +			break; +		} + +		/* Regenerate LSPs to advertise the new locator and the SID */ +		lsp_regenerate_schedule(area, area->is_type, 0); +	} + +	return 0; +} +  static zclient_handler *const isis_handlers[] = {  	[ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra,  	[ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -1380,10 +1593,9 @@ static zclient_handler *const isis_handlers[] = {  	[ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, -	[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = -		isis_zebra_process_srv6_locator_chunk,  	[ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add,  	[ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, +	[ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify,  };  void isis_zebra_init(struct event_loop *master, int instance) diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index f1684b7c25..79da16efac 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -68,4 +68,11 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra);  extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name);  extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); +extern int isis_zebra_srv6_manager_get_locator(const char *name); +extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj); +extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, +					struct in6_addr *sid_value, +					const char *locator_name); +extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx); +  #endif /* _ZEBRA_ISIS_ZEBRA_H */  | 
