Merge pull request #9052 from mjstapp/dplane_incoming_dev

zebra: Move incoming netlink interface address change events to the dplane pthread
This commit is contained in:
Donald Sharp 2021-09-21 10:51:37 -04:00 committed by GitHub
commit 5b311cf18d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 762 additions and 77 deletions

View File

@ -512,7 +512,7 @@ extern char *esi_to_str(const esi_t *esi, char *buf, int size);
extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len); extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len);
extern void prefix_evpn_hexdump(const struct prefix_evpn *p); extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
static inline int ipv6_martian(struct in6_addr *addr) static inline int ipv6_martian(const struct in6_addr *addr)
{ {
struct in6_addr localhost_addr; struct in6_addr localhost_addr;
@ -527,7 +527,7 @@ static inline int ipv6_martian(struct in6_addr *addr)
extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p); extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
/* NOTE: This routine expects the address argument in network byte order. */ /* NOTE: This routine expects the address argument in network byte order. */
static inline int ipv4_martian(struct in_addr *addr) static inline int ipv4_martian(const struct in_addr *addr)
{ {
in_addr_t ip = ntohl(addr->s_addr); in_addr_t ip = ntohl(addr->s_addr);

View File

@ -307,9 +307,10 @@ void connected_up(struct interface *ifp, struct connected *ifc)
} }
/* Add connected IPv4 route to the interface. */ /* Add connected IPv4 route to the interface. */
void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, void connected_add_ipv4(struct interface *ifp, int flags,
uint16_t prefixlen, struct in_addr *dest, const struct in_addr *addr, uint16_t prefixlen,
const char *label, uint32_t metric) const struct in_addr *dest, const char *label,
uint32_t metric)
{ {
struct prefix_ipv4 *p; struct prefix_ipv4 *p;
struct connected *ifc; struct connected *ifc;
@ -502,8 +503,8 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p)
/* Delete connected IPv4 route to the interface. */ /* Delete connected IPv4 route to the interface. */
void connected_delete_ipv4(struct interface *ifp, int flags, void connected_delete_ipv4(struct interface *ifp, int flags,
struct in_addr *addr, uint16_t prefixlen, const struct in_addr *addr, uint16_t prefixlen,
struct in_addr *dest) const struct in_addr *dest)
{ {
struct prefix p, d; struct prefix p, d;
struct connected *ifc; struct connected *ifc;
@ -527,8 +528,9 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
} }
/* Add connected IPv6 route to the interface. */ /* Add connected IPv6 route to the interface. */
void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, void connected_add_ipv6(struct interface *ifp, int flags,
struct in6_addr *dest, uint16_t prefixlen, const struct in6_addr *addr,
const struct in6_addr *dest, uint16_t prefixlen,
const char *label, uint32_t metric) const char *label, uint32_t metric)
{ {
struct prefix_ipv6 *p; struct prefix_ipv6 *p;
@ -589,8 +591,9 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
connected_update(ifp, ifc); connected_update(ifp, ifc);
} }
void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, void connected_delete_ipv6(struct interface *ifp,
struct in6_addr *dest, uint16_t prefixlen) const struct in6_addr *address,
const struct in6_addr *dest, uint16_t prefixlen)
{ {
struct prefix p, d; struct prefix p, d;
struct connected *ifc; struct connected *ifc;

View File

@ -39,13 +39,14 @@ extern struct connected *connected_check_ptp(struct interface *ifp,
union prefixconstptr d); union prefixconstptr d);
extern void connected_add_ipv4(struct interface *ifp, int flags, extern void connected_add_ipv4(struct interface *ifp, int flags,
struct in_addr *addr, uint16_t prefixlen, const struct in_addr *addr, uint16_t prefixlen,
struct in_addr *dest, const char *label, const struct in_addr *dest, const char *label,
uint32_t metric); uint32_t metric);
extern void connected_delete_ipv4(struct interface *ifp, int flags, extern void connected_delete_ipv4(struct interface *ifp, int flags,
struct in_addr *addr, uint16_t prefixlen, const struct in_addr *addr,
struct in_addr *dest); uint16_t prefixlen,
const struct in_addr *dest);
extern void connected_delete_ipv4_unnumbered(struct connected *ifc); extern void connected_delete_ipv4_unnumbered(struct connected *ifc);
@ -53,12 +54,13 @@ extern void connected_up(struct interface *ifp, struct connected *ifc);
extern void connected_down(struct interface *ifp, struct connected *ifc); extern void connected_down(struct interface *ifp, struct connected *ifc);
extern void connected_add_ipv6(struct interface *ifp, int flags, extern void connected_add_ipv6(struct interface *ifp, int flags,
struct in6_addr *address, struct in6_addr *dest, const struct in6_addr *address,
uint16_t prefixlen, const char *label, const struct in6_addr *dest, uint16_t prefixlen,
uint32_t metric); const char *label, uint32_t metric);
extern void connected_delete_ipv6(struct interface *ifp, extern void connected_delete_ipv6(struct interface *ifp,
struct in6_addr *address, const struct in6_addr *address,
struct in6_addr *dest, uint16_t prefixlen); const struct in6_addr *dest,
uint16_t prefixlen);
extern int connected_is_unnumbered(struct interface *); extern int connected_is_unnumbered(struct interface *);

View File

@ -1443,7 +1443,6 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
NULL, ifa->ifa_prefixlen); NULL, ifa->ifa_prefixlen);
} }
/* /*
* Linux kernel does not send route delete on interface down/addr del * Linux kernel does not send route delete on interface down/addr del
* so we have to re-process routes it owns (i.e. kernel routes) * so we have to re-process routes it owns (i.e. kernel routes)
@ -1454,6 +1453,215 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
return 0; return 0;
} }
/*
* Parse and validate an incoming interface address change message,
* generating a dplane context object.
* This runs in the dplane pthread; the context is enqueued to the
* main pthread for processing.
*/
int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
int startup /*ignored*/)
{
int len;
struct ifaddrmsg *ifa;
struct rtattr *tb[IFA_MAX + 1];
void *addr;
void *broad;
char *label = NULL;
uint32_t metric = METRIC_MAX;
uint32_t kernel_flags = 0;
struct zebra_dplane_ctx *ctx;
struct prefix p;
ifa = NLMSG_DATA(h);
/* Validate message types */
if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
return 0;
if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: Invalid address family: %u",
__func__, nl_msg_type_to_str(h->nlmsg_type),
ifa->ifa_family);
return 0;
}
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
if (len < 0) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: netlink msg bad size: %d %zu",
__func__, nl_msg_type_to_str(h->nlmsg_type),
h->nlmsg_len,
(size_t)NLMSG_LENGTH(
sizeof(struct ifaddrmsg)));
return -1;
}
netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
/* Flags passed through */
if (tb[IFA_FLAGS])
kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]);
else
kernel_flags = ifa->ifa_flags;
if (IS_ZEBRA_DEBUG_KERNEL) { /* remove this line to see initial ifcfg */
char buf[PREFIX_STRLEN];
zlog_debug("%s: %s nsid %u ifindex %u flags 0x%x:", __func__,
nl_msg_type_to_str(h->nlmsg_type), ns_id,
ifa->ifa_index, kernel_flags);
if (tb[IFA_LOCAL])
zlog_debug(" IFA_LOCAL %s/%d",
inet_ntop(ifa->ifa_family,
RTA_DATA(tb[IFA_LOCAL]), buf,
sizeof(buf)),
ifa->ifa_prefixlen);
if (tb[IFA_ADDRESS])
zlog_debug(" IFA_ADDRESS %s/%d",
inet_ntop(ifa->ifa_family,
RTA_DATA(tb[IFA_ADDRESS]), buf,
sizeof(buf)),
ifa->ifa_prefixlen);
if (tb[IFA_BROADCAST])
zlog_debug(" IFA_BROADCAST %s/%d",
inet_ntop(ifa->ifa_family,
RTA_DATA(tb[IFA_BROADCAST]), buf,
sizeof(buf)),
ifa->ifa_prefixlen);
if (tb[IFA_LABEL])
zlog_debug(" IFA_LABEL %s",
(const char *)RTA_DATA(tb[IFA_LABEL]));
if (tb[IFA_CACHEINFO]) {
struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);
zlog_debug(" IFA_CACHEINFO pref %d, valid %d",
ci->ifa_prefered, ci->ifa_valid);
}
}
/* Validate prefix length */
if (ifa->ifa_family == AF_INET
&& ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: Invalid prefix length: %u",
__func__, nl_msg_type_to_str(h->nlmsg_type),
ifa->ifa_prefixlen);
return -1;
}
if (ifa->ifa_family == AF_INET6) {
if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: Invalid prefix length: %u",
__func__,
nl_msg_type_to_str(h->nlmsg_type),
ifa->ifa_prefixlen);
return -1;
}
/* Only consider valid addresses; we'll not get a kernel
* notification till IPv6 DAD has completed, but at init
* time, FRR does query for and will receive all addresses.
*/
if (h->nlmsg_type == RTM_NEWADDR
&& (kernel_flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: Invalid/tentative addr",
__func__,
nl_msg_type_to_str(h->nlmsg_type));
return 0;
}
}
/* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
if (tb[IFA_LOCAL] == NULL)
tb[IFA_LOCAL] = tb[IFA_ADDRESS];
if (tb[IFA_ADDRESS] == NULL)
tb[IFA_ADDRESS] = tb[IFA_LOCAL];
/* local interface address */
addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
/* addr is primary key, SOL if we don't have one */
if (addr == NULL) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: No local interface address",
__func__, nl_msg_type_to_str(h->nlmsg_type));
return -1;
}
/* Allocate a context object, now that validation is done. */
ctx = dplane_ctx_alloc();
if (h->nlmsg_type == RTM_NEWADDR)
dplane_ctx_set_op(ctx, DPLANE_OP_INTF_ADDR_ADD);
else
dplane_ctx_set_op(ctx, DPLANE_OP_INTF_ADDR_DEL);
dplane_ctx_set_ifindex(ctx, ifa->ifa_index);
dplane_ctx_set_ns_id(ctx, ns_id);
/* Convert addr to prefix */
memset(&p, 0, sizeof(p));
p.family = ifa->ifa_family;
p.prefixlen = ifa->ifa_prefixlen;
if (p.family == AF_INET)
p.u.prefix4 = *(struct in_addr *)addr;
else
p.u.prefix6 = *(struct in6_addr *)addr;
dplane_ctx_set_intf_addr(ctx, &p);
/* is there a peer address? */
if (tb[IFA_ADDRESS]
&& memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]),
RTA_PAYLOAD(tb[IFA_ADDRESS]))) {
broad = RTA_DATA(tb[IFA_ADDRESS]);
dplane_ctx_intf_set_connected(ctx);
} else if (tb[IFA_BROADCAST]) {
/* seeking a broadcast address */
broad = RTA_DATA(tb[IFA_BROADCAST]);
dplane_ctx_intf_set_broadcast(ctx);
} else
broad = NULL;
if (broad) {
/* Convert addr to prefix */
memset(&p, 0, sizeof(p));
p.family = ifa->ifa_family;
p.prefixlen = ifa->ifa_prefixlen;
if (p.family == AF_INET)
p.u.prefix4 = *(struct in_addr *)broad;
else
p.u.prefix6 = *(struct in6_addr *)broad;
dplane_ctx_set_intf_dest(ctx, &p);
}
/* Flags. */
if (kernel_flags & IFA_F_SECONDARY)
dplane_ctx_intf_set_secondary(ctx);
/* Label */
if (tb[IFA_LABEL]) {
label = (char *)RTA_DATA(tb[IFA_LABEL]);
dplane_ctx_set_intf_label(ctx, label);
}
if (tb[IFA_RT_PRIORITY])
metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]);
dplane_ctx_set_intf_metric(ctx, metric);
/* Enqueue ctx for main pthread to process */
dplane_provider_enqueue_to_zebra(ctx);
return 0;
}
int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{ {
int len; int len;

View File

@ -29,6 +29,14 @@ extern "C" {
extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
int startup); int startup);
/*
* Parse an incoming interface address change message, generate a dplane
* context object for processing.
*/
int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
int startup);
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns); extern int interface_lookup_netlink(struct zebra_ns *zns);

