mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 22:02:23 +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 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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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 *);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user