zebra: Add code to set SRv6 encap source addr in dplane

Add a bunch of set functions and associated data structure in
zebra_dplane to allow the configuration of the source address for SRv6
encap in the data plane.

Signed-off-by: Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
This commit is contained in:
Carmine Scarpitta 2022-11-03 16:23:51 +01:00 committed by Carmine Scarpitta
parent 959267f7c2
commit 8d0b4745a1
9 changed files with 223 additions and 0 deletions

View File

@ -972,6 +972,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
case DPLANE_OP_TC_FILTER_ADD:
case DPLANE_OP_TC_FILTER_DELETE:
case DPLANE_OP_TC_FILTER_UPDATE:
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
case DPLANE_OP_NONE:
case DPLANE_OP_STARTUP_STAGE:
break;

View File

@ -111,6 +111,106 @@ int genl_resolve_family(const char *family)
return ge_netlink_talk(genl_parse_getfamily, &req.n, zns, false);
}
/*
* sr tunsrc change via netlink interface, using a dataplane context object
*
* Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
* otherwise the number of bytes written to buf.
*/
ssize_t netlink_sr_tunsrc_set_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen)
{
struct nlsock *nl;
const struct in6_addr *tunsrc_addr;
struct genl_request *req = buf;
if (seg6_genl_family < 0) {
zlog_err(
"Failed to set SRv6 source address: kernel does not support 'SEG6' Generic Netlink family.");
return -1;
}
tunsrc_addr = dplane_ctx_get_srv6_encap_srcaddr(ctx);
if (!tunsrc_addr)
return -1;
if (buflen < sizeof(*req))
return 0;
nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
memset(req, 0, sizeof(*req));
req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
/* Prepare Netlink request to set tunsrc addr */
req->n.nlmsg_type = seg6_genl_family;
req->n.nlmsg_pid = nl->snl.nl_pid;
req->g.cmd = cmd;
req->g.version = SEG6_GENL_VERSION;
switch (cmd) {
case SEG6_CMD_SET_TUNSRC:
if (!nl_attr_put(&req->n, buflen, SEG6_ATTR_DST, tunsrc_addr,
sizeof(struct in6_addr)))
return 0;
break;
default:
zlog_err("Unsupported command (%u)", cmd);
return -1;
}
return NLMSG_ALIGN(req->n.nlmsg_len);
}
ssize_t netlink_sr_tunsrc_set_msg_encoder(struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen)
{
enum dplane_op_e op;
int cmd = 0;
op = dplane_ctx_get_op(ctx);
/* Call to netlink layer based on type of operation */
if (op == DPLANE_OP_SRV6_ENCAP_SRCADDR_SET) {
/* Validate */
if (dplane_ctx_get_srv6_encap_srcaddr(ctx) == NULL) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"sr tunsrc set failed: SRv6 encap source address not set");
return -1;
}
cmd = SEG6_CMD_SET_TUNSRC;
} else {
/* Invalid op */
zlog_err("Context received for kernel sr tunsrc update with incorrect OP code (%u)",
op);
return -1;
}
return netlink_sr_tunsrc_set_msg_encode(cmd, ctx, buf, buflen);
}
enum netlink_msg_status
netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
{
enum dplane_op_e op;
struct zebra_ns *zns;
struct genl_request req;
op = dplane_ctx_get_op(ctx);
assert(op == DPLANE_OP_SRV6_ENCAP_SRCADDR_SET);
netlink_sr_tunsrc_set_msg_encoder(ctx, &req, sizeof(req));
zns = zebra_ns_lookup(dplane_ctx_get_ns_sock(ctx));
return ge_netlink_talk(netlink_talk_filter, &req.n, zns, false);
}
void ge_netlink_init(struct zebra_ns *zns)
{
if (zns->ge_netlink_cmd.sock < 0)

View File

@ -25,6 +25,15 @@ struct genl_request {
};
extern int genl_resolve_family(const char *family);
extern ssize_t netlink_sr_tunsrc_set_msg_encode(int cmd,
struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen);
extern ssize_t netlink_sr_tunsrc_set_msg_encoder(struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen);
struct nl_batch;
extern enum netlink_msg_status
netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth,
struct zebra_dplane_ctx *ctx);
extern void ge_netlink_init(struct zebra_ns *zns);
#ifdef __cplusplus

View File

@ -1648,6 +1648,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_TC_FILTER_DELETE:
case DPLANE_OP_TC_FILTER_UPDATE:
return netlink_put_tc_filter_update_msg(bth, ctx);
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
return netlink_put_sr_tunsrc_set_msg(bth, ctx);
}
return FRR_NETLINK_ERROR;

View File

@ -1622,6 +1622,7 @@ void kernel_update_multi(struct dplane_ctx_list_head *ctx_list)
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
case DPLANE_OP_STARTUP_STAGE:
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
zlog_err("Unhandled dplane data for %s",
dplane_op2str(dplane_ctx_get_op(ctx)));
res = ZEBRA_DPLANE_REQUEST_FAILURE;

View File

@ -356,6 +356,13 @@ struct dplane_tc_filter_info {
uint32_t classid;
};
/*
* SRv6 encapsulation params context for the dataplane
*/
struct dplane_srv6_encap_ctx {
struct in6_addr srcaddr;
};
/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
@ -418,6 +425,7 @@ struct zebra_dplane_ctx {
struct dplane_gre_ctx gre;
struct dplane_netconf_info netconf;
enum zebra_dplane_startup_notifications spot;
struct dplane_srv6_encap_ctx srv6_encap;
} u;
/* Namespace info, used especially for netlink kernel communication */
@ -599,6 +607,9 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_tcs_in;
_Atomic uint32_t dg_tcs_errors;
_Atomic uint32_t dg_srv6_encap_srcaddr_set_in;
_Atomic uint32_t dg_srv6_encap_srcaddr_set_errors;
/* Dataplane pthread */
struct frr_pthread *dg_pthread;
@ -861,6 +872,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_GRE_SET:
case DPLANE_OP_INTF_NETCONFIG:
case DPLANE_OP_STARTUP_STAGE:
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
break;
}
}
@ -1186,6 +1198,11 @@ const char *dplane_op2str(enum dplane_op_e op)
break;
case DPLANE_OP_STARTUP_STAGE:
ret = "STARTUP_STAGE";
break;
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
ret = "SRV6_ENCAP_SRCADDR_SET";
break;
}
return ret;
@ -2599,6 +2616,16 @@ const struct prefix *dplane_ctx_get_intf_addr(
return &(ctx->u.intf.prefix);
}
/* Accessors for SRv6 encapsulation source address information */
const struct in6_addr *
dplane_ctx_get_srv6_encap_srcaddr(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return &(ctx->u.srv6_encap.srcaddr);
}
void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
const struct prefix *p)
{
@ -5872,6 +5899,60 @@ done:
return result;
}
/*
* Common helper api for SRv6 encapsulation source address set
*/
enum zebra_dplane_result
dplane_srv6_encap_srcaddr_set(const struct in6_addr *addr, ns_id_t ns_id)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
struct zebra_dplane_ctx *ctx = NULL;
enum dplane_op_e op = DPLANE_OP_SRV6_ENCAP_SRCADDR_SET;
int ret;
struct zebra_ns *zns;
if (!addr)
return result;
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
zlog_debug("init dplane ctx %s: addr %pI6", dplane_op2str(op),
addr);
}
zns = zebra_ns_lookup(ns_id);
if (!zns)
return result;
ctx = dplane_ctx_alloc();
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
dplane_ctx_ns_init(ctx, zns, false);
/* Init the SRv6 encap source address specific data area */
memcpy(&ctx->u.srv6_encap.srcaddr, addr,
sizeof(ctx->u.srv6_encap.srcaddr));
/* Update counter */
atomic_fetch_add_explicit(&zdplane_info.dg_srv6_encap_srcaddr_set_in, 1,
memory_order_relaxed);
/* Enqueue context for processing */
ret = dplane_update_enqueue(ctx);
if (ret == AOK)
result = ZEBRA_DPLANE_REQUEST_QUEUED;
else {
atomic_fetch_add_explicit(&zdplane_info
.dg_srv6_encap_srcaddr_set_errors,
1, memory_order_relaxed);
if (ctx)
dplane_ctx_free(&ctx);
}
return result;
}
/*
* Handler for 'show dplane'
*/
@ -6597,6 +6678,12 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_TC_FILTER_UPDATE:
case DPLANE_OP_STARTUP_STAGE:
break;
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
zlog_debug("Dplane SRv6 encap source address set op %s, addr %pI6",
dplane_op2str(dplane_ctx_get_op(ctx)),
&ctx->u.srv6_encap.srcaddr);
break;
}
}
@ -6767,6 +6854,13 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_NETCONFIG:
break;
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
atomic_fetch_add_explicit(&zdplane_info
.dg_srv6_encap_srcaddr_set_errors,
1, memory_order_relaxed);
break;
case DPLANE_OP_NONE:
case DPLANE_OP_STARTUP_STAGE:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)

View File

@ -18,6 +18,7 @@
#include "zebra/zserv.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_nhg.h"
#include "zebra/ge_netlink.h"
#ifdef __cplusplus
extern "C" {
@ -198,6 +199,9 @@ enum dplane_op_e {
/* Startup Control */
DPLANE_OP_STARTUP_STAGE,
/* Source address for SRv6 encapsulation */
DPLANE_OP_SRV6_ENCAP_SRCADDR_SET,
};
/*
@ -664,6 +668,8 @@ bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx);
const struct prefix *dplane_ctx_get_intf_addr(
const struct zebra_dplane_ctx *ctx);
const struct in6_addr *
dplane_ctx_get_srv6_encap_srcaddr(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
const struct prefix *p);
bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx);
@ -992,6 +998,13 @@ enum zebra_dplane_result
dplane_gre_set(struct interface *ifp, struct interface *ifp_link,
unsigned int mtu, const struct zebra_l2info_gre *gre_info);
/*
* Enqueue an SRv6 encap source address set
*/
enum zebra_dplane_result
dplane_srv6_encap_srcaddr_set(const struct in6_addr *addr, ns_id_t ns_id);
/* Forward ref of zebra_pbr_rule */
struct zebra_pbr_rule;

View File

@ -4961,6 +4961,7 @@ static void rib_process_dplane_results(struct event *thread)
case DPLANE_OP_BR_PORT_UPDATE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
case DPLANE_OP_NONE:
break;
case DPLANE_OP_STARTUP_STAGE:

View File

@ -415,6 +415,7 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx)
case DPLANE_OP_TC_FILTER_UPDATE:
/* Not currently handled */
case DPLANE_OP_INTF_NETCONFIG: /*NYI*/
case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
case DPLANE_OP_NONE:
case DPLANE_OP_STARTUP_STAGE:
break;