View File

@ -1205,6 +1205,109 @@ void zebra_if_set_protodown(struct interface *ifp, bool down)
#endif #endif
} }
/*
* Handle an interface addr event based on info in a dplane context object.
* This runs in the main pthread, using the info in the context object to
* modify an interface.
*/
void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx)
{
struct interface *ifp;
uint8_t flags = 0;
const char *label = NULL;
ns_id_t ns_id;
struct zebra_ns *zns;
uint32_t metric = METRIC_MAX;
ifindex_t ifindex;
const struct prefix *addr, *dest = NULL;
enum dplane_op_e op;
op = dplane_ctx_get_op(ctx);
ns_id = dplane_ctx_get_ns_id(ctx);
zns = zebra_ns_lookup(ns_id);
if (zns == NULL) {
/* No ns - deleted maybe? */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: can't find zns id %u", __func__, ns_id);
goto done;
}
ifindex = dplane_ctx_get_ifindex(ctx);
ifp = if_lookup_by_index_per_ns(zns, ifindex);
if (ifp == NULL) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: can't find ifp at nsid %u index %d",
__func__, ns_id, ifindex);
goto done;
}
addr = dplane_ctx_get_intf_addr(ctx);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__,
dplane_op2str(op), ifindex, addr);
/* Is there a peer or broadcast address? */
dest = dplane_ctx_get_intf_dest(ctx);
if (dest->prefixlen == 0)
dest = NULL;
if (dplane_ctx_intf_is_connected(ctx))
SET_FLAG(flags, ZEBRA_IFA_PEER);
/* Flags. */
if (dplane_ctx_intf_is_secondary(ctx))
SET_FLAG(flags, ZEBRA_IFA_SECONDARY);
/* Label? */
if (dplane_ctx_intf_has_label(ctx))
label = dplane_ctx_get_intf_label(ctx);
if (label && strcmp(ifp->name, label) == 0)
label = NULL;
metric = dplane_ctx_get_intf_metric(ctx);
/* Register interface address to the interface. */
if (addr->family == AF_INET) {
if (op == DPLANE_OP_INTF_ADDR_ADD)
connected_add_ipv4(
ifp, flags, &addr->u.prefix4, addr->prefixlen,
dest ? &dest->u.prefix4 : NULL, label, metric);
else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) {
/* Delete with a peer address */
connected_delete_ipv4(ifp, flags, &addr->u.prefix4,
addr->prefixlen,
&dest->u.prefix4);
} else
connected_delete_ipv4(ifp, flags, &addr->u.prefix4,
addr->prefixlen, NULL);
}
if (addr->family == AF_INET6) {
if (op == DPLANE_OP_INTF_ADDR_ADD) {
connected_add_ipv6(ifp, flags, &addr->u.prefix6,
dest ? &dest->u.prefix6 : NULL,
addr->prefixlen, label, metric);
} else
connected_delete_ipv6(ifp, &addr->u.prefix6, NULL,
addr->prefixlen);
}
/*
* Linux kernel does not send route delete on interface down/addr del
* so we have to re-process routes it owns (i.e. kernel routes)
*/
if (op != DPLANE_OP_INTF_ADDR_ADD)
rib_update(RIB_UPDATE_KERNEL);
done:
/* We're responsible for the ctx object */
dplane_ctx_fini(&ctx);
}
/* Dump if address information to vty. */ /* Dump if address information to vty. */
static void connected_dump_vty(struct vty *vty, json_object *json, static void connected_dump_vty(struct vty *vty, json_object *json,
struct connected *connected) struct connected *connected)

