diff options
| author | Russ White <russ@riw.us> | 2025-02-26 09:52:08 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-26 09:52:08 -0500 | 
| commit | 9a939d6ed60b31946a41d8a78953774f4f66bfb4 (patch) | |
| tree | cd10743b4ac4f309b214e5a38dc7de723cadfc8d | |
| parent | 1016090a8a5df21ccc11b489d00933fcbc7267b6 (diff) | |
| parent | 35b40cc996e9c5359e7ea724ed907986e5a05694 (diff) | |
Merge pull request #18198 from cscarpitta/feature/srv6_staticd_ua
staticd: Add support for SRv6 uA behavior
| -rw-r--r-- | doc/user/static.rst | 11 | ||||
| -rw-r--r-- | lib/srv6.h | 1 | ||||
| -rw-r--r-- | staticd/static_nb.c | 21 | ||||
| -rw-r--r-- | staticd/static_nb.h | 16 | ||||
| -rw-r--r-- | staticd/static_nb_config.c | 107 | ||||
| -rw-r--r-- | staticd/static_vty.c | 46 | ||||
| -rw-r--r-- | staticd/static_zebra.c | 53 | ||||
| -rw-r--r-- | tests/topotests/static_srv6_sids/expected_srv6_sids.json | 35 | ||||
| -rw-r--r-- | tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_1.json | 35 | ||||
| -rw-r--r-- | tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_2.json | 35 | ||||
| -rw-r--r-- | tests/topotests/static_srv6_sids/r1/frr.conf | 1 | ||||
| -rw-r--r-- | yang/frr-staticd.yang | 22 | ||||
| -rw-r--r-- | zebra/zebra_srv6.c | 46 | 
13 files changed, 419 insertions, 10 deletions
diff --git a/doc/user/static.rst b/doc/user/static.rst index 0ce6e2107e..c1d11cf0b0 100644 --- a/doc/user/static.rst +++ b/doc/user/static.rst @@ -207,17 +207,18 @@ SRv6 Static SIDs Commands     Move from srv6 node to static-sids node. In this static-sids node, user can     configure static SRv6 SIDs. -.. clicmd:: sid X:X::X:X/M locator NAME behavior <uN|uDT4|uDT6|uDT46> [vrf VRF] +.. clicmd:: sid X:X::X:X/M locator NAME behavior <uN|uA|uDT4|uDT6|uDT46> [vrf VRF] [interface IFNAME [nexthop X:X::X:X]]     Specify the locator sid manually. Configuring a local sid in a purely static mode     by specifying the sid value would generate a unique SID.     This feature will support the configuration of static SRv6 decapsulation on the system. -   It supports four parameter options, corresponding to the following functions: -   uN, uDT4, uDT6, uDT46 +   It supports the following behaviors: uN, uA, uDT4, uDT6, uDT46.     When configuring the local sid, if the action is set to 'uN', no vrf should be set. -   While for any other action, it is necessary to specify a specific vrf. +   For uDT4, uDT6 and uDT46, it is necessary to specify a specific vrf. +   The uA behavior requires the outgoing interface and optionally the IPv6 address of the Layer 3 adjacency +   to which the packet should be forwarded.  :: @@ -228,6 +229,7 @@ SRv6 Static SIDs Commands     router(config-srv6-sids)# sid fcbb:bbbb:1:fe01::/64 locator LOC1 behavior uDT6 vrf Vrf1     router(config-srv6-sids)# sid fcbb:bbbb:1:fe02::/64 locator LOC1 behavior uDT4 vrf Vrf1     router(config-srv6-sids)# sid fcbb:bbbb:1:fe03::/64 locator LOC1 behavior uDT46 vrf Vrf2 +   router(config-srv6-sids)# sid fcbb:bbbb:1:fe04::/64 locator LOC1 behavior uA interface eth0 nexthop 2001::2     router(config-srv6-locator)# show run     ... @@ -237,5 +239,6 @@ SRv6 Static SIDs Commands        sid    fcbb:bbbb:1:fe01::/64 locator LOC1 behavior uDT6 vrf Vrf1        sid    fcbb:bbbb:1:fe02::/64 locator LOC1 behavior uDT4 vrf Vrf1        sid    fcbb:bbbb:1:fe03::/64 locator LOC1 behavior uDT46 vrf Vrf2 +      sid    fcbb:bbbb:1:fe04::/64 locator LOC1 behavior uA interface eth0 nexthop 2001::2         !     ...
\ No newline at end of file diff --git a/lib/srv6.h b/lib/srv6.h index 3200aee70a..467f02a3c9 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -321,6 +321,7 @@ struct srv6_sid_ctx {  	struct in_addr nh4;  	struct in6_addr nh6;  	vrf_id_t vrf_id; +	ifindex_t ifindex;  };  static inline const char *seg6_mode2str(enum seg6_mode_t mode) diff --git a/staticd/static_nb.c b/staticd/static_nb.c index ef363bfe7e..60dc3dc788 100644 --- a/staticd/static_nb.c +++ b/staticd/static_nb.c @@ -157,6 +157,27 @@ const struct frr_yang_module_info frr_staticd_info = {  			}  		},  		{ +			.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid/paths", +			.cbs = { +				.create = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_create, +				.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_destroy, +			} +		}, +		{ +			.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid/paths/interface", +			.cbs = { +				.modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_modify, +				.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_destroy, +			} +		}, +		{ +			.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid/paths/next-hop", +			.cbs = { +				.modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_modify, +				.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_destroy, +			} +		}, +		{  			.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid/locator-name",  			.cbs = {  				.modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify, diff --git a/staticd/static_nb.h b/staticd/static_nb.h index aa11f34021..282c9dcf11 100644 --- a/staticd/static_nb.h +++ b/staticd/static_nb.h @@ -96,6 +96,18 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routi  	struct nb_cb_modify_args *args);  int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_destroy(  	struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_create( +	struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_destroy( +	struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_modify( +	struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_destroy( +	struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_modify( +	struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_destroy( +	struct nb_cb_destroy_args *args);  int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify(  	struct nb_cb_modify_args *args);  int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy( @@ -183,6 +195,10 @@ int routing_control_plane_protocols_name_validate(  #define FRR_STATIC_SRV6_SID_LOCATOR_NAME_XPATH "/locator-name" +#define FRR_STATIC_SRV6_SID_INTERFACE_XPATH "/paths[path-index=%u]/interface" + +#define FRR_STATIC_SRV6_SID_NEXTHOP_XPATH "/paths[path-index=%u]/next-hop" +  #ifdef __cplusplus  }  #endif diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index e2ab1f2ffe..71df15fa61 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -1231,6 +1231,113 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routi  /*   * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/paths + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_create( +	struct nb_cb_create_args *args) +{ +	/* Actual setting is done in apply_finish */ +	return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_destroy( +	struct nb_cb_destroy_args *args) +{ +	return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/paths/interface + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_modify( +	struct nb_cb_modify_args *args) +{ +	struct static_srv6_sid *sid; +	const char *ifname; + +	if (args->event != NB_EV_APPLY) +		return NB_OK; + +	sid = nb_running_get_entry(args->dnode, NULL, true); + +	/* Release and uninstall existing SID, if any, before requesting the new one */ +	if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) { +		static_zebra_release_srv6_sid(sid); +		UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID); +	} + +	if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) { +		static_zebra_srv6_sid_uninstall(sid); +		UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA); +	} + +	ifname = yang_dnode_get_string(args->dnode, "../interface"); +	snprintf(sid->attributes.ifname, sizeof(sid->attributes.ifname), "%s", ifname); + +	return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_destroy( +	struct nb_cb_destroy_args *args) +{ +	return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/paths/next-hop + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_modify( +	struct nb_cb_modify_args *args) +{ +	struct static_srv6_sid *sid; +	struct ipaddr nexthop; + +	switch (args->event) { +	case NB_EV_VALIDATE: +		zlog_info("validating nexthop %pI6", &nexthop.ipaddr_v6); +		yang_dnode_get_ip(&nexthop, args->dnode, "../next-hop"); +		if (!IS_IPADDR_V6(&nexthop)) { +			snprintf(args->errmsg, args->errmsg_len, +				 "%% Nexthop must be an IPv6 address"); +			return NB_ERR_VALIDATION; +		} +		break; +	case NB_EV_ABORT: +	case NB_EV_PREPARE: +		break; +	case NB_EV_APPLY: +		sid = nb_running_get_entry(args->dnode, NULL, true); + +		/* Release and uninstall existing SID, if any, before requesting the new one */ +		if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) { +			static_zebra_release_srv6_sid(sid); +			UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID); +		} + +		if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) { +			static_zebra_srv6_sid_uninstall(sid); +			UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA); +		} + +		yang_dnode_get_ip(&nexthop, args->dnode, "../next-hop"); +		sid->attributes.nh6 = nexthop.ipaddr_v6; + +		break; +	} + +	return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_destroy( +	struct nb_cb_destroy_args *args) +{ +	return NB_OK; +} + +/* + * XPath:   * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/vrf-name   */  int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify( diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 5c19d23883..6e9087363d 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -1199,13 +1199,18 @@ DEFUN_NOSH (static_srv6_sids, static_srv6_sids_cmd,  }  DEFPY_YANG(srv6_sid, srv6_sid_cmd, -      "sid X:X::X:X/M locator NAME$locator_name behavior <uN | uDT6 vrf VIEWVRFNAME | uDT4 vrf VIEWVRFNAME | uDT46 vrf VIEWVRFNAME>", +      "sid X:X::X:X/M locator NAME$locator_name behavior <uN | uA interface INTERFACE$interface [nexthop X:X::X:X$nh6] | uDT6 vrf VIEWVRFNAME | uDT4 vrf VIEWVRFNAME | uDT46 vrf VIEWVRFNAME>",  	  "Configure SRv6 SID\n"        "Specify SRv6 SID\n"  	  "Locator name\n"        "Specify Locator name\n"        "Specify SRv6 SID behavior\n"        "Apply the code to a uN SID\n" +      "Behavior uA\n" +      "Configure the interface\n" +      "Interface name\n" +      "Configure the nexthop\n" +      "IPv6 address of the nexthop\n"        "Apply the code to an uDT6 SID\n"        "Configure VRF name\n"        "Specify VRF name\n" @@ -1223,7 +1228,10 @@ DEFPY_YANG(srv6_sid, srv6_sid_cmd,  	char xpath_sid[XPATH_MAXLEN];  	char xpath_behavior[XPATH_MAXLEN];  	char xpath_vrf_name[XPATH_MAXLEN]; +	char xpath_ifname[XPATH_MAXLEN]; +	char xpath_nexthop[XPATH_MAXLEN];  	char xpath_locator_name[XPATH_MAXLEN]; +	char ab_xpath[XPATH_MAXLEN];  	if (argv_find(argv, argc, "uN", &idx)) {  		behavior = SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID; @@ -1236,6 +1244,8 @@ DEFPY_YANG(srv6_sid, srv6_sid_cmd,  	} else if (argv_find(argv, argc, "uDT46", &idx)) {  		behavior = SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID;  		vrf_name = argv[idx + 2]->arg; +	} else if (argv_find(argv, argc, "uA", &idx)) { +		behavior = SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID;  	}  	snprintf(xpath_srv6, sizeof(xpath_srv6), FRR_STATIC_SRV6_INFO_KEY_XPATH, @@ -1259,6 +1269,22 @@ DEFPY_YANG(srv6_sid, srv6_sid_cmd,  		nb_cli_enqueue_change(vty, xpath_vrf_name, NB_OP_MODIFY, vrf_name);  	} +	if (interface) { +		snprintf(ab_xpath, sizeof(ab_xpath), FRR_STATIC_SRV6_SID_INTERFACE_XPATH, 0); +		strlcpy(xpath_ifname, xpath_sid, sizeof(xpath_ifname)); +		strlcat(xpath_ifname, ab_xpath, sizeof(xpath_ifname)); + +		nb_cli_enqueue_change(vty, xpath_ifname, NB_OP_MODIFY, interface); +	} + +	if (nh6_str) { +		snprintf(ab_xpath, sizeof(ab_xpath), FRR_STATIC_SRV6_SID_NEXTHOP_XPATH, 0); +		strlcpy(xpath_nexthop, xpath_sid, sizeof(xpath_nexthop)); +		strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop)); + +		nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_MODIFY, nh6_str); +	} +  	strlcpy(xpath_locator_name, xpath_sid, sizeof(xpath_locator_name));  	strlcat(xpath_locator_name, FRR_STATIC_SRV6_SID_LOCATOR_NAME_XPATH,  		sizeof(xpath_locator_name)); @@ -1269,7 +1295,7 @@ DEFPY_YANG(srv6_sid, srv6_sid_cmd,  }  DEFPY_YANG(no_srv6_sid, no_srv6_sid_cmd, -      "no sid X:X::X:X/M [locator NAME$locator_name] [behavior <uN | uDT6 vrf VIEWVRFNAME | uDT4 vrf VIEWVRFNAME | uDT46 vrf VIEWVRFNAME>]", +      "no sid X:X::X:X/M [locator NAME$locator_name] [behavior <uN | uA interface INTERFACE$interface [nexthop X:X::X:X$nh6] | uDT6 vrf VIEWVRFNAME | uDT4 vrf VIEWVRFNAME | uDT46 vrf VIEWVRFNAME>]",        NO_STR  	  "Configure SRv6 SID\n"        "Specify SRv6 SID\n" @@ -1277,6 +1303,11 @@ DEFPY_YANG(no_srv6_sid, no_srv6_sid_cmd,        "Specify Locator name\n"        "Specify SRv6 SID behavior\n"        "Apply the code to a uN SID\n" +      "Behavior uA\n" +      "Configure the interface\n" +      "Interface name\n" +      "Configure the nexthop\n" +      "IPv6 address of the nexthop\n"        "Apply the code to an uDT6 SID\n"        "Configure VRF name\n"        "Specify VRF name\n" @@ -1685,6 +1716,7 @@ static void srv6_sid_cli_show(struct vty *vty, const struct lyd_node *sid, bool  {  	enum srv6_endpoint_behavior_codepoint srv6_behavior;  	struct prefix_ipv6 sid_value; +	struct ipaddr nexthop;  	yang_dnode_get_ipv6p(&sid_value, sid, "sid"); @@ -1756,6 +1788,16 @@ static void srv6_sid_cli_show(struct vty *vty, const struct lyd_node *sid, bool  	if (yang_dnode_exists(sid, "vrf-name"))  		vty_out(vty, " vrf %s", yang_dnode_get_string(sid, "vrf-name")); +	if (yang_dnode_exists(sid, "paths[path-index=0]/interface")) { +		vty_out(vty, " interface %s", +			yang_dnode_get_string(sid, "paths[path-index=0]/interface")); + +		if (yang_dnode_exists(sid, "paths[path-index=0]/next-hop")) { +			yang_dnode_get_ip(&nexthop, sid, "paths[path-index=0]/next-hop"); +			vty_out(vty, " nexthop %pI6", &nexthop.ipaddr_v6); +		} +	} +  	vty_out(vty, "\n");  } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 3faeb3d37a..a6521cccc6 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -706,12 +706,24 @@ void static_zebra_srv6_sid_install(struct static_srv6_sid *sid)  			return;  		}  		break; +	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: +		action = ZEBRA_SEG6_LOCAL_ACTION_END_X; +		ctx.nh6 = sid->attributes.nh6; +		ifp = if_lookup_by_name(sid->attributes.ifname, VRF_DEFAULT); +		if (!ifp) { +			zlog_warn("Failed to install SID %pFX: failed to get interface %s", +				  &sid->addr, sid->attributes.ifname); +			return; +		} +		SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); +		ctx.flv.lcblock_len = sid->locator->block_bits_length; +		ctx.flv.lcnode_func_len = sid->locator->node_bits_length; +		break;  	case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_X:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD: -	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: @@ -834,12 +846,20 @@ void static_zebra_srv6_sid_uninstall(struct static_srv6_sid *sid)  			return;  		}  		break; +	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: +		ctx.nh6 = sid->attributes.nh6; +		ifp = if_lookup_by_name(sid->attributes.ifname, VRF_DEFAULT); +		if (!ifp) { +			zlog_warn("Failed to install SID %pFX: failed to get interface %s", +				  &sid->addr, sid->attributes.ifname); +			return; +		} +		break;  	case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_X:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD: -	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: @@ -894,6 +914,7 @@ extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid)  	struct srv6_sid_ctx ctx = {};  	int ret = 0;  	struct vrf *vrf; +	struct interface *ifp;  	if (!sid)  		return; @@ -945,12 +966,22 @@ extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid)  		}  		break; +	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: +		ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; +		ctx.nh6 = sid->attributes.nh6; +		ifp = if_lookup_by_name(sid->attributes.ifname, VRF_DEFAULT); +		if (!ifp) { +			zlog_warn("Failed to request SRv6 SID %pFX: interface %s does not exist", +				  &sid->addr, sid->attributes.ifname); +			return; +		} +		ctx.ifindex = ifp->ifindex; +		break;  	case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_X:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD: -	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: @@ -970,6 +1001,7 @@ extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid)  	struct srv6_sid_ctx ctx = {};  	struct vrf *vrf;  	int ret = 0; +	struct interface *ifp;  	if (!sid || !CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID))  		return; @@ -1021,12 +1053,22 @@ extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid)  		}  		break; +	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: +		ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; +		ctx.nh6 = sid->attributes.nh6; +		ifp = if_lookup_by_name(sid->attributes.ifname, VRF_DEFAULT); +		if (!ifp) { +			zlog_warn("Failed to request SRv6 SID %pFX: interface %s does not exist", +				  &sid->addr, sid->attributes.ifname); +			return; +		} +		ctx.ifindex = ifp->ifindex; +		break;  	case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_END_X:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD: -	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:  	case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:  	case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: @@ -1244,6 +1286,9 @@ static int static_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)  			return 0;  		} +		if (!IPV6_ADDR_SAME(&ctx.nh6, &in6addr_any)) +			sid->attributes.nh6 = ctx.nh6; +  		SET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);  		/* diff --git a/tests/topotests/static_srv6_sids/expected_srv6_sids.json b/tests/topotests/static_srv6_sids/expected_srv6_sids.json index de78878445..1796c870a6 100644 --- a/tests/topotests/static_srv6_sids/expected_srv6_sids.json +++ b/tests/topotests/static_srv6_sids/expected_srv6_sids.json @@ -162,5 +162,40 @@  				}  			]  		} +	], +	"fcbb:bbbb:1:fe40::/64": [ +		{ +			"prefix": "fcbb:bbbb:1:fe40::/64", +			"prefixLen": 64, +			"protocol": "static", +			"vrfId": 0, +			"vrfName": "default", +			"selected": true, +			"destSelected": true, +			"distance": 1, +			"metric": 0, +			"installed": true, +			"table": 254, +			"internalStatus": 16, +			"internalFlags": 9, +			"internalNextHopNum": 1, +			"internalNextHopActiveNum": 1, +			"nexthops": [ +				{ +					"flags": 3, +					"fib": true, +					"directlyConnected": true, +					"interfaceName": "sr0", +					"active": true, +					"weight": 1, +					"seg6local": { +						"action": "End.X" +					}, +					"seg6localContext": { +						"nh6": "2001::2" +					} +				} +			] +		}  	]  }
\ No newline at end of file diff --git a/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_1.json b/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_1.json index dd0850fb3c..bd1f4bf87a 100644 --- a/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_1.json +++ b/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_1.json @@ -121,5 +121,40 @@  				}  			]  		} +	], +	"fcbb:bbbb:1:fe40::/64": [ +		{ +			"prefix": "fcbb:bbbb:1:fe40::/64", +			"prefixLen": 64, +			"protocol": "static", +			"vrfId": 0, +			"vrfName": "default", +			"selected": true, +			"destSelected": true, +			"distance": 1, +			"metric": 0, +			"installed": true, +			"table": 254, +			"internalStatus": 16, +			"internalFlags": 9, +			"internalNextHopNum": 1, +			"internalNextHopActiveNum": 1, +			"nexthops": [ +				{ +					"flags": 3, +					"fib": true, +					"directlyConnected": true, +					"interfaceName": "sr0", +					"active": true, +					"weight": 1, +					"seg6local": { +						"action": "End.X" +					}, +					"seg6localContext": { +						"nh6": "2001::2" +					} +				} +			] +		}  	]  }
\ No newline at end of file diff --git a/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_2.json b/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_2.json index 4051c01425..2bd40cdb5c 100644 --- a/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_2.json +++ b/tests/topotests/static_srv6_sids/expected_srv6_sids_sid_delete_2.json @@ -80,5 +80,40 @@  				}  			]  		} +	], +	"fcbb:bbbb:1:fe40::/64": [ +		{ +			"prefix": "fcbb:bbbb:1:fe40::/64", +			"prefixLen": 64, +			"protocol": "static", +			"vrfId": 0, +			"vrfName": "default", +			"selected": true, +			"destSelected": true, +			"distance": 1, +			"metric": 0, +			"installed": true, +			"table": 254, +			"internalStatus": 16, +			"internalFlags": 9, +			"internalNextHopNum": 1, +			"internalNextHopActiveNum": 1, +			"nexthops": [ +				{ +					"flags": 3, +					"fib": true, +					"directlyConnected": true, +					"interfaceName": "sr0", +					"active": true, +					"weight": 1, +					"seg6local": { +						"action": "End.X" +					}, +					"seg6localContext": { +						"nh6": "2001::2" +					} +				} +			] +		}  	]  }
\ No newline at end of file diff --git a/tests/topotests/static_srv6_sids/r1/frr.conf b/tests/topotests/static_srv6_sids/r1/frr.conf index b4904d9ac2..ce8fb88165 100644 --- a/tests/topotests/static_srv6_sids/r1/frr.conf +++ b/tests/topotests/static_srv6_sids/r1/frr.conf @@ -12,6 +12,7 @@ segment-routing     sid fcbb:bbbb:1:fe10::/64 locator MAIN behavior uDT4 vrf Vrf10     sid fcbb:bbbb:1:fe20::/64 locator MAIN behavior uDT6 vrf Vrf20     sid fcbb:bbbb:1:fe30::/64 locator MAIN behavior uDT46 vrf Vrf30 +   sid fcbb:bbbb:1:fe40::/64 locator MAIN behavior uA interface sr0 nexthop 2001::2    !   !  !
\ No newline at end of file diff --git a/yang/frr-staticd.yang b/yang/frr-staticd.yang index 8d0e58c0a5..3bf3a5e817 100644 --- a/yang/frr-staticd.yang +++ b/yang/frr-staticd.yang @@ -12,6 +12,10 @@ module frr-staticd {      prefix frr-nexthop;    } +  import frr-interface { +    prefix frr-interface; +  } +    import ietf-inet-types {      prefix inet;    } @@ -240,6 +244,24 @@ module frr-staticd {                  description                    "The VRF name.";                } +              list paths { +                key "path-index"; +                leaf path-index { +                  type uint8; +                  description +                    "Path index"; +                } +                leaf interface { +                  type frr-interface:interface-ref; +                  description +                    "Interface name."; +                } +                leaf next-hop { +                  type inet:ip-address; +                  description +                    "Nexthop IP address."; +                } +              }              }            }          } diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 6d228c5e24..51efcceb75 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -18,6 +18,7 @@  #include "zebra/zebra_srv6.h"  #include "zebra/zebra_errors.h"  #include "zebra/ge_netlink.h" +#include "zebra/interface.h"  #include <stdio.h>  #include <string.h> @@ -1745,6 +1746,13 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx,  	int ret = -1;  	struct srv6_locator *locator;  	char buf[256]; +	struct nhg_connected *rb_node_dep = NULL; +	struct listnode *node; +	struct nexthop *nexthop; +	struct nbr_connected *nc; +	bool found = false; +	struct interface *ifp; +	struct zebra_if *zebra_if;  	enum srv6_sid_alloc_mode alloc_mode =  		(sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT @@ -1755,6 +1763,44 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx,  			   __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx),  			   sid_value, srv6_sid_alloc_mode2str(alloc_mode)); +	if (ctx->ifindex != 0 && IPV6_ADDR_SAME(&ctx->nh6, &in6addr_any)) { +		ifp = if_lookup_by_index(ctx->ifindex, VRF_DEFAULT); +		if (!ifp) { +			zlog_err("%s: interface %u does not exist", __func__, ctx->ifindex); +			return -1; +		} + +		for (ALL_LIST_ELEMENTS_RO(ifp->nbr_connected, node, nc)) +			if (nc->address && nc->address->family == AF_INET6 && +			    IN6_IS_ADDR_LINKLOCAL(&nc->address->u.prefix6)) { +				ctx->nh6 = nc->address->u.prefix6; +				found = true; +				break; +			} + +		if (!found) { +			zebra_if = ifp->info; + +			frr_each (nhg_connected_tree, &zebra_if->nhg_dependents, rb_node_dep) { +				for (ALL_NEXTHOPS(rb_node_dep->nhe->nhg, nexthop)) { +					/* skip non link-local addresses */ +					if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &in6addr_any)) { +						ctx->nh6 = nexthop->gate.ipv6; +						found = true; +						break; +					} +				} +				if (found) +					break; +			} +			if (!found) { +				zlog_err("%s: cannot get SID, interface (ifindex %u) not found", +					 __func__, ctx->ifindex); +				return -1; +			} +		} +	} +  	if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) {  		/*  		 * Explicit SID allocation: allocate a specific SID value  | 
