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.c109
1 files changed, 92 insertions, 17 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 8977074d97..edab6d4646 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -23,6 +23,7 @@
#ifdef HAVE_NETLINK
#include <net/if_arp.h>
+#include <linux/if_bridge.h>
#include <linux/lwtunnel.h>
#include <linux/mpls_iptunnel.h>
#include <linux/neighbour.h>
@@ -2687,6 +2688,7 @@ 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, uint32_t nhg_id,
+ bool nfy, uint8_t nfy_flags,
void *data, size_t datalen)
{
uint8_t protocol = RTPROT_ZEBRA;
@@ -2730,6 +2732,11 @@ static ssize_t netlink_neigh_update_msg_encode(
if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id))
return 0;
}
+ if (nfy) {
+ if (!nl_attr_put32(&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))
@@ -2764,7 +2771,8 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
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),
- 0 /*nhg*/, nl_pkt, sizeof(nl_pkt))
+ 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/,
+ nl_pkt, sizeof(nl_pkt))
<= 0)
return -1;
@@ -2793,6 +2801,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);
@@ -2840,13 +2851,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),
@@ -2869,7 +2896,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)
@@ -2897,7 +2924,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.
@@ -2910,6 +2937,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};
@@ -3108,17 +3138,40 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
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));
@@ -3136,19 +3189,30 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
else
vid_buf[0] = '\0';
- zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s nhg %u",
+ 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)),
- nhg_id);
+ 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, nhg_id, data, datalen);
+ AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags,
+ data, datalen);
return total;
}
@@ -3182,6 +3246,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)
{
@@ -3198,6 +3264,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);
@@ -3307,10 +3374,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);
}
@@ -3565,8 +3639,9 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
}
if (netlink_neigh_update_msg_encode(ctx, cmd, mac, ip, true, family,
- RTN_UNICAST, flags, state, nl_pkt,
- sizeof(nl_pkt))
+ RTN_UNICAST, flags, state,
+ 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/,
+ nl_pkt, sizeof(nl_pkt))
<= 0)
return -1;