View File

@ -513,6 +513,7 @@ extern void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf);
extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif); extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif);
extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
char *pd_buf, uint32_t pd_buf_len); char *pd_buf, uint32_t pd_buf_len);
void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx);
#ifdef HAVE_PROC_NET_DEV #ifdef HAVE_PROC_NET_DEV
extern void ifstat_update_proc(void); extern void ifstat_update_proc(void);

View File

@ -324,6 +324,10 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
return ret; return ret;
} }
/*
* Dispatch an incoming netlink message; used by the zebra main pthread's
* netlink event reader.
*/
static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
int startup) int startup)
{ {
@ -345,10 +349,6 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
return netlink_link_change(h, ns_id, startup); return netlink_link_change(h, ns_id, startup);
case RTM_DELLINK: case RTM_DELLINK:
return netlink_link_change(h, ns_id, startup); return netlink_link_change(h, ns_id, startup);
case RTM_NEWADDR:
return netlink_interface_addr(h, ns_id, startup);
case RTM_DELADDR:
return netlink_interface_addr(h, ns_id, startup);
case RTM_NEWNEIGH: case RTM_NEWNEIGH:
case RTM_DELNEIGH: case RTM_DELNEIGH:
case RTM_GETNEIGH: case RTM_GETNEIGH:
@ -361,6 +361,12 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
return netlink_nexthop_change(h, ns_id, startup); return netlink_nexthop_change(h, ns_id, startup);
case RTM_DELNEXTHOP: case RTM_DELNEXTHOP:
return netlink_nexthop_change(h, ns_id, startup); return netlink_nexthop_change(h, ns_id, startup);
/* Messages handled in the dplane thread */
case RTM_NEWADDR:
case RTM_DELADDR:
return 0;
default: default:
/* /*
* If we have received this message then * If we have received this message then
@ -378,6 +384,32 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
return 0; return 0;
} }
/*
* Dispatch an incoming netlink message; used by the dataplane pthread's
* netlink event reader code.
*/
static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
{
/*
* Dispatch the incoming messages that the dplane pthread handles
*/
switch (h->nlmsg_type) {
case RTM_NEWADDR:
case RTM_DELADDR:
return netlink_interface_addr_dplane(h, ns_id, startup);
/* TODO */
case RTM_NEWLINK:
case RTM_DELLINK:
default:
break;
}
return 0;
}
static int kernel_read(struct thread *thread) static int kernel_read(struct thread *thread)
{ {
struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread);
@ -388,13 +420,24 @@ static int kernel_read(struct thread *thread)
netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info, netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info,
5, 0); 5, 0);
zns->t_netlink = NULL;
thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock,
&zns->t_netlink); &zns->t_netlink);
return 0; return 0;
} }
/*
* Called by the dplane pthread to read incoming OS messages and dispatch them.
*/
int kernel_dplane_read(struct zebra_dplane_info *info)
{
netlink_parse_info(dplane_netlink_information_fetch, &info->nls, info,
5, 0);
return 0;
}
/* /*
* Filter out messages from self that occur on listener socket, * Filter out messages from self that occur on listener socket,
* caused by our actions on the command socket(s) * caused by our actions on the command socket(s)
@ -408,7 +451,7 @@ static int kernel_read(struct thread *thread)
* so that we only had to write one way to handle incoming * so that we only had to write one way to handle incoming
* address add/delete changes. * address add/delete changes.
*/ */
static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid) static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid)
{ {
/* /*
* BPF_JUMP instructions and where you jump to are based upon * BPF_JUMP instructions and where you jump to are based upon
@ -476,8 +519,8 @@ static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid)
safe_strerror(errno)); safe_strerror(errno));
} }
void netlink_parse_rtattr_flags(struct rtattr **tb, int max, void netlink_parse_rtattr_flags(struct rtattr **tb, int max, struct rtattr *rta,
struct rtattr *rta, int len, unsigned short flags) int len, unsigned short flags)
{ {
unsigned short type; unsigned short type;
@ -799,8 +842,7 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg,
* ignored, -1 otherwise. * ignored, -1 otherwise.
*/ */
static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
const struct zebra_dplane_info *zns, bool is_cmd, bool startup)
bool startup)
{ {
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
int errnum = err->error; int errnum = err->error;
@ -833,7 +875,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
} }
/* Deal with errors that occur because of races in link handling. */ /* Deal with errors that occur because of races in link handling. */
if (zns->is_cmd if (is_cmd
&& ((msg_type == RTM_DELROUTE && ((msg_type == RTM_DELROUTE
&& (-errnum == ENODEV || -errnum == ESRCH)) && (-errnum == ENODEV || -errnum == ESRCH))
|| (msg_type == RTM_NEWROUTE || (msg_type == RTM_NEWROUTE
@ -852,7 +894,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
* do not log these as an error. * do not log these as an error.
*/ */
if (msg_type == RTM_DELNEIGH if (msg_type == RTM_DELNEIGH
|| (zns->is_cmd && msg_type == RTM_NEWROUTE || (is_cmd && msg_type == RTM_NEWROUTE
&& (-errnum == ESRCH || -errnum == ENETUNREACH))) { && (-errnum == ESRCH || -errnum == ENETUNREACH))) {
/* /*
* This is known to happen in some situations, don't log as * This is known to happen in some situations, don't log as
@ -924,8 +966,9 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
/* Error handling. */ /* Error handling. */
if (h->nlmsg_type == NLMSG_ERROR) { if (h->nlmsg_type == NLMSG_ERROR) {
int err = netlink_parse_error(nl, h, zns, int err = netlink_parse_error(
startup); nl, h, zns->is_cmd, startup);
if (err == 1) { if (err == 1) {
if (!(h->nlmsg_flags & NLM_F_MULTI)) if (!(h->nlmsg_flags & NLM_F_MULTI))
return 0; return 0;
@ -937,8 +980,8 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
/* OK we got netlink message. */ /* OK we got netlink message. */
if (IS_ZEBRA_DEBUG_KERNEL) if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug( zlog_debug(
"netlink_parse_info: %s type %s(%u), len=%d, seq=%u, pid=%u", "%s: %s type %s(%u), len=%d, seq=%u, pid=%u",
nl->name, __func__, nl->name,
nl_msg_type_to_str(h->nlmsg_type), nl_msg_type_to_str(h->nlmsg_type),
h->nlmsg_type, h->nlmsg_len, h->nlmsg_type, h->nlmsg_len,
h->nlmsg_seq, h->nlmsg_pid); h->nlmsg_seq, h->nlmsg_pid);
@ -1140,7 +1183,8 @@ static int nl_batch_read_resp(struct nl_batch *bth)
} }
if (h->nlmsg_type == NLMSG_ERROR) { if (h->nlmsg_type == NLMSG_ERROR) {
int err = netlink_parse_error(nl, h, bth->zns, 0); int err = netlink_parse_error(nl, h, bth->zns->is_cmd,
false);
if (err == -1) if (err == -1)
dplane_ctx_set_status( dplane_ctx_set_status(
@ -1359,6 +1403,8 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_GRE_SET: case DPLANE_OP_GRE_SET:
return netlink_put_gre_set_msg(bth, ctx); return netlink_put_gre_set_msg(bth, ctx);
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
case DPLANE_OP_NONE: case DPLANE_OP_NONE:
return FRR_NETLINK_ERROR; return FRR_NETLINK_ERROR;
} }
@ -1455,12 +1501,25 @@ void kernel_init(struct zebra_ns *zns)
exit(-1); exit(-1);
} }
snprintf(zns->netlink_dplane.name, sizeof(zns->netlink_dplane.name), /* Outbound socket for dplane programming of the host OS. */
"netlink-dp (NS %u)", zns->ns_id); snprintf(zns->netlink_dplane_out.name,
zns->netlink_dplane.sock = -1; sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)",
if (netlink_socket(&zns->netlink_dplane, 0, zns->ns_id) < 0) { zns->ns_id);
zns->netlink_dplane_out.sock = -1;
if (netlink_socket(&zns->netlink_dplane_out, 0, zns->ns_id) < 0) {
zlog_err("Failure to create %s socket", zlog_err("Failure to create %s socket",
zns->netlink_dplane.name); zns->netlink_dplane_out.name);
exit(-1);
}
/* Inbound socket for OS events coming to the dplane. */
snprintf(zns->netlink_dplane_in.name,
sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)",
zns->ns_id);
zns->netlink_dplane_in.sock = -1;
if (netlink_socket(&zns->netlink_dplane_in, groups, zns->ns_id) < 0) {
zlog_err("Failure to create %s socket",
zns->netlink_dplane_in.name);
exit(-1); exit(-1);
} }
@ -1483,8 +1542,8 @@ void kernel_init(struct zebra_ns *zns)
errno, safe_strerror(errno)); errno, safe_strerror(errno));
one = 1; one = 1;
ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_EXT_ACK, ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK,
&one, sizeof(one)); NETLINK_EXT_ACK, &one, sizeof(one));
if (ret < 0) if (ret < 0)
zlog_notice("Registration for extended dp ACK failed : %d %s", zlog_notice("Registration for extended dp ACK failed : %d %s",
@ -1496,8 +1555,8 @@ void kernel_init(struct zebra_ns *zns)
* setsockopt fails, ignore the error. * setsockopt fails, ignore the error.
*/ */
one = 1; one = 1;
ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK, ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK,
&one, sizeof(one)); NETLINK_CAP_ACK, &one, sizeof(one));
if (ret < 0) if (ret < 0)
zlog_notice( zlog_notice(
"Registration for reduced ACK packet size failed, probably running an early kernel"); "Registration for reduced ACK packet size failed, probably running an early kernel");
@ -1512,20 +1571,33 @@ void kernel_init(struct zebra_ns *zns)
zlog_err("Can't set %s socket error: %s(%d)", zlog_err("Can't set %s socket error: %s(%d)",
zns->netlink_cmd.name, safe_strerror(errno), errno); zns->netlink_cmd.name, safe_strerror(errno), errno);
if (fcntl(zns->netlink_dplane.sock, F_SETFL, O_NONBLOCK) < 0) if (fcntl(zns->netlink_dplane_out.sock, F_SETFL, O_NONBLOCK) < 0)
zlog_err("Can't set %s socket error: %s(%d)", zlog_err("Can't set %s socket error: %s(%d)",
zns->netlink_dplane.name, safe_strerror(errno), errno); zns->netlink_dplane_out.name, safe_strerror(errno),
errno);
if (fcntl(zns->netlink_dplane_in.sock, F_SETFL, O_NONBLOCK) < 0)
zlog_err("Can't set %s socket error: %s(%d)",
zns->netlink_dplane_in.name, safe_strerror(errno),
errno);
/* Set receive buffer size if it's set from command line */ /* Set receive buffer size if it's set from command line */
if (nl_rcvbufsize) { if (nl_rcvbufsize) {
netlink_recvbuf(&zns->netlink, nl_rcvbufsize); netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize);
netlink_recvbuf(&zns->netlink_dplane, nl_rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize);
netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize);
} }
netlink_install_filter(zns->netlink.sock, /* Set filter for inbound sockets, to exclude events we've generated
* ourselves.
*/
netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid,
zns->netlink_dplane_out.snl.nl_pid);
netlink_install_filter(zns->netlink_dplane_in.sock,
zns->netlink_cmd.snl.nl_pid, zns->netlink_cmd.snl.nl_pid,
zns->netlink_dplane.snl.nl_pid); zns->netlink_dplane_out.snl.nl_pid);
zns->t_netlink = NULL; zns->t_netlink = NULL;
@ -1549,13 +1621,18 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
zns->netlink_cmd.sock = -1; zns->netlink_cmd.sock = -1;
} }
if (zns->netlink_dplane_in.sock >= 0) {
close(zns->netlink_dplane_in.sock);
zns->netlink_dplane_in.sock = -1;
}
/* During zebra shutdown, we need to leave the dataplane socket /* During zebra shutdown, we need to leave the dataplane socket
* around until all work is done. * around until all work is done.
*/ */
if (complete) { if (complete) {
if (zns->netlink_dplane.sock >= 0) { if (zns->netlink_dplane_out.sock >= 0) {
close(zns->netlink_dplane.sock); close(zns->netlink_dplane_out.sock);
zns->netlink_dplane.sock = -1; zns->netlink_dplane_out.sock = -1;
} }
} }
} }

