Skip to content

Commit

Permalink
zebra: Fetch actual SRv6 encap src addr on startup
Browse files Browse the repository at this point in the history
When zebra is started, someone may have configured an SRv6 encap source
address different from the default address ( :: ) in the kernel.

On startup, zebra should not assume that the actual SRv6 encap source
address is the default address ( :: ), but should retrieve the actual
source address from the kernel and put it in zebra configuration. In
other words, on startup we expect the actual SRv6 encap source
address and the configured one to be the same.

This commit makes the necessary changes to support the above.

Signed-off-by: Carmine Scarpitta <[email protected]>
  • Loading branch information
cscarpitta committed Dec 14, 2023
1 parent fcf17cc commit 223d453
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 1 deletion.
139 changes: 139 additions & 0 deletions zebra/ge_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,27 @@
#include "zebra/ge_netlink.h"
#include "zebra/debug.h"
#include "zebra/kernel_netlink.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_srv6.h"


/**
* This file provides an implementation of the functionality exposed by the
* kernel through the Generic Netlink mechanism.
*
* Supported features include the ability to configure the source address used
* for SRv6 encapsulation ('sr tunsrc' in kernel terminology).
*
* At the time of writing this code, the kernel does not send us any asynchronous
* notifications when someone changes the 'sr tunsrc' under us. As a result, we
* are currently unable to detect when the source address changes and update the
* SRv6 encapsulation source address configured in zebra.
*
* In the future, when the kernel supports async notifications, the implementation
* can be improved by listening on the Generic Netlink socket and adding a handler
* to process/parse incoming 'sr tunsrc' change messages and update the SRv6 zebra
* configuration with the new encap source address.
*/


/*
Expand Down Expand Up @@ -211,6 +232,117 @@ netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx
return ge_netlink_talk(netlink_talk_filter, &req.n, zns, false);
}

/**
* netlink_sr_tunsrc_reply_read() - Read in SR tunsrc reply from the kernel
*
* @h: Netlink message header
* @ns_id: Namspace id
* @startup: Are we reading under startup conditions?
*
* Return: Result status
*/
int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct genlmsghdr *ghdr;
struct rtattr *tb[SEG6_ATTR_MAX + 1] = {};
struct rtattr *attrs;

if (h->nlmsg_type != seg6_genl_family)
return 0;

len = h->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
if (len < 0) {
zlog_warn("%s: Message received from netlink is of a broken size %d %zu",
__func__, h->nlmsg_len,
(size_t)NLMSG_LENGTH(GENL_HDRLEN));
return -1;
}

ghdr = NLMSG_DATA(h);

if (ghdr->cmd != SEG6_CMD_GET_TUNSRC)
return 0;

attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
netlink_parse_rtattr(tb, SEG6_ATTR_MAX, attrs, len);

if (tb[SEG6_ATTR_DST] == NULL) {
zlog_err("Missing tunsrc addr");
return -1;
}

zebra_srv6_encap_src_addr_set(
(struct in6_addr *)RTA_DATA(tb[SEG6_ATTR_DST]));

if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: SRv6 encap source address received from kernel: '%pI6'",
__func__,
(struct in6_addr *)RTA_DATA(tb[SEG6_ATTR_DST]));

return 0;
}

/**
* netlink_request_sr_tunsrc() - Request SR tunsrc from the kernel
* @zns: Zebra namespace
*
* Return: Result status
*/
static int netlink_request_sr_tunsrc(struct zebra_ns *zns)
{
struct genl_request req;

if (zns->ge_netlink_cmd.sock < 0)
return -1;

if (seg6_genl_family < 0) {
zlog_err(
"Failed to get SRv6 encap source address: kernel does not support 'SEG6' Generic Netlink family.");
return -1;
}

/* Form the request, specifying filter (rtattr) if needed. */
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = seg6_genl_family;
req.g.cmd = SEG6_CMD_GET_TUNSRC;
req.g.version = SEG6_GENL_VERSION;

return netlink_request(&zns->ge_netlink_cmd, &req);
}

/**
* SR tunsrc read function using netlink interface. Only called
* on bootstrap time.
*/
int netlink_sr_tunsrc_read(struct zebra_ns *zns)
{
int ret;
struct zebra_dplane_info dp_info;

if (zns->ge_netlink_cmd.sock < 0)
return -1;

/* Capture info in intermediate info struct */
dp_info.ns_id = zns->ns_id;
dp_info.is_cmd = true;
dp_info.sock = zns->ge_netlink_cmd.sock;
dp_info.seq = zns->ge_netlink_cmd.seq;

/* Get SR tunsrc. */
ret = netlink_request_sr_tunsrc(zns);
if (ret < 0)
return ret;
ret = netlink_parse_info(netlink_sr_tunsrc_reply_read,
&zns->ge_netlink_cmd, &dp_info, 0, true);
if (ret < 0)
return ret;

return 0;
}

void ge_netlink_init(struct zebra_ns *zns)
{
if (zns->ge_netlink_cmd.sock < 0)
Expand All @@ -225,6 +357,13 @@ void ge_netlink_init(struct zebra_ns *zns)
if (genl_resolve_family("SEG6"))
zlog_warn(
"Kernel does not support 'SEG6' Generic Netlink family. Any attempt to set the encapsulation parameters under the SRv6 configuration will fail");

/**
* Retrieve the actual SRv6 encap source address from the kernel
* (default namespace) and save it to zebra SRv6 config
*/
if (zns->ns_id == NS_DEFAULT)
netlink_sr_tunsrc_read(zns);
}

#endif /* HAVE_NETLINK */
4 changes: 4 additions & 0 deletions zebra/ge_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ struct nl_batch;
extern enum netlink_msg_status
netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth,
struct zebra_dplane_ctx *ctx);

int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup);
int netlink_sr_tunsrc_read(struct zebra_ns *zns);

extern void ge_netlink_init(struct zebra_ns *zns);

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion zebra/kernel_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1963,7 +1963,7 @@ void kernel_init(struct zebra_ns *zns)

rt_netlink_init();

ge_netlink_init();
ge_netlink_init(zns);
}

/* Helper to clean up an nlsock */
Expand Down
1 change: 1 addition & 0 deletions zebra/zebra_srv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "zebra/zebra_router.h"
#include "zebra/zebra_srv6.h"
#include "zebra/zebra_errors.h"
#include "zebra/ge_netlink.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Expand Down

0 comments on commit 223d453

Please sign in to comment.