Merge pull request #16894 from wenwang00/project-phoenixwing-ysj

staticd: Add support for SRv6 Static SIDs
This commit is contained in:
Philippe Guibert 2025-01-20 09:20:15 +01:00 committed by GitHub
commit 084ebc9473
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 2010 additions and 17 deletions

View File

@ -176,3 +176,52 @@ multiple segments instructions.
router# show ipv6 route
[..]
S>* 2005::/64 [1/0] is directly connected, ens3, seg6 2001:db8:aaaa::7,2002::4,2002::3,2002::2, weight 1, 00:00:06
SRv6 Static SIDs Commands
=========================
.. clicmd:: segment-routing
Move from configure mode to segment-routing node.
.. clicmd:: srv6
Move from segment-routing node to srv6 node.
.. clicmd:: static-sids
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]
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
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.
::
router# configure terminal
router(config)# segment-routing
router(config-sr)# srv6
router(config-srv6)# static-sids
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-locator)# show run
...
segment-routing
srv6
static-sids
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
!
...

View File

@ -698,7 +698,7 @@ void isis_srv6_area_init(struct isis_area *area)
srv6db->config.max_end_pop_msd = ISIS_DEFAULT_SRV6_MAX_END_POP_MSD;
srv6db->config.max_h_encaps_msd = ISIS_DEFAULT_SRV6_MAX_H_ENCAPS_MSD;
srv6db->config.max_end_d_msd = ISIS_DEFAULT_SRV6_MAX_END_D_MSD;
strlcpy(srv6db->config.srv6_ifname, ISIS_DEFAULT_SRV6_IFNAME, sizeof(srv6db->config.srv6_ifname));
strlcpy(srv6db->config.srv6_ifname, DEFAULT_SRV6_IFNAME, sizeof(srv6db->config.srv6_ifname));
#endif
/* Initialize SRv6 Locator chunks list */

View File

@ -16,8 +16,7 @@
#define ISIS_DEFAULT_SRV6_MAX_SEG_LEFT_MSD 3
#define ISIS_DEFAULT_SRV6_MAX_END_POP_MSD 3
#define ISIS_DEFAULT_SRV6_MAX_H_ENCAPS_MSD 2
#define ISIS_DEFAULT_SRV6_MAX_END_D_MSD 5
#define ISIS_DEFAULT_SRV6_IFNAME "sr0"
#define ISIS_DEFAULT_SRV6_MAX_END_D_MSD 5
/* SRv6 SID structure */
struct isis_srv6_sid_structure {

View File

@ -154,6 +154,7 @@ enum node_type {
PCEP_PCE_NODE, /* PCE configuration node */
PCEP_PCC_NODE, /* PCC configuration node */
SRV6_NODE, /* SRv6 node */
SRV6_SIDS_NODE, /* SRv6 SIDs node */
SRV6_LOCS_NODE, /* SRv6 locators node */
SRV6_LOC_NODE, /* SRv6 locator node */
SRV6_ENCAP_NODE, /* SRv6 encapsulation node */

View File

@ -22,6 +22,8 @@
#define SRV6_SID_FORMAT_NAME_SIZE 512
#define DEFAULT_SRV6_IFNAME "sr0"
#ifdef __cplusplus
extern "C" {
#endif
@ -186,6 +188,42 @@ enum srv6_endpoint_behavior_codepoint {
SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF,
};
/*
* Convert SRv6 endpoint behavior codepoints to human-friendly string.
*/
static inline const char *
srv6_endpoint_behavior_codepoint2str(enum srv6_endpoint_behavior_codepoint behavior)
{
switch (behavior) {
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
return "Reserved";
case SRV6_ENDPOINT_BEHAVIOR_END:
return "End";
case SRV6_ENDPOINT_BEHAVIOR_END_X:
return "End.X";
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
return "End.DT6";
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
return "End.DT4";
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
return "End.DT46";
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
return "uN";
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
return "uA";
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
return "uDT6";
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
return "uDT4";
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
return "uDT46";
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
return "Opaque";
}
return "Unspec";
}
struct nexthop_srv6 {
/* SRv6 localsid info for Endpoint-behaviour */
enum seg6local_action_t seg6local_action;

View File

@ -22,6 +22,7 @@
struct debug static_dbg_events = {0, "debug static events", "Staticd events"};
struct debug static_dbg_route = {0, "debug static route", "Staticd route"};
struct debug static_dbg_bfd = {0, "debug static bfd", "Staticd bfd"};
struct debug static_dbg_srv6 = {0, "debug static srv6", "Staticd srv6"};
/* clang-format on */
/*
@ -37,8 +38,7 @@ struct debug static_dbg_bfd = {0, "debug static bfd", "Staticd bfd"};
* Debug general internal events
*
*/
void static_debug_set(int vtynode, bool onoff, bool events, bool route,
bool bfd)
void static_debug_set(int vtynode, bool onoff, bool events, bool route, bool bfd, bool srv6)
{
uint32_t mode = DEBUG_NODE2MODE(vtynode);
@ -50,6 +50,8 @@ void static_debug_set(int vtynode, bool onoff, bool events, bool route,
DEBUG_MODE_SET(&static_dbg_bfd, mode, onoff);
bfd_protocol_integration_set_debug(onoff);
}
if (srv6)
DEBUG_MODE_SET(&static_dbg_srv6, mode, onoff);
}
/*
@ -61,4 +63,5 @@ void static_debug_init(void)
debug_install(&static_dbg_events);
debug_install(&static_dbg_route);
debug_install(&static_dbg_bfd);
debug_install(&static_dbg_srv6);
}

View File

@ -20,6 +20,7 @@ extern "C" {
extern struct debug static_dbg_events;
extern struct debug static_dbg_route;
extern struct debug static_dbg_bfd;
extern struct debug static_dbg_srv6;
/*
* Initialize staticd debugging.
@ -41,8 +42,7 @@ void static_debug_init(void);
* Debug general internal events
*
*/
void static_debug_set(int vtynode, bool onoff, bool events, bool route,
bool bfd);
void static_debug_set(int vtynode, bool onoff, bool events, bool route, bool bfd, bool srv6);
#ifdef __cplusplus
}

View File

@ -26,6 +26,7 @@
#include "static_zebra.h"
#include "static_debug.h"
#include "static_nb.h"
#include "static_srv6.h"
#include "mgmt_be_client.h"
@ -76,6 +77,10 @@ static void sigint(void)
static_vrf_terminate();
static_zebra_stop();
/* clean up SRv6 data structures */
static_srv6_cleanup();
frr_fini();
exit(0);
@ -161,6 +166,9 @@ int main(int argc, char **argv, char **envp)
static_debug_init();
static_vrf_init();
/* initialize SRv6 data structures */
static_srv6_init();
static_zebra_init();
static_vty_init();

View File

@ -224,6 +224,35 @@ const struct frr_yang_module_info frr_staticd_info = {
.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid",
.cbs = {
.apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish,
.create = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create,
.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid/behavior",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify,
.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid/vrf-name",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_modify,
.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/locator-name",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify,
.destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy,
}
},
{
.xpath = NULL,
},

View File

@ -118,6 +118,34 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify(
struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_modify(
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_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(
struct nb_cb_destroy_args *args);
/* Optional 'apply_finish' callbacks. */
@ -125,6 +153,8 @@ void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_p
struct nb_cb_apply_finish_args *args);
void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish(
struct nb_cb_apply_finish_args *args);
void routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish(
struct nb_cb_apply_finish_args *args);
/* Optional 'pre_validate' callbacks. */
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate(
@ -206,6 +236,24 @@ int routing_control_plane_protocols_name_validate(
FRR_S_ROUTE_SRC_INFO_KEY_NO_DISTANCE_XPATH \
FRR_STATIC_ROUTE_NH_KEY_XPATH
/* srv6 */
#define FRR_STATIC_SRV6_INFO_KEY_XPATH \
"/frr-routing:routing/control-plane-protocols/" \
"control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \
"frr-staticd:staticd/segment-routing/srv6"
/* srv6/static-sids */
#define FRR_STATIC_SRV6_SID_KEY_XPATH \
FRR_STATIC_SRV6_INFO_KEY_XPATH \
"/static-sids/" \
"sid[sid='%s']"
#define FRR_STATIC_SRV6_SID_BEHAVIOR_XPATH "/behavior"
#define FRR_STATIC_SRV6_SID_VRF_NAME_XPATH "/vrf-name"
#define FRR_STATIC_SRV6_SID_LOCATOR_NAME_XPATH "/locator-name"
#ifdef __cplusplus
}
#endif

View File

@ -20,6 +20,9 @@
#include "static_nb.h"
#include "static_zebra.h"
#include "static_srv6.h"
#include "static_debug.h"
static int static_path_list_create(struct nb_cb_create_args *args)
{
@ -1367,3 +1370,222 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_create(
struct nb_cb_create_args *args)
{
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_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
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_create(
struct nb_cb_create_args *args)
{
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_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/static-sids
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_create(
struct nb_cb_create_args *args)
{
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_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
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create(
struct nb_cb_create_args *args)
{
struct static_srv6_sid *sid;
struct prefix_ipv6 sid_value;
if (args->event != NB_EV_APPLY)
return NB_OK;
yang_dnode_get_ipv6p(&sid_value, args->dnode, "sid");
sid = static_srv6_sid_alloc(&sid_value);
nb_running_set_entry(args->dnode, sid);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy(
struct nb_cb_destroy_args *args)
{
struct static_srv6_sid *sid;
if (args->event != NB_EV_APPLY)
return NB_OK;
sid = nb_running_unset_entry(args->dnode);
listnode_delete(srv6_sids, sid);
static_srv6_sid_del(sid);
return NB_OK;
}
void routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct static_srv6_sid *sid;
struct static_srv6_locator *locator;
sid = nb_running_get_entry(args->dnode, NULL, true);
locator = static_srv6_locator_lookup(sid->locator_name);
if (!locator) {
DEBUGD(&static_dbg_srv6,
"%s: Locator %s not found, trying to get locator information from zebra",
__func__, sid->locator_name);
static_zebra_srv6_manager_get_locator(sid->locator_name);
listnode_add(srv6_sids, sid);
return;
}
sid->locator = locator;
listnode_add(srv6_sids, sid);
static_zebra_request_srv6_sid(sid);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/behavior
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
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);
}
sid->behavior = yang_dnode_get_enum(args->dnode, "../behavior");
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_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_vrf_name_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
const char *vrf_name;
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);
}
vrf_name = yang_dnode_get_string(args->dnode, "../vrf-name");
snprintf(sid->attributes.vrf_name, sizeof(sid->attributes.vrf_name), "%s", vrf_name);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_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(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
const char *loc_name;
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);
}
loc_name = yang_dnode_get_string(args->dnode, "../locator-name");
snprintf(sid->locator_name, sizeof(sid->locator_name), "%s", loc_name);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}

174
staticd/static_srv6.c Normal file
View File

@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* STATICd - Segment Routing over IPv6 (SRv6) code
* Copyright (C) 2025 Alibaba Inc.
* Yuqing Zhao
* Lingyu Zhang
*/
#include <zebra.h>
#include "vrf.h"
#include "nexthop.h"
#include "static_routes.h"
#include "static_srv6.h"
#include "static_vrf.h"
#include "static_zebra.h"
#include "static_debug.h"
/*
* List of SRv6 SIDs.
*/
struct list *srv6_locators;
struct list *srv6_sids;
DEFINE_MTYPE_STATIC(STATIC, STATIC_SRV6_LOCATOR, "Static SRv6 locator");
DEFINE_MTYPE_STATIC(STATIC, STATIC_SRV6_SID, "Static SRv6 SID");
/*
* When an interface is enabled in the kernel, go through all the static SRv6 SIDs in
* the system that use this interface and install/remove them in the zebra RIB.
*
* ifp - The interface being enabled
* is_up - Whether the interface is up or down
*/
void static_ifp_srv6_sids_update(struct interface *ifp, bool is_up)
{
struct static_srv6_sid *sid;
struct listnode *node;
if (!srv6_sids || !ifp)
return;
DEBUGD(&static_dbg_srv6, "%s: Interface %s %s. %s SIDs that depend on the interface",
__func__, (is_up) ? "enabled" : "disabled", (is_up) ? "Removing" : "disabled",
ifp->name);
/*
* iterate over the list of SRv6 SIDs and remove the SIDs that use this
* VRF from the zebra RIB
*/
for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) {
if ((strcmp(sid->attributes.vrf_name, ifp->name) == 0) ||
(strncmp(ifp->name, DEFAULT_SRV6_IFNAME, sizeof(ifp->name)) == 0 &&
(sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END ||
sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID))) {
if (is_up) {
static_zebra_srv6_sid_install(sid);
SET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
} else {
static_zebra_srv6_sid_uninstall(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
}
}
}
/*
* Allocate an SRv6 SID object and initialize the fields common to all the
* behaviors (i.e., SID address and behavor).
*/
struct static_srv6_sid *static_srv6_sid_alloc(struct prefix_ipv6 *addr)
{
struct static_srv6_sid *sid = NULL;
sid = XCALLOC(MTYPE_STATIC_SRV6_SID, sizeof(struct static_srv6_sid));
sid->addr = *addr;
return sid;
}
void static_srv6_sid_free(struct static_srv6_sid *sid)
{
XFREE(MTYPE_STATIC_SRV6_SID, sid);
}
struct static_srv6_locator *static_srv6_locator_lookup(const char *name)
{
struct static_srv6_locator *locator;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(srv6_locators, node, locator))
if (!strncmp(name, locator->name, SRV6_LOCNAME_SIZE))
return locator;
return NULL;
}
/*
* Look-up an SRv6 SID in the list of SRv6 SIDs.
*/
struct static_srv6_sid *static_srv6_sid_lookup(struct prefix_ipv6 *sid_addr)
{
struct static_srv6_sid *sid;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid))
if (memcmp(&sid->addr, sid_addr, sizeof(struct prefix_ipv6)) == 0)
return sid;
return NULL;
}
struct static_srv6_locator *static_srv6_locator_alloc(const char *name)
{
struct static_srv6_locator *locator = NULL;
locator = XCALLOC(MTYPE_STATIC_SRV6_LOCATOR, sizeof(struct static_srv6_locator));
strlcpy(locator->name, name, sizeof(locator->name));
return locator;
}
void static_srv6_locator_free(struct static_srv6_locator *locator)
{
XFREE(MTYPE_STATIC_SRV6_LOCATOR, locator);
}
void delete_static_srv6_locator(void *val)
{
static_srv6_locator_free((struct static_srv6_locator *)val);
}
/*
* Remove an SRv6 SID from the zebra RIB (if it was previously installed) and
* release the memory previously allocated for the SID.
*/
void static_srv6_sid_del(struct static_srv6_sid *sid)
{
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);
}
XFREE(MTYPE_STATIC_SRV6_SID, sid);
}
void delete_static_srv6_sid(void *val)
{
static_srv6_sid_free((struct static_srv6_sid *)val);
}
/*
* Initialize SRv6 data structures.
*/
void static_srv6_init(void)
{
srv6_locators = list_new();
srv6_locators->del = delete_static_srv6_locator;
srv6_sids = list_new();
srv6_sids->del = delete_static_srv6_sid;
}
/*
* Clean up all the SRv6 data structures.
*/
void static_srv6_cleanup(void)
{
list_delete(&srv6_locators);
list_delete(&srv6_sids);
}

108
staticd/static_srv6.h Normal file
View File

@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* STATICd - Segment Routing over IPv6 (SRv6) header
* Copyright (C) 2025 Alibaba Inc.
* Yuqing Zhao
* Lingyu Zhang
*/
#ifndef __STATIC_SRV6_H__
#define __STATIC_SRV6_H__
#include "vrf.h"
#include "srv6.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Attributes for an SRv6 SID */
struct static_srv6_sid_attributes {
/* VRF name */
char vrf_name[VRF_NAMSIZ];
char ifname[IFNAMSIZ];
struct in6_addr nh6;
};
/* Static SRv6 SID */
struct static_srv6_sid {
/* SRv6 SID address */
struct prefix_ipv6 addr;
/* behavior bound to the SRv6 SID */
enum srv6_endpoint_behavior_codepoint behavior;
/* SID attributes */
struct static_srv6_sid_attributes attributes;
/* SRv6 SID flags */
uint8_t flags;
/*
* this SRv6 SID has been allocated by SID Manager
* and can be installed in the zebra RIB
*/
#define STATIC_FLAG_SRV6_SID_VALID (1 << 0)
/* this SRv6 SID has been installed in the zebra RIB */
#define STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA (1 << 1)
char locator_name[SRV6_LOCNAME_SIZE];
struct static_srv6_locator *locator;
};
struct static_srv6_locator {
char name[SRV6_LOCNAME_SIZE];
struct prefix_ipv6 prefix;
/*
* Bit length of SRv6 locator described in
* draft-ietf-bess-srv6-services-05#section-3.2.1
*/
uint8_t block_bits_length;
uint8_t node_bits_length;
uint8_t function_bits_length;
uint8_t argument_bits_length;
uint8_t flags;
};
/* List of SRv6 SIDs. */
extern struct list *srv6_locators;
extern struct list *srv6_sids;
/*
* Allocate an SRv6 SID object and initialize its fields, SID address and
* behavor.
*/
extern struct static_srv6_sid *static_srv6_sid_alloc(struct prefix_ipv6 *addr);
extern void static_srv6_sid_free(struct static_srv6_sid *sid);
/* Look-up an SRv6 SID in the list of SRv6 SIDs. */
extern struct static_srv6_sid *static_srv6_sid_lookup(struct prefix_ipv6 *sid_addr);
/*
* Remove an SRv6 SID from the zebra RIB (if it was previously installed) and
* release the memory previously allocated for the SID.
*/
extern void static_srv6_sid_del(struct static_srv6_sid *sid);
/* Initialize SRv6 data structures. */
extern void static_srv6_init(void);
/* Clean up all the SRv6 data structures. */
extern void static_srv6_cleanup(void);
/*
* When an interface is enabled in the kernel, go through all the static SRv6 SIDs in
* the system that use this interface and install/remove them in the zebra RIB.
*
* ifp - The interface being enabled
* is_up - Whether the interface is up or down
*/
void static_ifp_srv6_sids_update(struct interface *ifp, bool is_up);
struct static_srv6_locator *static_srv6_locator_alloc(const char *name);
void static_srv6_locator_free(struct static_srv6_locator *locator);
struct static_srv6_locator *static_srv6_locator_lookup(const char *name);
void delete_static_srv6_sid(void *val);
void delete_static_srv6_locator(void *val);
#ifdef __cplusplus
}
#endif
#endif /* __STATIC_SRV6_H__ */

View File

@ -27,6 +27,8 @@
#include "static_debug.h"
#include "staticd/static_vty_clippy.c"
#include "static_nb.h"
#include "static_srv6.h"
#include "static_zebra.h"
#define STATICD_STR "Static route daemon\n"
@ -1201,8 +1203,167 @@ DEFPY_YANG(ipv6_route_vrf, ipv6_route_vrf_cmd,
return static_route_nb_run(vty, &args);
}
DEFUN_NOSH (static_segment_routing, static_segment_routing_cmd,
"segment-routing",
"Segment Routing\n")
{
VTY_PUSH_CONTEXT_NULL(SEGMENT_ROUTING_NODE);
return CMD_SUCCESS;
}
DEFUN_NOSH (static_srv6, static_srv6_cmd,
"srv6",
"Segment Routing SRv6\n")
{
VTY_PUSH_CONTEXT_NULL(SRV6_NODE);
return CMD_SUCCESS;
}
DEFUN_YANG_NOSH (no_static_srv6, no_static_srv6_cmd,
"no srv6",
NO_STR
"Segment Routing SRv6\n")
{
char xpath[XPATH_MAXLEN];
snprintf(xpath, sizeof(xpath), FRR_STATIC_SRV6_INFO_KEY_XPATH, "frr-staticd:staticd",
"staticd", VRF_DEFAULT_NAME);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, "%s", xpath);
}
DEFUN_NOSH (static_srv6_sids, static_srv6_sids_cmd,
"static-sids",
"Segment Routing SRv6 SIDs\n")
{
VTY_PUSH_CONTEXT_NULL(SRV6_SIDS_NODE);
return CMD_SUCCESS;
}
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>",
"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"
"Apply the code to an uDT6 SID\n"
"Configure VRF name\n"
"Specify VRF name\n"
"Apply the code to an uDT4 SID\n"
"Configure VRF name\n"
"Specify VRF name\n"
"Apply the code to an uDT46 SID\n"
"Configure VRF name\n"
"Specify VRF name\n")
{
enum srv6_endpoint_behavior_codepoint behavior = SRV6_ENDPOINT_BEHAVIOR_RESERVED;
int idx = 0;
const char *vrf_name = NULL;
char xpath_srv6[XPATH_MAXLEN];
char xpath_sid[XPATH_MAXLEN];
char xpath_behavior[XPATH_MAXLEN];
char xpath_vrf_name[XPATH_MAXLEN];
char xpath_locator_name[XPATH_MAXLEN];
if (argv_find(argv, argc, "uN", &idx)) {
behavior = SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID;
} else if (argv_find(argv, argc, "uDT6", &idx)) {
behavior = SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID;
vrf_name = argv[idx + 2]->arg;
} else if (argv_find(argv, argc, "uDT4", &idx)) {
behavior = SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID;
vrf_name = argv[idx + 2]->arg;
} else if (argv_find(argv, argc, "uDT46", &idx)) {
behavior = SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID;
vrf_name = argv[idx + 2]->arg;
}
snprintf(xpath_srv6, sizeof(xpath_srv6), FRR_STATIC_SRV6_INFO_KEY_XPATH,
"frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME);
snprintf(xpath_sid, sizeof(xpath_sid), FRR_STATIC_SRV6_SID_KEY_XPATH, "frr-staticd:staticd",
"staticd", VRF_DEFAULT_NAME, sid_str);
strlcpy(xpath_behavior, xpath_sid, sizeof(xpath_behavior));
strlcat(xpath_behavior, FRR_STATIC_SRV6_SID_BEHAVIOR_XPATH, sizeof(xpath_behavior));
nb_cli_enqueue_change(vty, xpath_sid, NB_OP_CREATE, sid_str);
nb_cli_enqueue_change(vty, xpath_behavior, NB_OP_MODIFY,
srv6_endpoint_behavior_codepoint2str(behavior));
if (vrf_name) {
strlcpy(xpath_vrf_name, xpath_sid, sizeof(xpath_vrf_name));
strlcat(xpath_vrf_name, FRR_STATIC_SRV6_SID_VRF_NAME_XPATH, sizeof(xpath_vrf_name));
nb_cli_enqueue_change(vty, xpath_vrf_name, NB_OP_MODIFY, vrf_name);
}
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));
nb_cli_enqueue_change(vty, xpath_locator_name, NB_OP_MODIFY, locator_name);
return nb_cli_apply_changes(vty, "%s", xpath_sid);
}
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_STR
"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"
"Apply the code to an uDT6 SID\n"
"Configure VRF name\n"
"Specify VRF name\n"
"Apply the code to an uDT4 SID\n"
"Configure VRF name\n"
"Specify VRF name\n"
"Apply the code to an uDT46 SID\n"
"Configure VRF name\n"
"Specify VRF name\n")
{
char xpath[XPATH_MAXLEN + 37];
snprintf(xpath, sizeof(xpath), FRR_STATIC_SRV6_INFO_KEY_XPATH, "frr-staticd:staticd",
"staticd", VRF_DEFAULT_NAME);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
#ifdef INCLUDE_MGMTD_CMDDEFS_ONLY
static struct cmd_node sr_node = {
.name = "sr",
.node = SEGMENT_ROUTING_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-sr)# ",
};
static struct cmd_node srv6_node = {
.name = "srv6",
.node = SRV6_NODE,
.parent_node = SEGMENT_ROUTING_NODE,
.prompt = "%s(config-srv6)# ",
};
static struct cmd_node srv6_sids_node = {
.name = "srv6-sids",
.node = SRV6_SIDS_NODE,
.parent_node = SRV6_NODE,
.prompt = "%s(config-srv6-sids)# ",
};
static void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
@ -1545,6 +1706,100 @@ static int static_path_list_cli_cmp(const struct lyd_node *dnode1,
return (int)distance1 - (int)distance2;
}
static void static_segment_routing_cli_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, "segment-routing\n");
}
static void static_segment_routing_cli_show_end(struct vty *vty, const struct lyd_node *dnode)
{
vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
static void static_srv6_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults)
{
vty_out(vty, " srv6\n");
}
static void static_srv6_cli_show_end(struct vty *vty, const struct lyd_node *dnode)
{
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
}
static void static_sids_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults)
{
vty_out(vty, " static-sids\n");
}
static void static_sids_cli_show_end(struct vty *vty, const struct lyd_node *dnode)
{
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
}
static void srv6_sid_cli_show(struct vty *vty, const struct lyd_node *sid, bool show_defaults)
{
enum srv6_endpoint_behavior_codepoint srv6_behavior;
struct prefix_ipv6 sid_value;
yang_dnode_get_ipv6p(&sid_value, sid, "sid");
vty_out(vty, " sid %pFX", &sid_value);
vty_out(vty, " locator %s", yang_dnode_get_string(sid, "locator-name"));
srv6_behavior = yang_dnode_get_enum(sid, "behavior");
switch (srv6_behavior) {
case SRV6_ENDPOINT_BEHAVIOR_END:
vty_out(vty, " behavior End");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_X:
vty_out(vty, " behavior End.X");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
vty_out(vty, " behavior End.DT6");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
vty_out(vty, " behavior End.DT4");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
vty_out(vty, " behavior End.DT46");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
vty_out(vty, " behavior uN");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
vty_out(vty, " behavior uA");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
vty_out(vty, " behavior uDT6");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
vty_out(vty, " behavior uDT4");
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
vty_out(vty, " behavior uDT46");
break;
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
vty_out(vty, " behavior unknown");
break;
}
if (yang_dnode_exists(sid, "vrf-name"))
vty_out(vty, " vrf %s", yang_dnode_get_string(sid, "vrf-name"));
vty_out(vty, "\n");
}
static void static_srv6_sid_cli_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
srv6_sid_cli_show(vty, dnode, show_defaults);
}
const struct frr_yang_module_info frr_staticd_cli_info = {
.name = "frr-staticd",
.ignore_cfg_cbs = true,
@ -1594,6 +1849,33 @@ const struct frr_yang_module_info frr_staticd_cli_info = {
.cli_cmp = static_nexthop_cli_cmp,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing",
.cbs = {
.cli_show = static_segment_routing_cli_show,
.cli_show_end = static_segment_routing_cli_show_end,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6",
.cbs = {
.cli_show = static_srv6_cli_show,
.cli_show_end = static_srv6_cli_show_end,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids",
.cbs = {
.cli_show = static_sids_cli_show,
.cli_show_end = static_sids_cli_show_end,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids/sid",
.cbs = {
.cli_show = static_srv6_sid_cli_show,
}
},
{
.xpath = NULL,
},
@ -1603,17 +1885,18 @@ const struct frr_yang_module_info frr_staticd_cli_info = {
#else /* ifdef INCLUDE_MGMTD_CMDDEFS_ONLY */
DEFPY_YANG(debug_staticd, debug_staticd_cmd,
"[no] debug static [{events$events|route$route|bfd$bfd}]",
"[no] debug static [{events$events|route$route|bfd$bfd|srv6$srv6}]",
NO_STR DEBUG_STR STATICD_STR
"Debug events\n"
"Debug route\n"
"Debug bfd\n")
"Debug bfd\n"
"Debug srv6\n")
{
/* If no specific category, change all */
if (strmatch(argv[argc - 1]->text, "static"))
static_debug_set(vty->node, !no, true, true, true);
static_debug_set(vty->node, !no, true, true, true, true);
else
static_debug_set(vty->node, !no, !!events, !!route, !!bfd);
static_debug_set(vty->node, !no, !!events, !!route, !!bfd, !!srv6);
return CMD_SUCCESS;
}
@ -1669,6 +1952,21 @@ void static_vty_init(void)
install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
install_element(CONFIG_NODE, &ipv6_route_cmd);
install_element(VRF_NODE, &ipv6_route_vrf_cmd);
install_node(&sr_node);
install_node(&srv6_node);
install_node(&srv6_sids_node);
install_default(SEGMENT_ROUTING_NODE);
install_default(SRV6_NODE);
install_default(SRV6_SIDS_NODE);
install_element(CONFIG_NODE, &static_segment_routing_cmd);
install_element(SEGMENT_ROUTING_NODE, &static_srv6_cmd);
install_element(SEGMENT_ROUTING_NODE, &no_static_srv6_cmd);
install_element(SRV6_NODE, &static_srv6_sids_cmd);
install_element(SRV6_SIDS_NODE, &srv6_sid_cmd);
install_element(SRV6_SIDS_NODE, &no_srv6_sid_cmd);
#endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
#ifndef INCLUDE_MGMTD_CMDDEFS_ONLY

View File

@ -30,6 +30,9 @@
#include "static_nht.h"
#include "static_vty.h"
#include "static_debug.h"
#include "zclient.h"
#include "static_srv6.h"
#include "lib_errors.h"
DEFINE_MTYPE_STATIC(STATIC, STATIC_NHT_DATA, "Static Nexthop tracking data");
PREDECL_HASH(static_nht_hash);
@ -113,6 +116,8 @@ static int static_ifp_up(struct interface *ifp)
{
static_ifindex_update(ifp, true);
static_ifp_srv6_sids_update(ifp, true);
return 0;
}
@ -120,6 +125,8 @@ static int static_ifp_down(struct interface *ifp)
{
static_ifindex_update(ifp, false);
static_ifp_srv6_sids_update(ifp, false);
return 0;
}
@ -530,10 +537,660 @@ extern void static_zebra_route_add(struct static_path *pn, bool install)
zclient, &api);
}
/**
* Send SRv6 SID to ZEBRA for installation or deletion.
*
* @param cmd ZEBRA_ROUTE_ADD or ZEBRA_ROUTE_DELETE
* @param sid SRv6 SID to install or delete
* @param prefixlen Prefix length
* @param oif Outgoing interface
* @param action SID action
* @param context SID context
*/
static void static_zebra_send_localsid(int cmd, const struct in6_addr *sid, uint16_t prefixlen,
ifindex_t oif, enum seg6local_action_t action,
const struct seg6local_context *context)
{
struct prefix_ipv6 p = {};
struct zapi_route api = {};
struct zapi_nexthop *znh;
if (cmd != ZEBRA_ROUTE_ADD && cmd != ZEBRA_ROUTE_DELETE) {
flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command", __func__);
return;
}
if (prefixlen > IPV6_MAX_BITLEN) {
flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong prefixlen %u", __func__, prefixlen);
return;
}
DEBUGD(&static_dbg_srv6, "%s: |- %s SRv6 SID %pI6 behavior %s", __func__,
cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete", sid, seg6local_action2str(action));
p.family = AF_INET6;
p.prefixlen = prefixlen;
p.prefix = *sid;
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_STATIC;
api.instance = 0;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, &p, sizeof(p));
if (cmd == ZEBRA_ROUTE_DELETE)
return (void)zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
znh = &api.nexthops[0];
memset(znh, 0, sizeof(*znh));
znh->type = NEXTHOP_TYPE_IFINDEX;
znh->ifindex = oif;
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL);
znh->seg6local_action = action;
memcpy(&znh->seg6local_ctx, context, sizeof(struct seg6local_context));
api.nexthop_num = 1;
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
/**
* Install SRv6 SID in the forwarding plane through Zebra.
*
* @param sid SRv6 SID
*/
void static_zebra_srv6_sid_install(struct static_srv6_sid *sid)
{
enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
struct seg6local_context ctx = {};
struct interface *ifp = NULL;
struct vrf *vrf;
if (!sid)
return;
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA))
return;
if (!sid->locator) {
zlog_err("Failed to install SID %pFX: missing locator information", &sid->addr);
return;
}
switch (sid->behavior) {
case SRV6_ENDPOINT_BEHAVIOR_END:
action = ZEBRA_SEG6_LOCAL_ACTION_END;
break;
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
action = ZEBRA_SEG6_LOCAL_ACTION_END;
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_DT6:
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf)) {
zlog_warn("Failed to install SID %pFX: VRF %s is inactive", &sid->addr,
sid->attributes.vrf_name);
return;
}
ctx.table = vrf->data.l.table_id;
ifp = if_get_vrf_loopback(vrf->vrf_id);
if (!ifp) {
zlog_warn("Failed to install SID %pFX: failed to get loopback for vrf %s",
&sid->addr, sid->attributes.vrf_name);
return;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4;
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf)) {
zlog_warn("Failed to install SID %pFX: VRF %s is inactive", &sid->addr,
sid->attributes.vrf_name);
return;
}
ctx.table = vrf->data.l.table_id;
ifp = if_get_vrf_loopback(vrf->vrf_id);
if (!ifp) {
zlog_warn("Failed to install SID %pFX: failed to get loopback for vrf %s",
&sid->addr, sid->attributes.vrf_name);
return;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
action = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf)) {
zlog_warn("Failed to install SID %pFX: VRF %s is inactive", &sid->addr,
sid->attributes.vrf_name);
return;
}
ctx.table = vrf->data.l.table_id;
ifp = if_get_vrf_loopback(vrf->vrf_id);
if (!ifp) {
zlog_warn("Failed to install SID %pFX: failed to get loopback for vrf %s",
&sid->addr, sid->attributes.vrf_name);
return;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_X:
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
zlog_warn("unsupported behavior: %u", sid->behavior);
break;
}
ctx.block_len = sid->locator->block_bits_length;
ctx.node_len = sid->locator->node_bits_length;
ctx.function_len = sid->locator->function_bits_length;
ctx.argument_len = sid->locator->argument_bits_length;
/* Attach the SID to the SRv6 interface */
if (!ifp) {
ifp = if_lookup_by_name(DEFAULT_SRV6_IFNAME, VRF_DEFAULT);
if (!ifp) {
zlog_warn("Failed to install SRv6 SID %pFX: %s interface not found",
&sid->addr, DEFAULT_SRV6_IFNAME);
return;
}
}
/* Send the SID to zebra */
static_zebra_send_localsid(ZEBRA_ROUTE_ADD, &sid->addr.prefix, sid->addr.prefixlen,
ifp->ifindex, action, &ctx);
SET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
void static_zebra_srv6_sid_uninstall(struct static_srv6_sid *sid)
{
enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
struct interface *ifp = NULL;
struct seg6local_context ctx = {};
struct vrf *vrf;
if (!sid)
return;
if (!CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA))
return;
if (!sid->locator) {
zlog_err("Failed to uninstall SID %pFX: missing locator information", &sid->addr);
return;
}
switch (sid->behavior) {
case SRV6_ENDPOINT_BEHAVIOR_END:
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf)) {
zlog_warn("Failed to install SID %pFX: VRF %s is inactive", &sid->addr,
sid->attributes.vrf_name);
return;
}
ifp = if_get_vrf_loopback(vrf->vrf_id);
if (!ifp) {
zlog_warn("Failed to install SID %pFX: failed to get loopback for vrf %s",
&sid->addr, sid->attributes.vrf_name);
return;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf)) {
zlog_warn("Failed to install SID %pFX: VRF %s is inactive", &sid->addr,
sid->attributes.vrf_name);
return;
}
ifp = if_get_vrf_loopback(vrf->vrf_id);
if (!ifp) {
zlog_warn("Failed to install SID %pFX: failed to get loopback for vrf %s",
&sid->addr, sid->attributes.vrf_name);
return;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf)) {
zlog_warn("Failed to install SID %pFX: VRF %s is inactive", &sid->addr,
sid->attributes.vrf_name);
return;
}
ifp = if_get_vrf_loopback(vrf->vrf_id);
if (!ifp) {
zlog_warn("Failed to install SID %pFX: failed to get loopback for vrf %s",
&sid->addr, sid->attributes.vrf_name);
return;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_X:
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
zlog_warn("unsupported behavior: %u", sid->behavior);
break;
}
/* The SID is attached to the SRv6 interface */
if (!ifp) {
ifp = if_lookup_by_name(DEFAULT_SRV6_IFNAME, VRF_DEFAULT);
if (!ifp) {
zlog_warn("%s interface not found: nothing to uninstall",
DEFAULT_SRV6_IFNAME);
return;
}
}
ctx.block_len = sid->locator->block_bits_length;
ctx.node_len = sid->locator->node_bits_length;
ctx.function_len = sid->locator->function_bits_length;
ctx.argument_len = sid->locator->argument_bits_length;
static_zebra_send_localsid(ZEBRA_ROUTE_DELETE, &sid->addr.prefix, sid->addr.prefixlen,
ifp->ifindex, action, &ctx);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid)
{
struct srv6_sid_ctx ctx = {};
int ret = 0;
struct vrf *vrf;
if (!sid)
return;
/* convert `srv6_endpoint_behavior_codepoint` to `seg6local_action_t` */
switch (sid->behavior) {
case SRV6_ENDPOINT_BEHAVIOR_END:
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END;
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
/* process SRv6 SID attributes */
/* generate table ID from the VRF name, if configured */
if (sid->attributes.vrf_name[0] != '\0') {
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf))
return;
ctx.vrf_id = vrf->vrf_id;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT4;
/* process SRv6 SID attributes */
/* generate table ID from the VRF name, if configured */
if (sid->attributes.vrf_name[0] != '\0') {
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf))
return;
ctx.vrf_id = vrf->vrf_id;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
/* process SRv6 SID attributes */
/* generate table ID from the VRF name, if configured */
if (sid->attributes.vrf_name[0] != '\0') {
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf))
return;
ctx.vrf_id = vrf->vrf_id;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_X:
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
zlog_warn("unsupported behavior: %u", sid->behavior);
return;
}
/* Request SRv6 SID from SID Manager */
ret = srv6_manager_get_sid(zclient, &ctx, &sid->addr.prefix, sid->locator->name, NULL);
if (ret < 0)
zlog_warn("%s: error getting SRv6 SID!", __func__);
}
extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid)
{
struct srv6_sid_ctx ctx = {};
struct vrf *vrf;
int ret = 0;
if (!sid || !CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID))
return;
/* convert `srv6_endpoint_behavior_codepoint` to `seg6local_action_t` */
switch (sid->behavior) {
case SRV6_ENDPOINT_BEHAVIOR_END:
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END;
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
/* process SRv6 SID attributes */
/* generate table ID from the VRF name, if configured */
if (sid->attributes.vrf_name[0] != '\0') {
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf))
return;
ctx.vrf_id = vrf->vrf_id;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT4;
/* process SRv6 SID attributes */
/* generate table ID from the VRF name, if configured */
if (sid->attributes.vrf_name[0] != '\0') {
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf))
return;
ctx.vrf_id = vrf->vrf_id;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
/* process SRv6 SID attributes */
/* generate table ID from the VRF name, if configured */
if (sid->attributes.vrf_name[0] != '\0') {
vrf = vrf_lookup_by_name(sid->attributes.vrf_name);
if (!vrf_is_enabled(vrf))
return;
ctx.vrf_id = vrf->vrf_id;
}
break;
case SRV6_ENDPOINT_BEHAVIOR_END_X:
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
zlog_warn("unsupported behavior: %u", sid->behavior);
return;
}
/* remove the SRv6 SID from the zebra RIB */
ret = srv6_manager_release_sid(zclient, &ctx);
if (ret == ZCLIENT_SEND_FAILURE)
flog_err(EC_LIB_ZAPI_SOCKET, "zclient_send_get_srv6_sid() delete failed: %s",
safe_strerror(errno));
}
/**
* Ask the SRv6 Manager (zebra) about a specific locator
*
* @param name Locator name
* @return 0 on success, -1 otherwise
*/
int static_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);
}
static void request_srv6_sids(struct static_srv6_locator *locator)
{
struct static_srv6_sid *sid;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) {
if (sid->locator == locator)
static_zebra_request_srv6_sid(sid);
}
}
/**
* Internal function to process an SRv6 locator
*
* @param locator The locator to be processed
*/
static int static_zebra_process_srv6_locator_internal(struct srv6_locator *locator)
{
struct static_srv6_locator *loc;
struct listnode *node;
struct static_srv6_sid *sid;
if (!locator)
return -1;
DEBUGD(&static_dbg_srv6,
"%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);
/* If we are already aware about the locator, nothing to do */
loc = static_srv6_locator_lookup(locator->name);
if (loc)
return 0;
loc = static_srv6_locator_alloc(locator->name);
DEBUGD(&static_dbg_srv6, "%s: SRv6 locator (locator %s, prefix %pFX) set", __func__,
locator->name, &locator->prefix);
/* Store the locator prefix */
loc->prefix = locator->prefix;
loc->block_bits_length = locator->block_bits_length;
loc->node_bits_length = locator->node_bits_length;
loc->function_bits_length = locator->function_bits_length;
loc->argument_bits_length = locator->argument_bits_length;
loc->flags = locator->flags;
listnode_add(srv6_locators, loc);
for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) {
if (strncmp(sid->locator_name, loc->name, sizeof(loc->name)) == 0)
sid->locator = loc;
}
/* Request SIDs from the locator */
request_srv6_sids(loc);
return 0;
}
/**
* Callback to process an SRv6 locator received from SRv6 Manager (zebra).
*
* @result 0 on success, -1 otherwise
*/
static int static_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
{
struct srv6_locator loc = {};
if (!srv6_locators)
return -1;
/* Decode the SRv6 locator */
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
return static_zebra_process_srv6_locator_internal(&loc);
}
/**
* Callback to process a notification from SRv6 Manager (zebra) of an SRv6
* locator deleted.
*
* @result 0 on success, -1 otherwise
*/
static int static_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
{
struct srv6_locator loc = {};
struct listnode *node2, *nnode2;
struct static_srv6_sid *sid;
struct static_srv6_locator *locator;
if (!srv6_locators)
return -1;
/* Decode the received zebra message */
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
DEBUGD(&static_dbg_srv6,
"%s: SRv6 locator deleted in zebra: name %s, prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u",
__func__, loc.name, &loc.prefix, loc.block_bits_length, loc.node_bits_length,
loc.function_bits_length, loc.argument_bits_length);
locator = static_srv6_locator_lookup(loc.name);
if (!locator)
return 0;
DEBUGD(&static_dbg_srv6, "%s: Deleting srv6 sids from locator %s", __func__, locator->name);
/* Delete SRv6 SIDs */
for (ALL_LIST_ELEMENTS(srv6_sids, node2, nnode2, sid)) {
if (sid->locator != locator)
continue;
DEBUGD(&static_dbg_srv6, "%s: Deleting SRv6 SID (locator %s, sid %pFX)", __func__,
locator->name, &sid->addr);
/*
* Uninstall the SRv6 SID from the forwarding plane
* through Zebra
*/
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);
}
}
listnode_delete(srv6_locators, locator);
static_srv6_locator_free(locator);
return 0;
}
static int static_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
{
struct srv6_sid_ctx ctx;
struct in6_addr sid_addr;
enum zapi_srv6_sid_notify note;
uint32_t sid_func;
struct listnode *node;
char buf[256];
struct static_srv6_sid *sid = NULL;
char *loc_name;
bool found = false;
if (!srv6_locators)
return -1;
/* Decode the received notification message */
if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, &sid_func, NULL, &note,
&loc_name)) {
zlog_err("%s : error in msg decode", __func__);
return -1;
}
DEBUGD(&static_dbg_srv6,
"%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));
/* Handle notification */
switch (note) {
case ZAPI_SRV6_SID_ALLOCATED:
DEBUGD(&static_dbg_srv6, "%s: SRv6 SID %pI6 %s ALLOCATED", __func__, &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) {
if (IPV6_ADDR_SAME(&sid->addr.prefix, &sid_addr)) {
found = true;
break;
}
}
if (!found || !sid) {
zlog_err("SRv6 SID %pI6 %s: not found", &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
return 0;
}
SET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
/*
* Install the new SRv6 End SID in the forwarding plane through
* Zebra
*/
static_zebra_srv6_sid_install(sid);
SET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
break;
case ZAPI_SRV6_SID_RELEASED:
DEBUGD(&static_dbg_srv6, "%s: SRv6 SID %pI6 %s: RELEASED", __func__, &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
break;
case ZAPI_SRV6_SID_FAIL_ALLOC:
zlog_err("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_err("%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;
}
return 0;
}
static zclient_handler *const static_handlers[] = {
[ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
[ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
[ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner,
[ZEBRA_SRV6_LOCATOR_ADD] = static_zebra_process_srv6_locator_add,
[ZEBRA_SRV6_LOCATOR_DELETE] = static_zebra_process_srv6_locator_delete,
[ZEBRA_SRV6_SID_NOTIFY] = static_zebra_srv6_sid_notify,
};
void static_zebra_init(void)

View File

@ -7,6 +7,8 @@
#ifndef __STATIC_ZEBRA_H__
#define __STATIC_ZEBRA_H__
#include "static_srv6.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -22,6 +24,14 @@ extern void static_zebra_stop(void);
extern void static_zebra_vrf_register(struct vrf *vrf);
extern void static_zebra_vrf_unregister(struct vrf *vrf);
extern int static_zebra_srv6_manager_get_locator(const char *name);
extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid);
extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid);
extern void static_zebra_srv6_sid_install(struct static_srv6_sid *sid);
extern void static_zebra_srv6_sid_uninstall(struct static_srv6_sid *sid);
#ifdef __cplusplus
}
#endif

View File

@ -19,6 +19,7 @@ staticd_libstatic_a_SOURCES = \
staticd/static_vty.c \
staticd/static_nb.c \
staticd/static_nb_config.c \
staticd/static_srv6.c \
# end
noinst_HEADERS += \
@ -29,6 +30,7 @@ noinst_HEADERS += \
staticd/static_vty.h \
staticd/static_vrf.h \
staticd/static_nb.h \
staticd/static_srv6.h \
# end
clippy_scan += \

View File

@ -0,0 +1,107 @@
{
"fcbb:bbbb:1:fe10::/64": [
{
"prefix": "fcbb:bbbb:1:fe10::/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": "Vrf10",
"active": true,
"weight": 1,
"seg6local": {
"action": "End.DT4"
},
"seg6localContext": {
"table": 10
}
}
]
}
],
"fcbb:bbbb:1:fe20::/64": [
{
"prefix": "fcbb:bbbb:1:fe20::/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": "Vrf20",
"active": true,
"weight": 1,
"seg6local": {
"action": "End.DT6"
},
"seg6localContext": {
"table": 20
}
}
]
}
],
"fcbb:bbbb:1:fe30::/64": [
{
"prefix": "fcbb:bbbb:1:fe30::/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": "Vrf30",
"active": true,
"weight": 1,
"seg6local": {
"action": "End.DT46"
},
"seg6localContext": {
"table": 30
}
}
]
}
]
}

View File

@ -0,0 +1,16 @@
hostname r1
!
segment-routing
srv6
locators
locator MAIN
prefix fcbb:bbbb:1::/48 block-len 32 node-len 16 func-bits 16
!
!
static-sids
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
!
!
!

View File

@ -0,0 +1,13 @@
ip link add sr0 type dummy
ip link set sr0 up
ip link add Vrf10 type vrf table 10
ip link set Vrf10 up
ip link add Vrf20 type vrf table 20
ip link set Vrf20 up
ip link add Vrf30 type vrf table 30
ip link set Vrf30 up
sysctl -w net.vrf.strict_mode=1

View File

@ -0,0 +1,83 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
#
# test_static_srv6_sids.py
#
# Copyright (c) 2025 by
# Alibaba Inc, Yuqing Zhao <galadriel.zyq@alibaba-inc.com>
# Lingyu Zhang <hanyu.zly@alibaba-inc.com>
#
"""
test_static_srv6_sids.py:
Test for SRv6 static route on zebra
"""
import os
import sys
import json
import pytest
import functools
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
pytestmark = [pytest.mark.staticd]
def open_json_file(filename):
try:
with open(filename, "r") as f:
return json.load(f)
except IOError:
assert False, "Could not read file {}".format(filename)
def setup_module(mod):
tgen = Topogen({None: "r1"}, mod.__name__)
tgen.start_topology()
for rname, router in tgen.routers().items():
router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
router.load_frr_config("frr.conf")
tgen.start_router()
def teardown_module():
tgen = get_topogen()
tgen.stop_topology()
def test_srv6_static_sids():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
router = tgen.gears["r1"]
def _check_srv6_static_sids(router, expected_route_file):
logger.info("checking zebra srv6 static sids")
output = json.loads(router.vtysh_cmd("show ipv6 route static json"))
expected = open_json_file("{}/{}".format(CWD, expected_route_file))
return topotest.json_cmp(output, expected)
def check_srv6_static_sids(router, expected_file):
func = functools.partial(_check_srv6_static_sids, router, expected_file)
_, result = topotest.run_and_expect(func, None, count=15, wait=1)
assert result is None, "Failed"
# FOR DEVELOPER:
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
logger.info("Test for srv6 sids configuration")
check_srv6_static_sids(router, "expected_srv6_sids.json")
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -1312,6 +1312,13 @@ static struct cmd_node srv6_node = {
.prompt = "%s(config-srv6)# ",
};
static struct cmd_node srv6_sids_node = {
.name = "srv6-sids",
.node = SRV6_SIDS_NODE,
.parent_node = SRV6_NODE,
.prompt = "%s(config-srv6-sids)# ",
};
static struct cmd_node srv6_locs_node = {
.name = "srv6-locators",
.node = SRV6_LOCS_NODE,
@ -1685,7 +1692,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end",
return vtysh_end();
}
DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd,
DEFUNSH(VTYSH_ZEBRA | VTYSH_MGMTD, srv6, srv6_cmd,
"srv6",
"Segment-Routing SRv6 configuration\n")
{
@ -1693,6 +1700,14 @@ DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd,
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_MGMTD, srv6_sids, srv6_sids_cmd,
"static-sids",
"Segment-Routing SRv6 SIDs configuration\n")
{
vty->node = SRV6_SIDS_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_ZEBRA, srv6_locators, srv6_locators_cmd,
"locators",
"Segment-Routing SRv6 locators configuration\n")
@ -2216,7 +2231,7 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab
}
#endif /* HAVE_FABRICD */
DEFUNSH(VTYSH_SR, segment_routing, segment_routing_cmd,
DEFUNSH(VTYSH_SR | VTYSH_MGMTD, segment_routing, segment_routing_cmd,
"segment-routing",
"Configure segment routing\n")
{
@ -2535,7 +2550,7 @@ DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_ZEBRA, exit_srv6_config, exit_srv6_config_cmd, "exit",
DEFUNSH(VTYSH_ZEBRA | VTYSH_MGMTD, exit_srv6_config, exit_srv6_config_cmd, "exit",
"Exit from SRv6 configuration mode\n")
{
if (vty->node == SRV6_NODE)
@ -2551,6 +2566,14 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_locs_config, exit_srv6_locs_config_cmd, "exit",
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_MGMTD, exit_srv6_sids_config, exit_srv6_sids_config_cmd, "exit",
"Exit from SRv6-SIDs configuration mode\n")
{
if (vty->node == SRV6_SIDS_NODE)
vty->node = SRV6_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_ZEBRA, exit_srv6_loc_config, exit_srv6_loc_config_cmd, "exit",
"Exit from SRv6-locators configuration mode\n")
{
@ -2806,13 +2829,13 @@ DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
return vtysh_exit_keys(self, vty, argc, argv);
}
DEFUNSH(VTYSH_SR, vtysh_exit_sr, vtysh_exit_sr_cmd, "exit",
DEFUNSH(VTYSH_SR | VTYSH_MGMTD, vtysh_exit_sr, vtysh_exit_sr_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit(vty);
}
DEFUNSH(VTYSH_SR, vtysh_quit_sr, vtysh_quit_sr_cmd, "quit",
DEFUNSH(VTYSH_SR | VTYSH_MGMTD, vtysh_quit_sr, vtysh_quit_sr_cmd, "quit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit(vty);
@ -4999,6 +5022,7 @@ void vtysh_init_vty(void)
install_node(&rmap_node);
install_node(&vty_node);
install_node(&srv6_node);
install_node(&srv6_sids_node);
install_node(&srv6_locs_node);
install_node(&srv6_loc_node);
install_node(&srv6_encap_node);
@ -5442,6 +5466,10 @@ void vtysh_init_vty(void)
install_element(SRV6_NODE, &exit_srv6_config_cmd);
install_element(SRV6_NODE, &vtysh_end_all_cmd);
install_element(SRV6_NODE, &srv6_encap_cmd);
install_element(SRV6_NODE, &srv6_sids_cmd);
install_element(SRV6_SIDS_NODE, &exit_srv6_sids_config_cmd);
install_element(SRV6_SIDS_NODE, &vtysh_end_all_cmd);
install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd);

View File

@ -20,6 +20,10 @@ module frr-staticd {
prefix frr-bfdd;
}
import frr-vrf {
prefix frr-vrf;
}
organization
"FRRouting";
contact
@ -92,6 +96,64 @@ module frr-staticd {
}
}
typedef srv6-behavior-codepoint {
description
"SRv6 Endpoint Behaviors Codepoints as per
https://www.iana.org/assignments/segment-routing/segment-routing.xhtml.";
type enumeration {
enum End {
value 1;
description
"This enum indicates End endpoint behavior.";
}
enum End.X {
value 5;
description
"This enum indicates End.X endpoint behavior.";
}
enum End.DT6 {
value 18;
description
"This enum indicates End.DT6 endpoint behavior.";
}
enum End.DT4 {
value 19;
description
"This enum indicates End.DT4 endpoint behavior.";
}
enum End.DT46 {
value 20;
description
"This enum indicates End.DT46 endpoint behavior.";
}
enum uN {
value 43;
description
"This enum indicates End with NEXT-CSID endpoint behavior.";
}
enum uA {
value 52;
description
"This enum indicates End.X with NEXT-CSID endpoint behavior.";
}
enum uDT6 {
value 62;
description
"This enum indicates End.DT6 with NEXT-CSID endpoint behavior.";
}
enum uDT4 {
value 63;
description
"This enum indicates End.DT4 with NEXT-CSID endpoint behavior.";
}
enum uDT46 {
value 64;
description
"This enum indicates End.DT46 with NEXT-CSID endpoint behavior.";
}
}
}
augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol" {
container staticd {
when "../frr-rt:type = 'frr-staticd:staticd'" {
@ -144,6 +206,44 @@ module frr-staticd {
uses staticd-prefix-attributes;
}
}
container segment-routing {
description
"Segment Routing configuration.";
container srv6 {
description
"Segment Routing over IPv6 (SRv6) configuration.";
container static-sids {
description
"This container lists the SRv6 Static SIDs instantiated on the local node.";
list sid {
description
"List of SRv6 Static SIDs.";
key "sid";
leaf sid {
type inet:ipv6-prefix;
description
"Value of the SRv6 SID.";
}
leaf behavior {
type srv6-behavior-codepoint;
description
"Behavior bound to the SRv6 SID.";
}
leaf locator-name {
type string;
description
"SRv6 locator name.";
}
leaf vrf-name {
type frr-vrf:vrf-ref;
description
"The VRF name.";
}
}
}
}
}
}
}
}
}