View File

@ -529,7 +529,7 @@ int ifm_read(struct if_msghdr *ifm)
/* paranoia: sanity check structure */ /* paranoia: sanity check structure */
if (ifm->ifm_msglen < sizeof(struct if_msghdr)) { if (ifm->ifm_msglen < sizeof(struct if_msghdr)) {
flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR, flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR,
"ifm_read: ifm->ifm_msglen %d too short\n", "ifm_read: ifm->ifm_msglen %d too short",
ifm->ifm_msglen); ifm->ifm_msglen);
return -1; return -1;
} }
@ -807,23 +807,17 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr,
switch (sockunion_family(addr)) { switch (sockunion_family(addr)) {
case AF_INET: case AF_INET:
case AF_INET6: { case AF_INET6: {
char buf[4][INET6_ADDRSTRLEN];
int masklen = int masklen =
(sockunion_family(addr) == AF_INET) (sockunion_family(addr) == AF_INET)
? ip_masklen(mask->sin.sin_addr) ? ip_masklen(mask->sin.sin_addr)
: ip6_masklen(mask->sin6.sin6_addr); : ip6_masklen(mask->sin6.sin6_addr);
zlog_debug( zlog_debug(
"%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %s/%d broad %s dst %s gateway %s", "%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %pSU/%d broad %pSU dst %pSU gateway %pSU",
__func__, ifm->ifam_index, __func__, ifm->ifam_index,
(ifnlen ? ifname : "(nil)"), (ifnlen ? ifname : "(nil)"),
rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)), rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)),
ifm->ifam_flags, ifm->ifam_flags, addr, masklen, brd, &dst,
sockunion2str(addr, buf[0], sizeof(buf[0])), &gateway);
masklen,
sockunion2str(brd, buf[1], sizeof(buf[1])),
sockunion2str(&dst, buf[2], sizeof(buf[2])),
sockunion2str(&gateway, buf[2],
sizeof(buf[2])));
} break; } break;
default: default:
zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs {%s}", zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs {%s}",
@ -951,7 +945,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest,
/* rt_msghdr version check. */ /* rt_msghdr version check. */
if (rtm->rtm_version != RTM_VERSION) if (rtm->rtm_version != RTM_VERSION)
flog_warn(EC_ZEBRA_RTM_VERSION_MISMATCH, flog_warn(EC_ZEBRA_RTM_VERSION_MISMATCH,
"Routing message version different %d should be %d.This may cause problem\n", "Routing message version different %d should be %d.This may cause problem",
rtm->rtm_version, RTM_VERSION); rtm->rtm_version, RTM_VERSION);
/* Be sure structure is cleared */ /* Be sure structure is cleared */
@ -1463,6 +1457,14 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
return; return;
} }
/*
* Called by the dplane pthread to read incoming OS messages and dispatch them.
*/
int kernel_dplane_read(struct zebra_dplane_info *info)
{
return 0;
}
void kernel_update_multi(struct dplane_ctx_q *ctx_list) void kernel_update_multi(struct dplane_ctx_q *ctx_list)
{ {
struct zebra_dplane_ctx *ctx; struct zebra_dplane_ctx *ctx;

View File

@ -110,6 +110,11 @@ extern int kernel_del_mac_nhg(uint32_t nhg_id);
*/ */
extern void kernel_update_multi(struct dplane_ctx_q *ctx_list); extern void kernel_update_multi(struct dplane_ctx_q *ctx_list);
/*
* Called by the dplane pthread to read incoming OS messages and dispatch them.
*/
int kernel_dplane_read(struct zebra_dplane_info *info);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -37,11 +37,12 @@
#include "zebra/zebra_pbr.h" #include "zebra/zebra_pbr.h"
#include "printfrr.h" #include "printfrr.h"
/* Memory type for context blocks */ /* Memory types */
DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx"); DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf"); DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider"); DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object"); DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes");
#ifndef AOK #ifndef AOK
# define AOK 0 # define AOK 0
@ -402,6 +403,19 @@ struct zebra_dplane_provider {
TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link; TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
}; };
/* Declare types for list of zns info objects */
PREDECL_DLIST(zns_info_list);
struct dplane_zns_info {
struct zebra_dplane_info info;
/* Read event */
struct thread *t_read;
/* List linkage */
struct zns_info_list_item link;
};
/* /*
* Globals * Globals
*/ */
@ -424,6 +438,9 @@ static struct zebra_dplane_globals {
/* Ordered list of providers */ /* Ordered list of providers */
TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q; TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
/* List of info about each zns */
struct zns_info_list_head dg_zns_list;
/* Counter used to assign internal ids to providers */ /* Counter used to assign internal ids to providers */
uint32_t dg_provider_id; uint32_t dg_provider_id;
@ -498,6 +515,9 @@ static struct zebra_dplane_globals {
} zdplane_info; } zdplane_info;
/* Instantiate zns list type */
DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link);
/* /*
* Lock and unlock for interactions with the zebra 'core' pthread * Lock and unlock for interactions with the zebra 'core' pthread
*/ */
@ -690,6 +710,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL: case DPLANE_OP_ADDR_UNINSTALL:
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
/* Maybe free label string, if allocated */ /* Maybe free label string, if allocated */
if (ctx->u.intf.label != NULL && if (ctx->u.intf.label != NULL &&
ctx->u.intf.label != ctx->u.intf.label_buf) { ctx->u.intf.label != ctx->u.intf.label_buf) {
@ -1011,6 +1033,12 @@ const char *dplane_op2str(enum dplane_op_e op)
case DPLANE_OP_GRE_SET: case DPLANE_OP_GRE_SET:
ret = "GRE_SET"; ret = "GRE_SET";
break; break;
case DPLANE_OP_INTF_ADDR_ADD:
return "INTF_ADDR_ADD";
case DPLANE_OP_INTF_ADDR_DEL:
return "INTF_ADDR_DEL";
} }
return ret; return ret;
@ -1108,6 +1136,21 @@ vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
return ctx->zd_vrf_id; return ctx->zd_vrf_id;
} }
/* In some paths we have only a namespace id */
void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid)
{
DPLANE_CTX_VALID(ctx);
ctx->zd_ns_info.ns_id = nsid;
}
ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return ctx->zd_ns_info.ns_id;
}
bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx) bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
{ {
DPLANE_CTX_VALID(ctx); DPLANE_CTX_VALID(ctx);
@ -1154,6 +1197,13 @@ ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
return ctx->zd_ifindex; return ctx->zd_ifindex;
} }
void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex)
{
DPLANE_CTX_VALID(ctx);
ctx->zd_ifindex = ifindex;
}
void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type) void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
{ {
DPLANE_CTX_VALID(ctx); DPLANE_CTX_VALID(ctx);
@ -1669,6 +1719,13 @@ uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
return ctx->u.intf.metric; return ctx->u.intf.metric;
} }
void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
{
DPLANE_CTX_VALID(ctx);
ctx->u.intf.metric = metric;
}
/* Is interface addr p2p? */ /* Is interface addr p2p? */
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx) bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
{ {
@ -1691,6 +1748,27 @@ bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST); return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
} }
void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
ctx->u.intf.flags |= DPLANE_INTF_CONNECTED;
}
void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
}
void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
}
const struct prefix *dplane_ctx_get_intf_addr( const struct prefix *dplane_ctx_get_intf_addr(
const struct zebra_dplane_ctx *ctx) const struct zebra_dplane_ctx *ctx)
{ {
@ -1699,6 +1777,14 @@ const struct prefix *dplane_ctx_get_intf_addr(
return &(ctx->u.intf.prefix); return &(ctx->u.intf.prefix);
} }
void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
const struct prefix *p)
{
DPLANE_CTX_VALID(ctx);
prefix_copy(&(ctx->u.intf.prefix), p);
}
bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx) bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
{ {
DPLANE_CTX_VALID(ctx); DPLANE_CTX_VALID(ctx);
@ -1711,10 +1797,15 @@ const struct prefix *dplane_ctx_get_intf_dest(
{ {
DPLANE_CTX_VALID(ctx); DPLANE_CTX_VALID(ctx);
if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST) return &(ctx->u.intf.dest_prefix);
return &(ctx->u.intf.dest_prefix); }
else
return NULL; void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
const struct prefix *p)
{
DPLANE_CTX_VALID(ctx);
prefix_copy(&(ctx->u.intf.dest_prefix), p);
} }
bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx) bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
@ -1731,6 +1822,35 @@ const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
return ctx->u.intf.label; return ctx->u.intf.label;
} }
void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label)
{
size_t len;
DPLANE_CTX_VALID(ctx);
if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf)
free(ctx->u.intf.label);
ctx->u.intf.label = NULL;
if (label) {
ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
/* Use embedded buffer if it's adequate; else allocate. */
len = strlen(label);
if (len < sizeof(ctx->u.intf.label_buf)) {
strlcpy(ctx->u.intf.label_buf, label,
sizeof(ctx->u.intf.label_buf));
ctx->u.intf.label = ctx->u.intf.label_buf;
} else {
ctx->u.intf.label = strdup(label);
}
} else {
ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL;
}
}
/* Accessors for MAC information */ /* Accessors for MAC information */
vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx) vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
{ {
@ -2177,9 +2297,9 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
* two messages in some 'update' cases. * two messages in some 'update' cases.
*/ */
if (is_update) if (is_update)
zns->netlink_dplane.seq += 2; zns->netlink_dplane_out.seq += 2;
else else
zns->netlink_dplane.seq++; zns->netlink_dplane_out.seq++;
#endif /* HAVE_NETLINK */ #endif /* HAVE_NETLINK */
return AOK; return AOK;
@ -4709,10 +4829,92 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
#if defined(HAVE_NETLINK) #if defined(HAVE_NETLINK)
ns_info->is_cmd = true; ns_info->is_cmd = true;
ns_info->nls = zns->netlink_dplane; ns_info->nls = zns->netlink_dplane_out;
#endif /* NETLINK */ #endif /* NETLINK */
} }
#ifdef HAVE_NETLINK
/*
* Callback when an OS (netlink) incoming event read is ready. This runs
* in the dplane pthread.
*/
static int dplane_incoming_read(struct thread *event)
{
struct dplane_zns_info *zi = THREAD_ARG(event);
kernel_dplane_read(&zi->info);
/* Re-start read task */
thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
zi->info.nls.sock, &zi->t_read);
return 0;
}
#endif /* HAVE_NETLINK */
/*
* Notify dplane when namespaces are enabled and disabled. The dplane
* needs to start and stop reading incoming events from the zns. In the
* common case where vrfs are _not_ namespaces, there will only be one
* of these.
*
* This is called in the main pthread.
*/
void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
{
struct dplane_zns_info *zi;
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("%s: %s for nsid %u", __func__,
(enabled ? "ENABLED" : "DISABLED"), zns->ns_id);
/* Search for an existing zns info entry */
frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
if (zi->info.ns_id == zns->ns_id)
break;
}
if (enabled) {
/* Create a new entry if necessary; start reading. */
if (zi == NULL) {
zi = XCALLOC(MTYPE_DP_NS, sizeof(*zi));
zi->info.ns_id = zns->ns_id;
zns_info_list_add_tail(&zdplane_info.dg_zns_list, zi);
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("%s: nsid %u, new zi %p", __func__,
zns->ns_id, zi);
}
/* Make sure we're up-to-date with the zns object */
#if defined(HAVE_NETLINK)
zi->info.is_cmd = false;
zi->info.nls = zns->netlink_dplane_in;
/* Start read task for the dplane pthread. */
if (zdplane_info.dg_master)
thread_add_read(zdplane_info.dg_master,
dplane_incoming_read, zi,
zi->info.nls.sock, &zi->t_read);
#endif
} else if (zi) {
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("%s: nsid %u, deleting zi %p", __func__,
zns->ns_id, zi);
/* Stop reading, free memory */
zns_info_list_del(&zdplane_info.dg_zns_list, zi);
if (zdplane_info.dg_master)
thread_cancel_async(zdplane_info.dg_master, &zi->t_read,
NULL);
XFREE(MTYPE_DP_NS, zi);
}
}
/* /*
* Provider api to signal that work/events are available * Provider api to signal that work/events are available
* for the dataplane pthread. * for the dataplane pthread.
@ -4878,6 +5080,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifname(ctx),
ctx->u.gre.link_ifindex); ctx->u.gre.link_ifindex);
break; break;
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
zlog_debug("Dplane incoming op %s, intf %s, addr %pFX",
dplane_op2str(dplane_ctx_get_op(ctx)),
dplane_ctx_get_ifname(ctx),
dplane_ctx_get_intf_addr(ctx));
break;
} }
} }
@ -5020,6 +5230,11 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_BR_PORT_UPDATE:
break; break;
/* TODO -- error counters for incoming events? */
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
break;
case DPLANE_OP_NONE: case DPLANE_OP_NONE:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
atomic_fetch_add_explicit(&zdplane_info.dg_other_errors, atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
@ -5355,9 +5570,21 @@ done:
*/ */
static int dplane_check_shutdown_status(struct thread *event) static int dplane_check_shutdown_status(struct thread *event)
{ {
struct dplane_zns_info *zi;
if (IS_ZEBRA_DEBUG_DPLANE) if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("Zebra dataplane shutdown status check called"); zlog_debug("Zebra dataplane shutdown status check called");
/* Remove any zns info entries as we stop the dplane pthread. */
frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) {
zns_info_list_del(&zdplane_info.dg_zns_list, zi);
if (zdplane_info.dg_master)
thread_cancel(&zi->t_read);
XFREE(MTYPE_DP_NS, zi);
}
if (dplane_work_pending()) { if (dplane_work_pending()) {
/* Reschedule dplane check on a short timer */ /* Reschedule dplane check on a short timer */
thread_add_timer_msec(zdplane_info.dg_master, thread_add_timer_msec(zdplane_info.dg_master,
@ -5652,6 +5879,7 @@ static void zebra_dplane_init_internal(void)
TAILQ_INIT(&zdplane_info.dg_update_ctx_q); TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
TAILQ_INIT(&zdplane_info.dg_providers_q); TAILQ_INIT(&zdplane_info.dg_providers_q);
zns_info_list_init(&zdplane_info.dg_zns_list);
zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK; zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
@ -5667,6 +5895,7 @@ static void zebra_dplane_init_internal(void)
*/ */
void zebra_dplane_start(void) void zebra_dplane_start(void)
{ {
struct dplane_zns_info *zi;
struct zebra_dplane_provider *prov; struct zebra_dplane_provider *prov;
struct frr_pthread_attr pattr = { struct frr_pthread_attr pattr = {
.start = frr_pthread_attr_default.start, .start = frr_pthread_attr_default.start,
@ -5686,6 +5915,14 @@ void zebra_dplane_start(void)
thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0, thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
&zdplane_info.dg_t_update); &zdplane_info.dg_t_update);
/* Enqueue reads if necessary */
frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
#if defined(HAVE_NETLINK)
thread_add_read(zdplane_info.dg_master, dplane_incoming_read,
zi, zi->info.nls.sock, &zi->t_read);
#endif
}
/* Call start callbacks for registered providers */ /* Call start callbacks for registered providers */
DPLANE_LOCK(); DPLANE_LOCK();

View File

@ -63,6 +63,12 @@ zebra_dplane_info_from_zns(struct zebra_dplane_info *zns_info,
#endif /* NETLINK */ #endif /* NETLINK */
} }
/*
* Notify dplane when namespaces are enabled and disabled. The dplane
* needs to start and stop reading incoming events from the ns.
*/
void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled);
/* /*
* Result codes used when returning status back to the main zebra context. * Result codes used when returning status back to the main zebra context.
*/ */
@ -98,7 +104,7 @@ enum zebra_dplane_result {
*/ */
/* /*
* Enqueue a route install or update for the dataplane. * Operations that the dataplane can process.
*/ */
enum dplane_op_e { enum dplane_op_e {
DPLANE_OP_NONE = 0, DPLANE_OP_NONE = 0,
@ -172,6 +178,10 @@ enum dplane_op_e {
DPLANE_OP_NEIGH_TABLE_UPDATE, DPLANE_OP_NEIGH_TABLE_UPDATE,
DPLANE_OP_GRE_SET, DPLANE_OP_GRE_SET,
/* Incoming interface address events */
DPLANE_OP_INTF_ADDR_ADD,
DPLANE_OP_INTF_ADDR_DEL,
}; };
/* /*
@ -284,6 +294,7 @@ void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx); const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname); void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname);
ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx); ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex);
/* Retrieve last/current provider id */ /* Retrieve last/current provider id */
uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx);
@ -306,6 +317,10 @@ uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf); void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf);
vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx); vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx);
/* In some paths we have only a namespace id */
void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid);
ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx);
bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx); bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx, void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
uint32_t id); uint32_t id);
@ -441,17 +456,26 @@ dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx);
/* Accessors for interface information */ /* Accessors for interface information */
uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric);
/* Is interface addr p2p? */ /* Is interface addr p2p? */
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx);
bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx);
bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx); 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 prefix *dplane_ctx_get_intf_addr(
const struct zebra_dplane_ctx *ctx); 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); bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx);
const struct prefix *dplane_ctx_get_intf_dest( const struct prefix *dplane_ctx_get_intf_dest(
const struct zebra_dplane_ctx *ctx); const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
const struct prefix *p);
bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx);
const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx); const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label);
/* Accessors for MAC information */ /* Accessors for MAC information */
vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx); vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx);

View File

@ -281,7 +281,7 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
ri->af = rib_dest_af(dest); ri->af = rib_dest_af(dest);
if (zvrf && zvrf->zns) if (zvrf && zvrf->zns)
ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid; ri->nlmsg_pid = zvrf->zns->netlink_dplane_out.snl.nl_pid;
ri->nlmsg_type = cmd; ri->nlmsg_type = cmd;
ri->rtm_table = table_info->table_id; ri->rtm_table = table_info->table_id;

View File

@ -2987,6 +2987,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_IPSET_ENTRY_DELETE: case DPLANE_OP_IPSET_ENTRY_DELETE:
case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET: case DPLANE_OP_GRE_SET:
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
break; break;
} }

View File

@ -123,6 +123,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
zns->ns_id = ns_id; zns->ns_id = ns_id;
kernel_init(zns); kernel_init(zns);
zebra_dplane_ns_enable(zns, true);
interface_list(zns); interface_list(zns);
route_read(zns); route_read(zns);
kernel_read_pbr_rules(zns); kernel_read_pbr_rules(zns);
@ -140,6 +141,8 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
{ {
route_table_finish(zns->if_table); route_table_finish(zns->if_table);
zebra_dplane_ns_enable(zns, false /*Disable*/);
kernel_terminate(zns, complete); kernel_terminate(zns, complete);
table_manager_disable(zns->ns_id); table_manager_disable(zns->ns_id);

View File

@ -52,7 +52,12 @@ struct zebra_ns {
#ifdef HAVE_NETLINK #ifdef HAVE_NETLINK
struct nlsock netlink; /* kernel messages */ struct nlsock netlink; /* kernel messages */
struct nlsock netlink_cmd; /* command channel */ struct nlsock netlink_cmd; /* command channel */
struct nlsock netlink_dplane; /* dataplane channel */
/* dplane system's channels: one for outgoing programming,
* for the FIB e.g., and one for incoming events from the OS.
*/
struct nlsock netlink_dplane_out;
struct nlsock netlink_dplane_in;
struct thread *t_netlink; struct thread *t_netlink;
#endif #endif

View File

@ -4209,6 +4209,11 @@ static int rib_process_dplane_results(struct thread *thread)
zebra_pbr_dplane_result(ctx); zebra_pbr_dplane_result(ctx);
break; break;
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
zebra_if_addr_update_ctx(ctx);
break;
/* Some op codes not handled here */ /* Some op codes not handled here */
case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL: case DPLANE_OP_ADDR_UNINSTALL: