diff --git a/doc/user/static.rst b/doc/user/static.rst index 0ce6e2107e7c..c1d11cf0b0e8 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 [vrf VRF] +.. clicmd:: sid X:X::X:X/M locator NAME behavior [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 3200aee70a8b..467f02a3c9e9 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 ef363bfe7e62..60dc3dc788c7 100644 --- a/staticd/static_nb.c +++ b/staticd/static_nb.c @@ -156,6 +156,27 @@ const struct frr_yang_module_info frr_staticd_info = { .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_destroy, } }, + { + .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 = { diff --git a/staticd/static_nb.h b/staticd/static_nb.h index aa11f340212b..282c9dcf11c5 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 e2ab1f2ffefe..71df15fa6123 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -1229,6 +1229,113 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routi 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 + */ +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 diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 5c19d238835a..6e9087363d1f 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 ", + "sid X:X::X:X/M locator NAME$locator_name behavior ", "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 ]", + "no sid X:X::X:X/M [locator NAME$locator_name] [behavior ]", 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 552dd3ee1f74..9a5e0efc4dc2 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -702,12 +702,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: @@ -830,12 +842,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: @@ -890,6 +910,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; @@ -940,13 +961,23 @@ extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid) ctx.vrf_id = vrf->vrf_id; } + 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: @@ -966,6 +997,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; @@ -1016,13 +1048,23 @@ extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid) ctx.vrf_id = vrf->vrf_id; } + 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: @@ -1240,6 +1282,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 de788784457b..1796c870a689 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 dd0850fb3c89..bd1f4bf87a74 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 4051c01425e6..2bd40cdb5c2c 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 b4904d9ac286..ce8fb8816519 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 8d0e58c0a5c3..3bf3a5e81764 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 6d228c5e24f3..51efcceb75a0 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 #include @@ -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