mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 20:48:27 +00:00
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:
commit
5b311cf18d
@ -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 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;
|
||||
|
||||
@ -527,7 +527,7 @@ static inline int ipv6_martian(struct in6_addr *addr)
|
||||
extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -307,9 +307,10 @@ void connected_up(struct interface *ifp, struct connected *ifc)
|
||||
}
|
||||
|
||||
/* Add connected IPv4 route to the interface. */
|
||||
void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
|
||||
uint16_t prefixlen, struct in_addr *dest,
|
||||
const char *label, uint32_t metric)
|
||||
void connected_add_ipv4(struct interface *ifp, int flags,
|
||||
const struct in_addr *addr, uint16_t prefixlen,
|
||||
const struct in_addr *dest, const char *label,
|
||||
uint32_t metric)
|
||||
{
|
||||
struct prefix_ipv4 *p;
|
||||
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. */
|
||||
void connected_delete_ipv4(struct interface *ifp, int flags,
|
||||
struct in_addr *addr, uint16_t prefixlen,
|
||||
struct in_addr *dest)
|
||||
const struct in_addr *addr, uint16_t prefixlen,
|
||||
const struct in_addr *dest)
|
||||
{
|
||||
struct prefix p, d;
|
||||
struct connected *ifc;
|
||||
@ -527,8 +528,9 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
|
||||
}
|
||||
|
||||
/* Add connected IPv6 route to the interface. */
|
||||
void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
|
||||
struct in6_addr *dest, uint16_t prefixlen,
|
||||
void connected_add_ipv6(struct interface *ifp, int flags,
|
||||
const struct in6_addr *addr,
|
||||
const struct in6_addr *dest, uint16_t prefixlen,
|
||||
const char *label, uint32_t metric)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
|
||||
struct in6_addr *dest, uint16_t prefixlen)
|
||||
void connected_delete_ipv6(struct interface *ifp,
|
||||
const struct in6_addr *address,
|
||||
const struct in6_addr *dest, uint16_t prefixlen)
|
||||
{
|
||||
struct prefix p, d;
|
||||
struct connected *ifc;
|
||||
|
@ -39,13 +39,14 @@ extern struct connected *connected_check_ptp(struct interface *ifp,
|
||||
union prefixconstptr d);
|
||||
|
||||
extern void connected_add_ipv4(struct interface *ifp, int flags,
|
||||
struct in_addr *addr, uint16_t prefixlen,
|
||||
struct in_addr *dest, const char *label,
|
||||
const struct in_addr *addr, uint16_t prefixlen,
|
||||
const struct in_addr *dest, const char *label,
|
||||
uint32_t metric);
|
||||
|
||||
extern void connected_delete_ipv4(struct interface *ifp, int flags,
|
||||
struct in_addr *addr, uint16_t prefixlen,
|
||||
struct in_addr *dest);
|
||||
const struct in_addr *addr,
|
||||
uint16_t prefixlen,
|
||||
const struct in_addr *dest);
|
||||
|
||||
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_add_ipv6(struct interface *ifp, int flags,
|
||||
struct in6_addr *address, struct in6_addr *dest,
|
||||
uint16_t prefixlen, const char *label,
|
||||
uint32_t metric);
|
||||
const struct in6_addr *address,
|
||||
const struct in6_addr *dest, uint16_t prefixlen,
|
||||
const char *label, uint32_t metric);
|
||||
extern void connected_delete_ipv6(struct interface *ifp,
|
||||
struct in6_addr *address,
|
||||
struct in6_addr *dest, uint16_t prefixlen);
|
||||
const struct in6_addr *address,
|
||||
const struct in6_addr *dest,
|
||||
uint16_t prefixlen);
|
||||
|
||||
extern int connected_is_unnumbered(struct interface *);
|
||||
|
||||
|
@ -1443,7 +1443,6 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
NULL, ifa->ifa_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)
|
||||
@ -1454,6 +1453,215 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
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 len;
|
||||
|
@ -29,6 +29,14 @@ extern "C" {
|
||||
|
||||
extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
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 interface_lookup_netlink(struct zebra_ns *zns);
|
||||
|
||||
|
@ -1205,6 +1205,109 @@ void zebra_if_set_protodown(struct interface *ifp, bool down)
|
||||
#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. */
|
||||
static void connected_dump_vty(struct vty *vty, json_object *json,
|
||||
struct connected *connected)
|
||||
|
@ -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 const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
|
||||
char *pd_buf, uint32_t pd_buf_len);
|
||||
void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
#ifdef HAVE_PROC_NET_DEV
|
||||
extern void ifstat_update_proc(void);
|
||||
|
@ -324,6 +324,10 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
|
||||
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,
|
||||
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);
|
||||
case RTM_DELLINK:
|
||||
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_DELNEIGH:
|
||||
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);
|
||||
case RTM_DELNEXTHOP:
|
||||
return netlink_nexthop_change(h, ns_id, startup);
|
||||
|
||||
/* Messages handled in the dplane thread */
|
||||
case RTM_NEWADDR:
|
||||
case RTM_DELADDR:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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,
|
||||
5, 0);
|
||||
zns->t_netlink = NULL;
|
||||
|
||||
thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock,
|
||||
&zns->t_netlink);
|
||||
|
||||
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,
|
||||
* 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
|
||||
* 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
|
||||
@ -476,8 +519,8 @@ static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid)
|
||||
safe_strerror(errno));
|
||||
}
|
||||
|
||||
void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
|
||||
struct rtattr *rta, int len, unsigned short flags)
|
||||
void netlink_parse_rtattr_flags(struct rtattr **tb, int max, struct rtattr *rta,
|
||||
int len, unsigned short flags)
|
||||
{
|
||||
unsigned short type;
|
||||
|
||||
@ -799,8 +842,7 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg,
|
||||
* ignored, -1 otherwise.
|
||||
*/
|
||||
static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
|
||||
const struct zebra_dplane_info *zns,
|
||||
bool startup)
|
||||
bool is_cmd, bool startup)
|
||||
{
|
||||
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
|
||||
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. */
|
||||
if (zns->is_cmd
|
||||
if (is_cmd
|
||||
&& ((msg_type == RTM_DELROUTE
|
||||
&& (-errnum == ENODEV || -errnum == ESRCH))
|
||||
|| (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.
|
||||
*/
|
||||
if (msg_type == RTM_DELNEIGH
|
||||
|| (zns->is_cmd && msg_type == RTM_NEWROUTE
|
||||
|| (is_cmd && msg_type == RTM_NEWROUTE
|
||||
&& (-errnum == ESRCH || -errnum == ENETUNREACH))) {
|
||||
/*
|
||||
* 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. */
|
||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
||||
int err = netlink_parse_error(nl, h, zns,
|
||||
startup);
|
||||
int err = netlink_parse_error(
|
||||
nl, h, zns->is_cmd, startup);
|
||||
|
||||
if (err == 1) {
|
||||
if (!(h->nlmsg_flags & NLM_F_MULTI))
|
||||
return 0;
|
||||
@ -937,8 +980,8 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
|
||||
/* OK we got netlink message. */
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"netlink_parse_info: %s type %s(%u), len=%d, seq=%u, pid=%u",
|
||||
nl->name,
|
||||
"%s: %s type %s(%u), len=%d, seq=%u, pid=%u",
|
||||
__func__, nl->name,
|
||||
nl_msg_type_to_str(h->nlmsg_type),
|
||||
h->nlmsg_type, h->nlmsg_len,
|
||||
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) {
|
||||
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)
|
||||
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:
|
||||
return netlink_put_gre_set_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
case DPLANE_OP_NONE:
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
@ -1455,12 +1501,25 @@ void kernel_init(struct zebra_ns *zns)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
snprintf(zns->netlink_dplane.name, sizeof(zns->netlink_dplane.name),
|
||||
"netlink-dp (NS %u)", zns->ns_id);
|
||||
zns->netlink_dplane.sock = -1;
|
||||
if (netlink_socket(&zns->netlink_dplane, 0, zns->ns_id) < 0) {
|
||||
/* Outbound socket for dplane programming of the host OS. */
|
||||
snprintf(zns->netlink_dplane_out.name,
|
||||
sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)",
|
||||
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",
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1483,8 +1542,8 @@ void kernel_init(struct zebra_ns *zns)
|
||||
errno, safe_strerror(errno));
|
||||
|
||||
one = 1;
|
||||
ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_EXT_ACK,
|
||||
&one, sizeof(one));
|
||||
ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK,
|
||||
NETLINK_EXT_ACK, &one, sizeof(one));
|
||||
|
||||
if (ret < 0)
|
||||
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.
|
||||
*/
|
||||
one = 1;
|
||||
ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK,
|
||||
&one, sizeof(one));
|
||||
ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK,
|
||||
NETLINK_CAP_ACK, &one, sizeof(one));
|
||||
if (ret < 0)
|
||||
zlog_notice(
|
||||
"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)",
|
||||
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)",
|
||||
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 */
|
||||
if (nl_rcvbufsize) {
|
||||
netlink_recvbuf(&zns->netlink, 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_dplane.snl.nl_pid);
|
||||
zns->netlink_dplane_out.snl.nl_pid);
|
||||
|
||||
zns->t_netlink = NULL;
|
||||
|
||||
@ -1549,13 +1621,18 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
|
||||
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
|
||||
* around until all work is done.
|
||||
*/
|
||||
if (complete) {
|
||||
if (zns->netlink_dplane.sock >= 0) {
|
||||
close(zns->netlink_dplane.sock);
|
||||
zns->netlink_dplane.sock = -1;
|
||||
if (zns->netlink_dplane_out.sock >= 0) {
|
||||
close(zns->netlink_dplane_out.sock);
|
||||
zns->netlink_dplane_out.sock = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ int ifm_read(struct if_msghdr *ifm)
|
||||
/* paranoia: sanity check structure */
|
||||
if (ifm->ifm_msglen < sizeof(struct if_msghdr)) {
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
@ -807,23 +807,17 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr,
|
||||
switch (sockunion_family(addr)) {
|
||||
case AF_INET:
|
||||
case AF_INET6: {
|
||||
char buf[4][INET6_ADDRSTRLEN];
|
||||
int masklen =
|
||||
(sockunion_family(addr) == AF_INET)
|
||||
? ip_masklen(mask->sin.sin_addr)
|
||||
: ip6_masklen(mask->sin6.sin6_addr);
|
||||
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,
|
||||
(ifnlen ? ifname : "(nil)"),
|
||||
rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)),
|
||||
ifm->ifam_flags,
|
||||
sockunion2str(addr, buf[0], sizeof(buf[0])),
|
||||
masklen,
|
||||
sockunion2str(brd, buf[1], sizeof(buf[1])),
|
||||
sockunion2str(&dst, buf[2], sizeof(buf[2])),
|
||||
sockunion2str(&gateway, buf[2],
|
||||
sizeof(buf[2])));
|
||||
ifm->ifam_flags, addr, masklen, brd, &dst,
|
||||
&gateway);
|
||||
} break;
|
||||
default:
|
||||
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. */
|
||||
if (rtm->rtm_version != RTM_VERSION)
|
||||
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);
|
||||
|
||||
/* Be sure structure is cleared */
|
||||
@ -1463,6 +1457,14 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
|
||||
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)
|
||||
{
|
||||
struct zebra_dplane_ctx *ctx;
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
* Called by the dplane pthread to read incoming OS messages and dispatch them.
|
||||
*/
|
||||
int kernel_dplane_read(struct zebra_dplane_info *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -37,11 +37,12 @@
|
||||
#include "zebra/zebra_pbr.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_INTF, "Zebra DPlane Intf");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes");
|
||||
|
||||
#ifndef AOK
|
||||
# define AOK 0
|
||||
@ -402,6 +403,19 @@ struct zebra_dplane_provider {
|
||||
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
|
||||
*/
|
||||
@ -424,6 +438,9 @@ static struct zebra_dplane_globals {
|
||||
/* Ordered list of providers */
|
||||
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 */
|
||||
uint32_t dg_provider_id;
|
||||
|
||||
@ -498,6 +515,9 @@ static struct zebra_dplane_globals {
|
||||
|
||||
} 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
|
||||
*/
|
||||
@ -690,6 +710,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
|
||||
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
/* Maybe free label string, if allocated */
|
||||
if (ctx->u.intf.label != NULL &&
|
||||
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:
|
||||
ret = "GRE_SET";
|
||||
break;
|
||||
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
return "INTF_ADDR_ADD";
|
||||
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
return "INTF_ADDR_DEL";
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1108,6 +1136,21 @@ vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
|
||||
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)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
@ -1154,6 +1197,13 @@ ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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? */
|
||||
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);
|
||||
}
|
||||
|
||||
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 zebra_dplane_ctx *ctx)
|
||||
{
|
||||
@ -1699,6 +1777,14 @@ const struct prefix *dplane_ctx_get_intf_addr(
|
||||
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)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
@ -1711,10 +1797,15 @@ const struct prefix *dplane_ctx_get_intf_dest(
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST)
|
||||
return &(ctx->u.intf.dest_prefix);
|
||||
else
|
||||
return NULL;
|
||||
return &(ctx->u.intf.dest_prefix);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1731,6 +1822,35 @@ const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
|
||||
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 */
|
||||
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.
|
||||
*/
|
||||
if (is_update)
|
||||
zns->netlink_dplane.seq += 2;
|
||||
zns->netlink_dplane_out.seq += 2;
|
||||
else
|
||||
zns->netlink_dplane.seq++;
|
||||
zns->netlink_dplane_out.seq++;
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
return AOK;
|
||||
@ -4709,10 +4829,92 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
|
||||
|
||||
#if defined(HAVE_NETLINK)
|
||||
ns_info->is_cmd = true;
|
||||
ns_info->nls = zns->netlink_dplane;
|
||||
ns_info->nls = zns->netlink_dplane_out;
|
||||
#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
|
||||
* for the dataplane pthread.
|
||||
@ -4878,6 +5080,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
|
||||
dplane_ctx_get_ifname(ctx),
|
||||
ctx->u.gre.link_ifindex);
|
||||
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:
|
||||
break;
|
||||
|
||||
/* TODO -- error counters for incoming events? */
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NONE:
|
||||
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
|
||||
@ -5355,9 +5570,21 @@ done:
|
||||
*/
|
||||
static int dplane_check_shutdown_status(struct thread *event)
|
||||
{
|
||||
struct dplane_zns_info *zi;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_DPLANE)
|
||||
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()) {
|
||||
/* Reschedule dplane check on a short timer */
|
||||
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_providers_q);
|
||||
zns_info_list_init(&zdplane_info.dg_zns_list);
|
||||
|
||||
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)
|
||||
{
|
||||
struct dplane_zns_info *zi;
|
||||
struct zebra_dplane_provider *prov;
|
||||
struct frr_pthread_attr pattr = {
|
||||
.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,
|
||||
&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 */
|
||||
|
||||
DPLANE_LOCK();
|
||||
|
@ -63,6 +63,12 @@ zebra_dplane_info_from_zns(struct zebra_dplane_info *zns_info,
|
||||
#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.
|
||||
*/
|
||||
@ -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 {
|
||||
DPLANE_OP_NONE = 0,
|
||||
@ -172,6 +178,10 @@ enum dplane_op_e {
|
||||
|
||||
DPLANE_OP_NEIGH_TABLE_UPDATE,
|
||||
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);
|
||||
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);
|
||||
void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex);
|
||||
|
||||
/* Retrieve last/current provider id */
|
||||
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);
|
||||
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);
|
||||
void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
|
||||
uint32_t id);
|
||||
@ -441,17 +456,26 @@ dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/* Accessors for interface information */
|
||||
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? */
|
||||
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);
|
||||
void dplane_ctx_intf_set_secondary(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 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);
|
||||
const struct prefix *dplane_ctx_get_intf_dest(
|
||||
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);
|
||||
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 */
|
||||
vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx);
|
||||
|
@ -281,7 +281,7 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
|
||||
ri->af = rib_dest_af(dest);
|
||||
|
||||
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->rtm_table = table_info->table_id;
|
||||
|
@ -2987,6 +2987,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
case DPLANE_OP_IPSET_ENTRY_DELETE:
|
||||
case DPLANE_OP_NEIGH_TABLE_UPDATE:
|
||||
case DPLANE_OP_GRE_SET:
|
||||
case DPLANE_OP_INTF_ADDR_ADD:
|
||||
case DPLANE_OP_INTF_ADDR_DEL:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -123,6 +123,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
||||
zns->ns_id = ns_id;
|
||||
|
||||
kernel_init(zns);
|
||||
zebra_dplane_ns_enable(zns, true);
|
||||
interface_list(zns);
|
||||
route_read(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);
|
||||
|
||||
zebra_dplane_ns_enable(zns, false /*Disable*/);
|
||||
|
||||
kernel_terminate(zns, complete);
|
||||
|
||||
table_manager_disable(zns->ns_id);
|
||||
|
@ -52,7 +52,12 @@ struct zebra_ns {
|
||||
#ifdef HAVE_NETLINK
|
||||
struct nlsock netlink; /* kernel messages */
|
||||
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;
|
||||
#endif
|
||||
|
||||
|
@ -4209,6 +4209,11 @@ static int rib_process_dplane_results(struct thread *thread)
|
||||
zebra_pbr_dplane_result(ctx);
|
||||
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 */
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
|
Loading…
Reference in New Issue
Block a user