summaryrefslogtreecommitdiff
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r--zebra/rt_netlink.c568
1 files changed, 406 insertions, 162 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 40a7eeba8e..4a6839d3b1 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -68,11 +68,27 @@
#include "zebra/zebra_mroute.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_errors.h"
+#include "zebra/zebra_evpn_mh.h"
#ifndef AF_MPLS
#define AF_MPLS 28
#endif
+/* Re-defining as I am unable to include <linux/if_bridge.h> which has the
+ * UAPI for MAC sync. */
+#ifndef _UAPI_LINUX_IF_BRIDGE_H
+/* FDB notification bits for NDA_NOTIFY:
+ * - BR_FDB_NFY_STATIC - notify on activity/expire even for a static entry
+ * - BR_FDB_NFY_INACTIVE - mark as inactive to avoid double notification,
+ * used with BR_FDB_NFY_STATIC (kernel controlled)
+ */
+enum {
+ BR_FDB_NFY_STATIC,
+ BR_FDB_NFY_INACTIVE,
+ BR_FDB_NFY_MAX
+};
+#endif
+
static vlanid_t filter_vlan = 0;
/* We capture whether the current kernel supports nexthop ids; by
@@ -131,6 +147,8 @@ static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags)
flags |= NTF_EXT_LEARNED;
if (dplane_flags & DPLANE_NTF_ROUTER)
flags |= NTF_ROUTER;
+ if (dplane_flags & DPLANE_NTF_USE)
+ flags |= NTF_USE;
return flags;
}
@@ -150,6 +168,8 @@ static uint16_t neigh_state_to_netlink(uint16_t dplane_state)
state |= NUD_NOARP;
if (dplane_state & DPLANE_NUD_PROBE)
state |= NUD_PROBE;
+ if (dplane_state & DPLANE_NUD_INCOMPLETE)
+ state |= NUD_INCOMPLETE;
return state;
}
@@ -163,7 +183,8 @@ static inline bool is_selfroute(int proto)
|| (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
|| (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
|| (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)
- || (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)) {
+ || (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)
+ || (proto == RTPROT_SRTE)) {
return true;
}
@@ -213,6 +234,9 @@ static inline int zebra2proto(int proto)
case ZEBRA_ROUTE_OPENFABRIC:
proto = RTPROT_OPENFABRIC;
break;
+ case ZEBRA_ROUTE_SRTE:
+ proto = RTPROT_SRTE;
+ break;
case ZEBRA_ROUTE_TABLE:
case ZEBRA_ROUTE_NHG:
proto = RTPROT_ZEBRA;
@@ -278,6 +302,9 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop)
case RTPROT_OPENFABRIC:
proto = ZEBRA_ROUTE_OPENFABRIC;
break;
+ case RTPROT_SRTE:
+ proto = ZEBRA_ROUTE_SRTE;
+ break;
case RTPROT_ZEBRA:
if (is_nexthop) {
proto = ZEBRA_ROUTE_NHG;
@@ -1051,14 +1078,17 @@ static bool _netlink_route_add_gateway_info(uint8_t route_family,
bytelen + 2))
return false;
} else {
- if (gw_family == AF_INET) {
- if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
- &nexthop->gate.ipv4, bytelen))
- return false;
- } else {
- if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
- &nexthop->gate.ipv6, bytelen))
- return false;
+ if (!(nexthop->rparent
+ && IS_MAPPED_IPV6(&nexthop->rparent->gate.ipv6))) {
+ if (gw_family == AF_INET) {
+ if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
+ &nexthop->gate.ipv4, bytelen))
+ return false;
+ } else {
+ if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
+ &nexthop->gate.ipv6, bytelen))
+ return false;
+ }
}
}
@@ -2204,19 +2234,11 @@ nexthop_done:
return NLMSG_ALIGN(req->n.nlmsg_len);
}
-/**
- * kernel_nexthop_update() - Update/delete a nexthop from the kernel
- *
- * @ctx: Dataplane context
- *
- * Return: Dataplane result flag
- */
-enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
+static ssize_t netlink_nexthop_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
{
enum dplane_op_e op;
int cmd = 0;
- int ret = 0;
- char buf[NL_PKT_BUF_SIZE];
op = dplane_ctx_get_op(ctx);
if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
@@ -2227,33 +2249,43 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
"Context received for kernel nexthop update with incorrect OP code (%u)",
op);
- return ZEBRA_DPLANE_REQUEST_FAILURE;
+ return -1;
}
+ return netlink_nexthop_msg_encode(cmd, ctx, buf, buflen);
+}
+
+enum netlink_msg_status
+netlink_put_nexthop_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
/* Nothing to do if the kernel doesn't support nexthop objects */
if (!kernel_nexthops_supported())
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ return FRR_NETLINK_SUCCESS;
- if (netlink_nexthop_msg_encode(cmd, ctx, buf, sizeof(buf)) > 0)
- ret = netlink_talk_info(netlink_talk_filter, (void *)&buf,
- dplane_ctx_get_ns(ctx), 0);
- else
- ret = 0;
+ return netlink_batch_add_msg(bth, ctx, netlink_nexthop_msg_encoder,
+ false);
+}
- return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
- : ZEBRA_DPLANE_REQUEST_FAILURE);
+static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf,
+ buflen, false, false);
}
-/*
- * Update or delete a prefix from the kernel,
- * using info from a dataplane context.
- */
-enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
+static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf,
+ buflen, false, false);
+}
+
+enum netlink_msg_status
+netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
{
- int cmd, ret;
+ int cmd;
const struct prefix *p = dplane_ctx_get_dest(ctx);
- struct nexthop *nexthop;
- uint8_t nl_pkt[NL_PKT_BUF_SIZE];
if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
cmd = RTM_DELROUTE;
@@ -2263,7 +2295,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
if (p->family == AF_INET || v6_rr_semantics) {
/* Single 'replace' operation */
- cmd = RTM_NEWROUTE;
/*
* With route replace semantics in place
@@ -2273,17 +2304,11 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
* route should cause us to withdraw from
* the kernel the old non-system route
*/
- if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) &&
- !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
- if (netlink_route_multipath_msg_encode(
- RTM_DELROUTE, ctx, nl_pkt,
- sizeof(nl_pkt), false, false)
- > 0)
- netlink_talk_info(
- netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
- }
+ if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))
+ && !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
+ netlink_batch_add_msg(
+ bth, ctx, netlink_delroute_msg_encoder,
+ true);
} else {
/*
* So v6 route replace semantics are not in
@@ -2297,51 +2322,24 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
* of the route delete. If that happens yeah we're
* screwed.
*/
- if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
- if (netlink_route_multipath_msg_encode(
- RTM_DELROUTE, ctx, nl_pkt,
- sizeof(nl_pkt), false, false)
- > 0)
- netlink_talk_info(
- netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
- }
- cmd = RTM_NEWROUTE;
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
+ netlink_batch_add_msg(
+ bth, ctx, netlink_delroute_msg_encoder,
+ true);
}
- } else {
- return ZEBRA_DPLANE_REQUEST_FAILURE;
- }
-
- if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
- if (netlink_route_multipath_msg_encode(
- cmd, ctx, nl_pkt, sizeof(nl_pkt), false, false)
- > 0)
- ret = netlink_talk_info(netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
- else
- ret = -1;
-
+ cmd = RTM_NEWROUTE;
} else
- ret = 0;
- if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
- /* Update installed nexthops to signal which have been
- * installed.
- */
- for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
+ return FRR_NETLINK_ERROR;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
- }
- }
+ if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
+ return FRR_NETLINK_SUCCESS;
- return (ret == 0 ?
- ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
+ return netlink_batch_add_msg(bth, ctx,
+ cmd == RTM_NEWROUTE
+ ? netlink_newroute_msg_encoder
+ : netlink_delroute_msg_encoder,
+ false);
}
/**
@@ -2518,6 +2516,15 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* We use the ID key'd nhg table for kernel updates */
id = *((uint32_t *)RTA_DATA(tb[NHA_ID]));
+ if (zebra_evpn_mh_is_fdb_nh(id)) {
+ /* If this is a L2 NH just ignore it */
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
+ zlog_debug("Ignore kernel update (%u) for fdb-nh 0x%x",
+ h->nlmsg_type, id);
+ }
+ return 0;
+ }
+
family = nhm->nh_family;
afi = family2afi(family);
@@ -2673,7 +2680,9 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
static ssize_t netlink_neigh_update_msg_encode(
const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac,
const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type,
- uint8_t flags, uint16_t state, void *data, size_t datalen)
+ uint8_t flags, uint16_t state, uint32_t nhg_id,
+ bool nfy, uint8_t nfy_flags,
+ void *data, size_t datalen)
{
uint8_t protocol = RTPROT_ZEBRA;
struct {
@@ -2686,7 +2695,7 @@ static ssize_t netlink_neigh_update_msg_encode(
if (datalen < sizeof(*req))
return 0;
- memset(req, 0, datalen);
+ memset(req, 0, sizeof(*req));
op = dplane_ctx_get_op(ctx);
@@ -2703,7 +2712,7 @@ static ssize_t netlink_neigh_update_msg_encode(
req->ndm.ndm_flags = flags;
req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
- if (!nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol,
+ if (!nl_attr_put(&req->n, datalen, NDA_PROTOCOL, &protocol,
sizeof(protocol)))
return 0;
@@ -2712,6 +2721,16 @@ static ssize_t netlink_neigh_update_msg_encode(
return 0;
}
+ if (nhg_id) {
+ if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id))
+ return 0;
+ }
+ if (nfy) {
+ if (!nl_attr_put(&req->n, datalen, NDA_NOTIFY,
+ &nfy_flags, sizeof(nfy_flags)))
+ return 0;
+ }
+
ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len))
return 0;
@@ -2736,22 +2755,16 @@ static ssize_t netlink_neigh_update_msg_encode(
* Add remote VTEP to the flood list for this VxLAN interface (VNI). This
* is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
*/
-static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
- int cmd)
+static ssize_t
+netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd,
+ void *buf, size_t buflen)
{
struct ethaddr dst_mac = {.octet = {0}};
- uint8_t nl_pkt[NL_PKT_BUF_SIZE];
- if (netlink_neigh_update_msg_encode(
- ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
- PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt,
- sizeof(nl_pkt))
- <= 0)
- return -1;
-
- return netlink_talk_info(netlink_talk_filter,
- (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
+ return netlink_neigh_update_msg_encode(
+ ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
+ PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/,
+ false /*nfy*/, 0 /*nfy_flags*/, buf, buflen);
}
#ifndef NDA_RTA
@@ -2774,6 +2787,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
char vid_buf[20];
char dst_buf[30];
bool sticky;
+ bool local_inactive = false;
+ bool dp_static = false;
+ uint32_t nhg_id = 0;
ndm = NLMSG_DATA(h);
@@ -2821,13 +2837,29 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
inet_ntoa(vtep_ip));
}
+ if (tb[NDA_NH_ID])
+ nhg_id = *(uint32_t *)RTA_DATA(tb[NDA_NH_ID]);
+
+ if (ndm->ndm_state & NUD_STALE)
+ local_inactive = true;
+
+ if (tb[NDA_NOTIFY]) {
+ uint8_t nfy_flags;
+
+ dp_static = true;
+ nfy_flags = *(uint8_t *)RTA_DATA(tb[NDA_NOTIFY]);
+ /* local activity has not been detected on the entry */
+ if (nfy_flags & (1 << BR_FDB_NFY_INACTIVE))
+ local_inactive = true;
+ }
+
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %s%s",
+ zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %s%s nhg %d",
nl_msg_type_to_str(h->nlmsg_type),
ndm->ndm_ifindex, vid_present ? vid_buf : "",
ndm->ndm_state, ndm->ndm_flags,
prefix_mac2str(&mac, buf, sizeof(buf)),
- dst_present ? dst_buf : "");
+ dst_present ? dst_buf : "", nhg_id);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
@@ -2850,7 +2882,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
}
- sticky = !!(ndm->ndm_state & NUD_NOARP);
+ sticky = !!(ndm->ndm_flags & NTF_STICKY);
if (filter_vlan && vid != filter_vlan) {
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2878,7 +2910,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
vid);
return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
- sticky);
+ sticky, local_inactive, dp_static);
}
/* This is a delete notification.
@@ -2891,6 +2923,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
* Note: We will get notifications from both bridge driver and VxLAN
* driver.
*/
+ if (nhg_id)
+ return 0;
+
if (dst_present) {
u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
@@ -3078,9 +3113,8 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
/*
* Netlink-specific handler for MAC updates using dataplane context object.
*/
-ssize_t
-netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
- size_t datalen)
+ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
+ size_t datalen)
{
struct ipaddr vtep_ip;
vlanid_t vid;
@@ -3088,18 +3122,43 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
int cmd;
uint8_t flags;
uint16_t state;
+ uint32_t nhg_id;
+ uint32_t update_flags;
+ bool nfy = false;
+ uint8_t nfy_flags = 0;
cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
? RTM_NEWNEIGH : RTM_DELNEIGH;
- flags = (NTF_SELF | NTF_MASTER);
+ flags = NTF_MASTER;
state = NUD_REACHABLE;
- if (dplane_ctx_mac_is_sticky(ctx))
- state |= NUD_NOARP;
- else
- flags |= NTF_EXT_LEARNED;
+ update_flags = dplane_ctx_mac_get_update_flags(ctx);
+ if (update_flags & DPLANE_MAC_REMOTE) {
+ flags |= NTF_SELF;
+ if (dplane_ctx_mac_is_sticky(ctx))
+ flags |= NTF_STICKY;
+ else
+ flags |= NTF_EXT_LEARNED;
+ /* if it was static-local previously we need to clear the
+ * notify flags on replace with remote
+ */
+ if (update_flags & DPLANE_MAC_WAS_STATIC)
+ nfy = true;
+ } else {
+ /* local mac */
+ if (update_flags & DPLANE_MAC_SET_STATIC) {
+ nfy_flags |= (1 << BR_FDB_NFY_STATIC);
+ state |= NUD_NOARP;
+ }
+ if (update_flags & DPLANE_MAC_SET_INACTIVE)
+ nfy_flags |= (1 << BR_FDB_NFY_INACTIVE);
+
+ nfy = true;
+ }
+
+ nhg_id = dplane_ctx_mac_get_nhg_id(ctx);
vtep_ip.ipaddr_v4 = *(dplane_ctx_mac_get_vtep_ip(ctx));
SET_IPADDR_V4(&vtep_ip);
@@ -3107,6 +3166,7 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
char ipbuf[PREFIX_STRLEN];
char buf[ETHER_ADDR_STRLEN];
char vid_buf[20];
+ const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx);
vid = dplane_ctx_mac_get_vlan(ctx);
if (vid > 0)
@@ -3114,20 +3174,30 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
else
vid_buf[0] = '\0';
- const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx);
-
- zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s",
+ zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s nhg %u%s%s%s%s%s",
nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE),
dplane_ctx_get_ifname(ctx),
dplane_ctx_get_ifindex(ctx), vid_buf,
dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
prefix_mac2str(mac, buf, sizeof(buf)),
- ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)));
+ ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)),
+ nhg_id,
+ (update_flags &
+ DPLANE_MAC_REMOTE) ? " rem" : "",
+ (update_flags &
+ DPLANE_MAC_WAS_STATIC) ? " clr_sync" : "",
+ (update_flags &
+ DPLANE_MAC_SET_STATIC) ? " static" : "",
+ (update_flags &
+ DPLANE_MAC_SET_INACTIVE) ? " inactive" : "",
+ (nfy &
+ DPLANE_MAC_SET_INACTIVE) ? " nfy" : "");
}
total = netlink_neigh_update_msg_encode(
ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true,
- AF_BRIDGE, 0, flags, state, data, datalen);
+ AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags,
+ data, datalen);
return total;
}
@@ -3161,6 +3231,8 @@ static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif,
#define NUD_VALID \
(NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE \
| NUD_DELAY)
+#define NUD_LOCAL_ACTIVE \
+ (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)
static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
{
@@ -3177,6 +3249,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
int mac_present = 0;
bool is_ext;
bool is_router;
+ bool local_inactive;
ndm = NLMSG_DATA(h);
@@ -3286,10 +3359,17 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
* result
* in re-adding the neighbor if it is a valid "remote" neighbor.
*/
- if (ndm->ndm_state & NUD_VALID)
+ if (ndm->ndm_state & NUD_VALID) {
+ local_inactive = !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
+
+ /* XXX - populate dp-static based on the sync flags
+ * in the kernel
+ */
return zebra_vxlan_handle_kernel_neigh_update(
ifp, link_if, &ip, &mac, ndm->ndm_state,
- is_ext, is_router);
+ is_ext, is_router, local_inactive,
+ false /* dp_static */);
+ }
return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
}
@@ -3510,15 +3590,14 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
/*
* Utility neighbor-update function, using info from dplane context.
*/
-static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
- int cmd)
+static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
+ int cmd, void *buf, size_t buflen)
{
const struct ipaddr *ip;
const struct ethaddr *mac;
uint8_t flags;
uint16_t state;
uint8_t family;
- uint8_t nl_pkt[NL_PKT_BUF_SIZE];
ip = dplane_ctx_neigh_get_ipaddr(ctx);
mac = dplane_ctx_neigh_get_mac(ctx);
@@ -3543,59 +3622,56 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
flags, state);
}
- if (netlink_neigh_update_msg_encode(ctx, cmd, mac, ip, true, family,
- RTN_UNICAST, flags, state, nl_pkt,
- sizeof(nl_pkt))
- <= 0)
- return -1;
-
- return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
+ return netlink_neigh_update_msg_encode(
+ ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state,
+ 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, buf, buflen);
}
-/*
- * Update MAC, using dataplane context object.
- */
-enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
+static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
{
- uint8_t nl_pkt[NL_PKT_BUF_SIZE];
- ssize_t rv;
-
- rv = netlink_macfdb_update_ctx(ctx, nl_pkt, sizeof(nl_pkt));
- if (rv <= 0)
- return ZEBRA_DPLANE_REQUEST_FAILURE;
-
- rv = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
- dplane_ctx_get_ns(ctx), 0);
-
- return rv == 0 ?
- ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE;
-}
-
-enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
-{
- int ret = -1;
+ ssize_t ret;
switch (dplane_ctx_get_op(ctx)) {
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
- ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH);
+ case DPLANE_OP_NEIGH_DISCOVER:
+ ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
break;
case DPLANE_OP_NEIGH_DELETE:
- ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH);
+ ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen);
break;
case DPLANE_OP_VTEP_ADD:
- ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH);
+ ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf,
+ buflen);
break;
case DPLANE_OP_VTEP_DELETE:
- ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH);
+ ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf,
+ buflen);
break;
default:
- break;
+ ret = -1;
}
- return (ret == 0 ?
- ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
+ return ret;
+}
+
+/*
+ * Update MAC, using dataplane context object.
+ */
+
+enum netlink_msg_status netlink_put_mac_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ return netlink_batch_add_msg(bth, ctx, netlink_macfdb_update_ctx,
+ false);
+}
+
+enum netlink_msg_status
+netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
+{
+ return netlink_batch_add_msg(bth, ctx, netlink_neigh_msg_encoder,
+ false);
}
/*
@@ -3754,4 +3830,172 @@ ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
return NLMSG_ALIGN(req->n.nlmsg_len);
}
+
+/****************************************************************************
+* This code was developed in a branch that didn't have dplane APIs for
+* MAC updates. Hence the use of the legacy style. It will be moved to
+* the new dplane style pre-merge to master. XXX
+*/
+static int netlink_fdb_nh_update(uint32_t nh_id, struct in_addr vtep_ip)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nhmsg nhm;
+ char buf[256];
+ } req;
+ int cmd = RTM_NEWNEXTHOP;
+ struct zebra_vrf *zvrf;
+ struct zebra_ns *zns;
+
+ zvrf = zebra_vrf_get_evpn();
+ if (!zvrf)
+ return -1;
+ zns = zvrf->zns;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
+ req.n.nlmsg_type = cmd;
+ req.nhm.nh_family = AF_INET;
+
+ if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id))
+ return -1;
+ if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0))
+ return -1;
+ if (!nl_attr_put(&req.n, sizeof(req), NHA_GATEWAY,
+ &vtep_ip, IPV4_MAX_BYTELEN))
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
+ zlog_debug("Tx %s fdb-nh 0x%x %s",
+ nl_msg_type_to_str(cmd), nh_id, inet_ntoa(vtep_ip));
+ }
+
+ return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
+ 0);
+}
+
+static int netlink_fdb_nh_del(uint32_t nh_id)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nhmsg nhm;
+ char buf[256];
+ } req;
+ int cmd = RTM_DELNEXTHOP;
+ struct zebra_vrf *zvrf;
+ struct zebra_ns *zns;
+
+ zvrf = zebra_vrf_get_evpn();
+ if (!zvrf)
+ return -1;
+ zns = zvrf->zns;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = cmd;
+ req.nhm.nh_family = AF_UNSPEC;
+
+ if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id))
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
+ zlog_debug("Tx %s fdb-nh 0x%x",
+ nl_msg_type_to_str(cmd), nh_id);
+ }
+
+ return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
+ 0);
+}
+
+static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt,
+ struct nh_grp *nh_ids)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nhmsg nhm;
+ char buf[256];
+ } req;
+ int cmd = RTM_NEWNEXTHOP;
+ struct zebra_vrf *zvrf;
+ struct zebra_ns *zns;
+ struct nexthop_grp grp[nh_cnt];
+ uint32_t i;
+
+ zvrf = zebra_vrf_get_evpn();
+ if (!zvrf)
+ return -1;
+ zns = zvrf->zns;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
+ req.n.nlmsg_type = cmd;
+ req.nhm.nh_family = AF_UNSPEC;
+
+ if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nhg_id))
+ return -1;
+ if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0))
+ return -1;
+ memset(&grp, 0, sizeof(grp));
+ for (i = 0; i < nh_cnt; ++i) {
+ grp[i].id = nh_ids[i].id;
+ grp[i].weight = nh_ids[i].weight;
+ }
+ if (!nl_attr_put(&req.n, sizeof(req), NHA_GROUP,
+ grp, nh_cnt * sizeof(struct nexthop_grp)))
+ return -1;
+
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
+ char vtep_str[ES_VTEP_LIST_STR_SZ];
+ char nh_buf[16];
+
+ vtep_str[0] = '\0';
+ for (i = 0; i < nh_cnt; ++i) {
+ snprintf(nh_buf, sizeof(nh_buf), "%u ",
+ grp[i].id);
+ strlcat(vtep_str, nh_buf, sizeof(vtep_str));
+ }
+
+ zlog_debug("Tx %s fdb-nhg 0x%x %s",
+ nl_msg_type_to_str(cmd), nhg_id, vtep_str);
+ }
+
+ return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
+ 0);
+}
+
+static int netlink_fdb_nhg_del(uint32_t nhg_id)
+{
+ return netlink_fdb_nh_del(nhg_id);
+}
+
+int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip)
+{
+ return netlink_fdb_nh_update(nh_id, vtep_ip);
+}
+
+int kernel_del_mac_nh(uint32_t nh_id)
+{
+ return netlink_fdb_nh_del(nh_id);
+}
+
+int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
+ struct nh_grp *nh_ids)
+{
+ return netlink_fdb_nhg_update(nhg_id, nh_cnt, nh_ids);
+}
+
+int kernel_del_mac_nhg(uint32_t nhg_id)
+{
+ return netlink_fdb_nhg_del(nhg_id);
+}
+
#endif /* HAVE_NETLINK */