mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
staticd: Request/Release SIDs to SID Manager
Signed-off-by: Yuqing Zhao <galadriel.zyq@alibaba-inc.com>
This commit is contained in:
parent
7aefc15f64
commit
e80f24df7e
|
@ -30,6 +30,9 @@
|
||||||
#include "static_nht.h"
|
#include "static_nht.h"
|
||||||
#include "static_vty.h"
|
#include "static_vty.h"
|
||||||
#include "static_debug.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");
|
DEFINE_MTYPE_STATIC(STATIC, STATIC_NHT_DATA, "Static Nexthop tracking data");
|
||||||
PREDECL_HASH(static_nht_hash);
|
PREDECL_HASH(static_nht_hash);
|
||||||
|
@ -530,10 +533,660 @@ extern void static_zebra_route_add(struct static_path *pn, bool install)
|
||||||
zclient, &api);
|
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[] = {
|
static zclient_handler *const static_handlers[] = {
|
||||||
[ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
|
[ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
|
||||||
[ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
|
[ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
|
||||||
[ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner,
|
[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)
|
void static_zebra_init(void)
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef __STATIC_ZEBRA_H__
|
#ifndef __STATIC_ZEBRA_H__
|
||||||
#define __STATIC_ZEBRA_H__
|
#define __STATIC_ZEBRA_H__
|
||||||
|
|
||||||
|
#include "static_srv6.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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_register(struct vrf *vrf);
|
||||||
extern void static_zebra_vrf_unregister(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue