mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 00:59:13 +00:00
Merge pull request #16894 from wenwang00/project-phoenixwing-ysj
staticd: Add support for SRv6 Static SIDs
This commit is contained in:
commit
084ebc9473
@ -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
|
||||
!
|
||||
...
|
@ -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 */
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
38
lib/srv6.h
38
lib/srv6.h
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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
174
staticd/static_srv6.c
Normal 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
108
staticd/static_srv6.h
Normal 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__ */
|
@ -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
|
||||
|
@ -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, ¬e,
|
||||
&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)
|
||||
|
@ -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
|
||||
|
@ -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 += \
|
||||
|
0
tests/topotests/static_srv6_sids/__init__.py
Normal file
0
tests/topotests/static_srv6_sids/__init__.py
Normal file
107
tests/topotests/static_srv6_sids/expected_srv6_sids.json
Normal file
107
tests/topotests/static_srv6_sids/expected_srv6_sids.json
Normal 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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
16
tests/topotests/static_srv6_sids/r1/frr.conf
Normal file
16
tests/topotests/static_srv6_sids/r1/frr.conf
Normal 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
|
||||
!
|
||||
!
|
||||
!
|
13
tests/topotests/static_srv6_sids/r1/setup.sh
Normal file
13
tests/topotests/static_srv6_sids/r1/setup.sh
Normal 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
|
83
tests/topotests/static_srv6_sids/test_static_srv6_sids.py
Executable file
83
tests/topotests/static_srv6_sids/test_static_srv6_sids.py
Executable 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))
|
@ -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);
|
||||
|
@ -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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user