]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: Provide neigh-mac tie-in in zebra
authorMitesh Kanjariya <mitesh@marvel-07.cumulusnetworks.com>
Wed, 5 Jul 2017 22:03:14 +0000 (15:03 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 8 Aug 2017 14:28:51 +0000 (10:28 -0400)
Currently, FRR does not do any linking between local MACs and neighbors.
We found this necessary when dealing with centralized GW. A neigh is considered local only when the mac is learnt locally as well.

Ticket: CM-16544
Review: CCR-6388
Unit-test: Manual/Evpn-Smoke

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
zebra/zebra_vxlan.c
zebra/zebra_vxlan_private.h

index cb555ff1ee2d706f83b073f93cffaebcd70ffaa3..393ac997b329ab912bd506b60140facaa50b1ba3 100644 (file)
@@ -74,7 +74,8 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
 static unsigned int neigh_hash_keymake(void *p);
 static int neigh_cmp(const void *p1, const void *p2);
 static void *zvni_neigh_alloc(void *p);
-static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip);
+static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
+                                    struct ethaddr *mac);
 static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n);
 static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg);
 static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall,
@@ -200,10 +201,13 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
                json_object_string_add(json, "mac", buf1);
        }
        if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
-               if (json == NULL)
+               if (json == NULL) {
                        vty_out(vty, " Remote VTEP: %s",
                                inet_ntoa(n->r_vtep_ip));
-               else
+                       vty_out(vty, " State: %s", IS_ZEBRA_NEIGH_ACTIVE(n)
+                                                          ? "Active"
+                                                          : "Inactive");
+               } else
                        json_object_string_add(json, "remoteVtep",
                                               inet_ntoa(n->r_vtep_ip));
        }
@@ -353,7 +357,10 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
 static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
 {
        struct vty *vty;
+       zebra_neigh_t *n = NULL;
+       struct listnode *node = NULL;
        char buf1[20];
+       char buf2[INET6_ADDRSTRLEN];
 
        vty = (struct vty *)ctxt;
        vty_out(vty, "MAC: %s",
@@ -371,11 +378,30 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
                vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex);
                if (mac->fwd_info.local.vid)
                        vty_out(vty, " VLAN: %u", mac->fwd_info.local.vid);
-       } else {
+       } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
                vty_out(vty, " Remote VTEP: %s",
                        inet_ntoa(mac->fwd_info.r_vtep_ip));
+       } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+               vty_out(vty, " Auto Mac ");
+       }
+       vty_out(vty, " ARP ref: %u\n", mac->neigh_refcnt);
+
+       /* print all the associated neigh */
+       vty_out(vty, " Neighbors:\n");
+       if (!listcount(mac->neigh_list))
+               vty_out(vty, "    No Neighbors\n");
+       else {
+               for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
+                       vty_out(vty, "    %s %s\n",
+                               ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+                               CHECK_FLAG(n->flags, ZEBRA_MAC_LOCAL)
+                                       ? (IS_ZEBRA_NEIGH_ACTIVE(n)
+                                                  ? "Active"
+                                                  : "Inactive")
+                                       : "");
+               }
        }
-       vty_out(vty, " ARP ref: %u", mac->neigh_refcnt);
+
        vty_out(vty, "\n");
 }
 
@@ -432,7 +458,7 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
                else
                        json_object_object_add(json_mac_hdr, buf1, json_mac);
                wctx->count++;
-       } else {
+       } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
                if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) {
                        if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
                                           &wctx->r_vtep_ip)) {
@@ -789,16 +815,26 @@ static void *zvni_neigh_alloc(void *p)
 /*
  * Add neighbor entry.
  */
-static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip)
+static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
+                                    struct ethaddr *mac)
 {
        zebra_neigh_t tmp_n;
        zebra_neigh_t *n = NULL;
+       zebra_mac_t *zmac = NULL;
 
        memset(&tmp_n, 0, sizeof(zebra_neigh_t));
        memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
        n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc);
        assert(n);
 
+       memcpy(&n->emac, mac, ETH_ALEN);
+       n->state = ZEBRA_NEIGH_INACTIVE;
+
+       /* Associate the neigh to mac */
+       zmac = zvni_mac_lookup(zvni, mac);
+       if (zmac)
+               listnode_add_sort(zmac->neigh_list, n);
+
        return n;
 }
 
@@ -808,6 +844,11 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip)
 static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
 {
        zebra_neigh_t *tmp_n;
+       zebra_mac_t *zmac = NULL;
+
+       zmac = zvni_mac_lookup(zvni, &n->emac);
+       if (zmac)
+               listnode_delete(zmac->neigh_list, n);
 
        /* Free the VNI hash entry and allocated memory. */
        tmp_n = hash_release(zvni->neigh_table, n);
@@ -907,6 +948,146 @@ static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
        return n;
 }
 
+/* Process all neigh associated to a mac upon local mac add event */
+static void zvni_process_neigh_on_local_mac_add(struct zebra_vrf *zvrf,
+                                               zebra_vni_t *zvni,
+                                               zebra_mac_t *zmac)
+{
+       zebra_neigh_t *n = NULL;
+       struct listnode *node = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+
+       for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+               if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+                       /* MAC is learnt locally, program all inactive neigh
+                        * pointing to this mac */
+                       if (IS_ZEBRA_NEIGH_INACTIVE(n)) {
+                               if (IS_ZEBRA_DEBUG_VXLAN)
+                                       zlog_debug(
+                                               "%u: neigh %s (MAC %s) on VNI %u is now ACTIVE",
+                                               zvrf_id(zvrf),
+                                               ipaddr2str(&n->ip, buf2,
+                                                          sizeof(buf2)),
+                                               prefix_mac2str(&n->emac, buf,
+                                                              sizeof(buf)),
+                                               zvni->vni);
+
+                               ZEBRA_NEIGH_SET_ACTIVE(n);
+                               zvni_neigh_send_add_to_client(
+                                       zvrf, zvni->vni, &n->ip, &n->emac, 0);
+                       } else {
+                               if (IS_ZEBRA_DEBUG_VXLAN)
+                                       zlog_debug(
+                                               "%u: neigh %s (MAC %s) on VNI %u should NOT be ACTIVE",
+                                               zvrf_id(zvrf),
+                                               ipaddr2str(&n->ip, buf2,
+                                                          sizeof(buf2)),
+                                               prefix_mac2str(&n->emac, buf,
+                                                              sizeof(buf)),
+                                               zvni->vni);
+                       }
+               } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+                       /* TODO: assume the neigh has moved too ?? */
+               }
+       }
+}
+
+/* Process all neigh associated to a mac upon local mac del event */
+static void zvni_process_neigh_on_local_mac_del(struct zebra_vrf *zvrf,
+                                               zebra_vni_t *zvni,
+                                               zebra_mac_t *zmac)
+{
+       zebra_neigh_t *n = NULL;
+       struct listnode *node = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+
+       for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+               if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+                       if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
+                               if (IS_ZEBRA_DEBUG_VXLAN)
+                                       zlog_debug(
+                                               "%u: neigh %s (MAC %s) on VNI %u is now INACTIVE",
+                                               zvrf_id(zvrf),
+                                               ipaddr2str(&n->ip, buf2,
+                                                          sizeof(buf2)),
+                                               prefix_mac2str(&n->emac, buf,
+                                                              sizeof(buf)),
+                                               zvni->vni);
+
+                               ZEBRA_NEIGH_SET_INACTIVE(n);
+                               zvni_neigh_send_del_to_client(
+                                       zvrf, zvni->vni, &n->ip, &n->emac, 0);
+                       }
+               } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_err(
+                                       "%u: local MAC %s getting deleted on VNI %u has remote neigh %s",
+                                       zvrf_id(zvrf),
+                                       prefix_mac2str(&n->emac, buf,
+                                                      sizeof(buf)),
+                                       zvni->vni,
+                                       ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+               }
+       }
+}
+
+/* process all neigh associated to a mac entry upon remote mac add */
+static void zvni_process_neigh_on_remote_mac_add(struct zebra_vrf *zvrf,
+                                                zebra_vni_t *zvni,
+                                                zebra_mac_t *zmac)
+{
+       zebra_neigh_t *n = NULL;
+       struct listnode *node = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+
+       for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+               if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+                       if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
+                               if (IS_ZEBRA_DEBUG_VXLAN)
+                                       zlog_debug(
+                                               "%u: neigh %s (MAC %s) on VNI %u INACTIVE",
+                                               zvrf_id(zvrf),
+                                               ipaddr2str(&n->ip, buf2,
+                                                          sizeof(buf2)),
+                                               prefix_mac2str(&n->emac, buf,
+                                                              sizeof(buf)),
+                                               zvni->vni);
+
+                               ZEBRA_NEIGH_SET_INACTIVE(n);
+                               zvni_neigh_send_del_to_client(
+                                       zvrf, zvni->vni, &n->ip, &n->emac, 0);
+                       }
+               }
+       }
+}
+
+/* process all neigh associated to mac entry upon remote mac del */
+static void zvni_process_neigh_on_remote_mac_del(struct zebra_vrf *zvrf,
+                                                zebra_vni_t *zvni,
+                                                zebra_mac_t *zmac)
+{
+       zebra_neigh_t *n = NULL;
+       struct listnode *node = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+
+       for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+               if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_err(
+                                       "%u: remote  MAC %s getting deleted on VNI %u has local neigh %s",
+                                       zvrf_id(zvrf),
+                                       prefix_mac2str(&n->emac, buf,
+                                                      sizeof(buf)),
+                                       zvni->vni,
+                                       ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+               }
+       }
+}
+
 /*
  * Inform BGP about local neighbor addition.
  */
@@ -1153,7 +1334,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
 
        n = zvni_neigh_lookup(zvni, ip);
        if (!n) {
-               n = zvni_neigh_add(zvni, ip);
+               n = zvni_neigh_add(zvni, ip, macaddr);
                if (!n) {
                        zlog_err(
                                "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
@@ -1366,6 +1547,9 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
        mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
        assert(mac);
 
+       mac->neigh_list = list_new();
+       mac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp;
+
        return mac;
 }
 
@@ -1376,6 +1560,8 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
 {
        zebra_mac_t *tmp_mac;
 
+       list_delete(mac->neigh_list);
+
        /* Free the VNI hash entry and allocated memory. */
        tmp_mac = hash_release(zvni->mac_table, mac);
        if (tmp_mac)
@@ -2599,6 +2785,8 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
        zebra_neigh_t *n;
        struct zebra_vrf *zvrf;
        char buf[INET6_ADDRSTRLEN];
+       char buf2[ETHER_ADDR_STRLEN];
+       zebra_mac_t *zmac;
 
        /* We are only interested in neighbors on an SVI that resides on top
         * of a VxLAN bridge.
@@ -2623,6 +2811,18 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
        if (!n)
                return 0;
 
+       zmac = zvni_mac_lookup(zvni, &n->emac);
+       if (!zmac) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_err(
+                               "%u: trying to del a neigh %s without a mac %s on VNI %u",
+                               ifp->vrf_id, ipaddr2str(ip, buf, sizeof(buf)),
+                               prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
+                               zvni->vni);
+
+               return 0;
+       }
+
        /* If it is a remote entry, the kernel has aged this out or someone has
         * deleted it, it needs to be re-installed as Quagga is the owner.
         */
@@ -2636,11 +2836,18 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
        assert(zvrf);
 
        /* Remove neighbor from BGP. */
-       zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, 0);
+       if (IS_ZEBRA_NEIGH_ACTIVE(n))
+               zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac,
+                                             0);
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
 
+       /* see if the AUTO mac needs to be deleted */
+       if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
+           || !listcount(zmac->neigh_list))
+               zvni_mac_del(zvni, zmac);
+
        return 0;
 }
 
@@ -2657,6 +2864,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
        zebra_vni_t *zvni;
        zebra_neigh_t *n;
        struct zebra_vrf *zvrf;
+       zebra_mac_t *zmac;
        char buf[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
        int send_upd = 1, send_del = 0;
@@ -2681,6 +2889,30 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
                        ifp->ifindex, state, ext_learned ? "ext-learned " : "",
                        zvni->vni);
 
+       /* create a dummy MAC if the MAC is not already present */
+       zmac = zvni_mac_lookup(zvni, macaddr);
+       if (!zmac) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "%u: AUTO MAC %s created for neigh %s on VNI %u",
+                               ifp->vrf_id,
+                               prefix_mac2str(macaddr, buf, sizeof(buf)),
+                               ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+
+               zmac = zvni_mac_add(zvni, macaddr);
+               if (!zmac) {
+                       zlog_warn("%u:Failed to add MAC %s VNI %u",
+                                 zvrf_id(zvrf),
+                                 prefix_mac2str(macaddr, buf, sizeof(buf)),
+                                 zvni->vni);
+                       return -1;
+               }
+
+               memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
+               memset(&zmac->flags, 0, sizeof(u_int32_t));
+               SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+       }
+
        /* If same entry already exists, it might be a change or it might be a
         * move from remote to local.
         */
@@ -2716,7 +2948,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
                        n->r_vtep_ip.s_addr = 0;
                }
        } else {
-               n = zvni_neigh_add(zvni, ip);
+               n = zvni_neigh_add(zvni, ip, macaddr);
                if (!n) {
                        zlog_err(
                                "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
@@ -2734,13 +2966,34 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
 
        /* Set "local" forwarding info. */
        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
-       memcpy(&n->emac, macaddr, ETH_ALEN);
        n->ifindex = ifp->ifindex;
 
+       /* Before we program this in BGP, we need to check if MAC is locally
+        * learnt as well */
+       if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "%u: Skipping neigh %s add to client as MAC %s is not local on VNI %u",
+                               ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+                               prefix_mac2str(macaddr, buf, sizeof(buf)),
+                               zvni->vni);
+
+               return 0;
+       }
+
        /* Inform BGP if required. */
-       if (send_upd)
+       if (send_upd) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "%u: neigh %s (MAC %s) is now ACTIVE on VNI %u",
+                               ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+                               prefix_mac2str(macaddr, buf, sizeof(buf)),
+                               zvni->vni);
+
+               ZEBRA_NEIGH_SET_ACTIVE(n);
                return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip,
                                                     macaddr, 0);
+       }
 
        return 0;
 }
@@ -2868,6 +3121,9 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length,
                        }
                } else {
                        if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+                               zvni_process_neigh_on_remote_mac_del(zvrf, zvni,
+                                                                    mac);
+
                                if (!mac->neigh_refcnt) {
                                        zvni_mac_uninstall(zvni, mac, 0);
                                        zvni_mac_del(zvni, mac);
@@ -3024,6 +3280,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
                        else
                                UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
 
+                       zvni_process_neigh_on_remote_mac_add(zvrf, zvni, mac);
+
                        /* Install the entry. */
                        zvni_mac_install(zvni, mac);
                }
@@ -3047,7 +3305,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
 
                if (update_neigh) {
                        if (!n) {
-                               n = zvni_neigh_add(zvni, &ip);
+                               n = zvni_neigh_add(zvni, &ip, &macaddr);
                                if (!n) {
                                        zlog_warn(
                                                "%u:Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
@@ -3070,12 +3328,12 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
                                if (old_mac)
                                        zvni_deref_ip2mac(zvni, old_mac, 1);
                                mac->neigh_refcnt++;
+                               memcpy(&n->emac, &macaddr, ETH_ALEN);
                        }
 
                        /* Set "remote" forwarding info. */
                        UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
                        /* TODO: Handle MAC change. */
-                       memcpy(&n->emac, &macaddr, ETH_ALEN);
                        n->r_vtep_ip = vtep_ip;
                        SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
 
@@ -3143,8 +3401,16 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
        zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr,
                                    (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
 
-       /* Delete this MAC entry. */
-       zvni_mac_del(zvni, mac);
+       /*
+        * If there are no neigh associated with the mac delete the mac
+        * else mark it as AUTO for forward reference
+        */
+       if (!listcount(mac->neigh_list)) {
+               zvni_mac_del(zvni, mac);
+       } else {
+               UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+               SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+       }
 
        return 0;
 }
@@ -3251,8 +3517,19 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
        zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr,
                                    (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
 
-       /* Delete this MAC entry. */
-       zvni_mac_del(zvni, mac);
+       /* Update all the neigh entries associated with this mac */
+       zvni_process_neigh_on_local_mac_del(zvrf, zvni, mac);
+
+       /*
+        * If there are no neigh associated with the mac delete the mac
+        * else mark it as AUTO for forward reference
+        */
+       if (!listcount(mac->neigh_list)) {
+               zvni_mac_del(zvni, mac);
+       } else {
+               UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+               SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+       }
 
        return 0;
 }
@@ -3307,6 +3584,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
                                             ? 1
                                             : 0;
 
+
                        /*
                         * return if nothing has changed.
                         * inform bgp if sticky flag has changed
@@ -3327,11 +3605,12 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
                                                ifp->name, ifp->ifindex, vid,
                                                zvni->vni);
                                return 0;
-                       } else if (mac_sticky != sticky)
+                       } else if (mac_sticky != sticky) {
                                add = 1;
-                       else
+                       } else {
                                add = 0; /* This is an update of local
                                            interface. */
+                       }
                } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
                        /*
                         * If we have already learned the MAC as a remote sticky
@@ -3367,8 +3646,9 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
 
        /* Set "local" forwarding info. */
        UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
-       memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+       UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
        SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+       memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
        mac->fwd_info.local.ifindex = ifp->ifindex;
        mac->fwd_info.local.vid = vid;
 
@@ -3378,10 +3658,11 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
                UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
 
        /* Inform BGP if required. */
-       if (add)
-               return zvni_mac_send_add_to_client(
-                       zvrf, zvni->vni, macaddr,
-                       (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+       if (add) {
+               zvni_process_neigh_on_local_mac_add(zvrf, zvni, mac);
+               return zvni_mac_send_add_to_client(zvrf, zvni->vni, macaddr,
+                                                  sticky);
+       }
 
        return 0;
 }
index 2bf00291e7538acda91f56028e35df1c1ba5991c..8539311eabd9babb430f28b41a216719efd1a779 100644 (file)
@@ -115,6 +115,9 @@ struct zebra_mac_t_ {
        } fwd_info;
 
        u_int32_t neigh_refcnt;
+
+       /* List of neigh associated with this mac */
+       struct list *neigh_list;
 };
 
 /*
@@ -140,6 +143,16 @@ struct mac_walk_ctx {
        struct json_object *json; /* Used for JSON Output */
 };
 
+enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
+
+#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE
+
+#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE
+
+#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE
+
+#define ZEBRA_NEIGH_SET_INACTIVE(n) n->state = ZEBRA_NEIGH_INACTIVE
+
 /*
  * Neighbor hash table.
  *
@@ -162,8 +175,10 @@ struct zebra_neigh_t_ {
        ifindex_t ifindex;
 
        u_int32_t flags;
-#define ZEBRA_NEIGH_LOCAL   0x01
-#define ZEBRA_NEIGH_REMOTE  0x02
+#define ZEBRA_NEIGH_LOCAL     0x01
+#define ZEBRA_NEIGH_REMOTE    0x02
+
+       enum zebra_neigh_state state;
 
        /* Remote VTEP IP - applicable only for remote neighbors. */
        struct in_addr r_vtep_ip;