mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
zebra: Fetch actual SRv6 encap src addr on startup
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 <cscarpit@cisco.com>
This commit is contained in:
parent
fcf17cc05d
commit
223d4534cd
|
@ -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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue