]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Readd special flood MAC upon del notification
authorvivek <vivek@cumulusnetworks.com>
Fri, 6 Sep 2019 04:11:07 +0000 (21:11 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 10 Mar 2020 14:02:43 +0000 (10:02 -0400)
Readd the special MAC that represents the flood (head-end replication) entry
for EVPN-VxLAN upon getting a delete notification for it.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Chirag Shah <chirag@cumulusnetworks.com>
Ticket:  CM-25797
Ticket: CM-26238
Testing Done:
1. evpn-min, evpn-smoke - results summarized in CM-25798

zebra/rt_netlink.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h

index 08d229619f94c65abe95953ff18c12adc3d74655..b76eb6be486ec545c29e2f3137dbae443e0a36b9 100644 (file)
@@ -2588,7 +2588,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        struct interface *br_if;
        struct ethaddr mac;
        vlanid_t vid = 0;
-       struct prefix vtep_ip;
+       struct in_addr vtep_ip;
        int vid_present = 0, dst_present = 0;
        char buf[ETHER_ADDR_STRLEN];
        char vid_buf[20];
@@ -2601,66 +2601,25 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        if (!is_evpn_enabled())
                return 0;
 
-       /* The interface should exist. */
-       ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
-                                       ndm->ndm_ifindex);
-       if (!ifp || !ifp->info) {
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("\t%s without associated interface: %u",
-                                  __func__, ndm->ndm_ifindex);
-               return 0;
-       }
-
-       /* The interface should be something we're interested in. */
-       if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) {
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("\t%s Not interested in %s, not a slave",
-                                  __func__, ifp->name);
-               return 0;
-       }
-
-       /* Drop "permanent" entries. */
-       if (ndm->ndm_state & NUD_PERMANENT) {
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("\t%s Entry is PERMANENT, dropping",
-                                  __func__);
-               return 0;
-       }
-
-       zif = (struct zebra_if *)ifp->info;
-       if ((br_if = zif->brslave_info.br_if) == NULL) {
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug(
-                               "%s family %s IF %s(%u) brIF %u - no bridge master",
-                               nl_msg_type_to_str(h->nlmsg_type),
-                               nl_family_to_str(ndm->ndm_family), ifp->name,
-                               ndm->ndm_ifindex,
-                               zif->brslave_info.bridge_ifindex);
-               return 0;
-       }
-
-       /* Parse attributes and extract fields of interest. */
-       memset(tb, 0, sizeof(tb));
+       /* Parse attributes and extract fields of interest. Do basic
+        * validation of the fields.
+        */
+       memset(tb, 0, sizeof tb);
        netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
 
        if (!tb[NDA_LLADDR]) {
                if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR",
+                       zlog_debug("%s AF_BRIDGE IF %u - no LLADDR",
                                   nl_msg_type_to_str(h->nlmsg_type),
-                                  nl_family_to_str(ndm->ndm_family), ifp->name,
-                                  ndm->ndm_ifindex,
-                                  zif->brslave_info.bridge_ifindex);
+                                  ndm->ndm_ifindex);
                return 0;
        }
 
        if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug(
-                               "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu",
-                               nl_msg_type_to_str(h->nlmsg_type),
-                               nl_family_to_str(ndm->ndm_family), ifp->name,
-                               ndm->ndm_ifindex,
-                               zif->brslave_info.bridge_ifindex,
+                               "%s AF_BRIDGE IF %u - LLADDR is not MAC, len %lu",
+                               nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex,
                                (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
                return 0;
        }
@@ -2676,24 +2635,42 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        if (tb[NDA_DST]) {
                /* TODO: Only IPv4 supported now. */
                dst_present = 1;
-               vtep_ip.family = AF_INET;
-               vtep_ip.prefixlen = IPV4_MAX_BITLEN;
-               memcpy(&(vtep_ip.u.prefix4.s_addr), RTA_DATA(tb[NDA_DST]),
+               memcpy(&vtep_ip.s_addr, RTA_DATA(tb[NDA_DST]),
                       IPV4_MAX_BYTELEN);
-               sprintf(dst_buf, " dst %s", inet_ntoa(vtep_ip.u.prefix4));
+               sprintf(dst_buf, " dst %s", inet_ntoa(vtep_ip));
        }
 
-       sticky = !!(ndm->ndm_state & NUD_NOARP);
-
        if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("Rx %s family %s IF %s(%u)%s %sMAC %s%s",
+               zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %s%s",
                           nl_msg_type_to_str(h->nlmsg_type),
-                          nl_family_to_str(ndm->ndm_family), ifp->name,
                           ndm->ndm_ifindex, vid_present ? vid_buf : "",
-                          sticky ? "sticky " : "",
+                          ndm->ndm_state, ndm->ndm_flags,
                           prefix_mac2str(&mac, buf, sizeof(buf)),
                           dst_present ? dst_buf : "");
 
+       /* The interface should exist. */
+       ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
+                                       ndm->ndm_ifindex);
+       if (!ifp || !ifp->info)
+               return 0;
+
+       /* The interface should be something we're interested in. */
+       if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
+               return 0;
+
+       zif = (struct zebra_if *)ifp->info;
+       if ((br_if = zif->brslave_info.br_if) == NULL) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug(
+                               "%s AF_BRIDGE IF %s(%u) brIF %u - no bridge master",
+                               nl_msg_type_to_str(h->nlmsg_type), ifp->name,
+                               ndm->ndm_ifindex,
+                               zif->brslave_info.bridge_ifindex);
+               return 0;
+       }
+
+       sticky = !!(ndm->ndm_state & NUD_NOARP);
+
        if (filter_vlan && vid != filter_vlan) {
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug("\tFiltered due to filter vlan: %d",
@@ -2707,6 +2684,13 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
         * so perform an implicit delete of any local entry (if it exists).
         */
        if (h->nlmsg_type == RTM_NEWNEIGH) {
+                /* Drop "permanent" entries. */
+                if (ndm->ndm_state & NUD_PERMANENT) {
+                       if (IS_ZEBRA_DEBUG_KERNEL)
+                               zlog_debug("\tDropping entry because of NUD_PERMANENT");
+                        return 0;
+               }
+
                if (IS_ZEBRA_IF_VXLAN(ifp))
                        return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac,
                                                               vid);
@@ -2716,16 +2700,20 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        }
 
        /* This is a delete notification.
+        * Ignore the notification with IP dest as it may just signify that the
+        * MAC has moved from remote to local. The exception is the special
+        * all-zeros MAC that represents the BUM flooding entry; we may have
+        * to readd it. Otherwise,
         *  1. For a MAC over VxLan, check if it needs to be refreshed(readded)
         *  2. For a MAC over "local" interface, delete the mac
         * Note: We will get notifications from both bridge driver and VxLAN
         * driver.
-        * Ignore the notification from VxLan driver as it is also generated
-        * when mac moves from remote to local.
         */
        if (dst_present) {
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("\tNo Destination Present");
+               u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+               if (!memcmp(zero_mac, mac.octet, ETH_ALEN))
+                       return zebra_vxlan_check_readd_vtep(ifp, vtep_ip);
                return 0;
        }
 
index dce48d39bd9445705bbacdf9e8eb3d2c230d515a..61865e5baf286f923babe66ccec4c204049523a1 100644 (file)
@@ -7787,6 +7787,52 @@ stream_failure:
        return;
 }
 
+/*
+ * Handle remote vtep delete by kernel; re-add the vtep if we have it
+ */
+int zebra_vxlan_check_readd_vtep(struct interface *ifp,
+                                struct in_addr vtep_ip)
+{
+       struct zebra_if *zif;
+       struct zebra_vrf *zvrf = NULL;
+       struct zebra_l2info_vxlan *vxl;
+       vni_t vni;
+       zebra_vni_t *zvni = NULL;
+       zebra_vtep_t *zvtep = NULL;
+
+       zif = ifp->info;
+       assert(zif);
+       vxl = &zif->l2info.vxl;
+       vni = vxl->vni;
+
+       /* If EVPN is not enabled, nothing to do. */
+       if (!is_evpn_enabled())
+               return 0;
+
+       /* Locate VRF corresponding to interface. */
+       zvrf = vrf_info_lookup(ifp->vrf_id);
+       if (!zvrf)
+               return -1;
+
+       /* Locate hash entry; it is expected to exist. */
+       zvni = zvni_lookup(vni);
+       if (!zvni)
+               return 0;
+
+       /* If the remote vtep entry doesn't exists nothing to do */
+       zvtep = zvni_vtep_find(zvni, &vtep_ip);
+       if (!zvtep)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                       "Del MAC for remote VTEP %s intf %s(%u) VNI %u - readd",
+                       inet_ntoa(vtep_ip), ifp->name, ifp->ifindex, vni);
+
+       zvni_vtep_install(zvni, zvtep);
+       return 0;
+}
+
 /*
  * Handle notification of MAC add/update over VxLAN. If the kernel is notifying
  * us, this must involve a multihoming scenario. Treat this as implicit delete
index b551ba8dff37a2bdf285c9bc4d61b05159726ed4..6ca93f6cb6beb55b3ff2fca1226e4a8714c3f507 100644 (file)
@@ -183,6 +183,8 @@ extern int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
 extern int zebra_vxlan_check_del_local_mac(struct interface *ifp,
                                           struct interface *br_if,
                                           struct ethaddr *mac, vlanid_t vid);
+extern int zebra_vxlan_check_readd_vtep(struct interface *ifp,
+                                       struct in_addr vtep_ip);
 extern int zebra_vxlan_if_up(struct interface *ifp);
 extern int zebra_vxlan_if_down(struct interface *ifp);
 extern int zebra_vxlan_if_add(struct interface *ifp);