]> git.puffer.fish Git - mirror/frr.git/commitdiff
Merge remote-tracking branch 'upstream/master' into evpn-extended-mobility
authorvivek <vivek@cumulusnetworks.com>
Mon, 27 Aug 2018 22:13:30 +0000 (22:13 +0000)
committervivek <vivek@cumulusnetworks.com>
Mon, 27 Aug 2018 22:13:30 +0000 (22:13 +0000)
Conflicts:
zebra/zebra_vxlan.c

1  2 
bgpd/bgp_evpn.c
bgpd/bgp_zebra.c
zebra/zebra_vxlan.c

diff --cc bgpd/bgp_evpn.c
Simple merge
Simple merge
index 79c2bb03e6a5cd8c88877ecbae747cb04e204fb9,b0fc0a39bd85663da4bee0ee5ecf0acc88e5e75e..9dfbfe6ce2b9b311cb0e2fdb67625d8981bff6ed
@@@ -1963,14 -1963,11 +1965,15 @@@ static int zvni_local_neigh_update(zebr
        char buf2[INET6_ADDRSTRLEN];
        zebra_neigh_t *n = NULL;
        zebra_mac_t *zmac = NULL, *old_zmac = NULL;
 +      uint32_t old_mac_seq = 0, mac_new_seq = 0;
 +      bool upd_mac_seq = false;
 +      bool neigh_mac_change = false;
+       bool check_rbit = false;
  
 -      /* create a dummy MAC if the MAC is not already present */
 +      /* Check if the MAC exists. */
        zmac = zvni_mac_lookup(zvni, macaddr);
        if (!zmac) {
 +              /* create a dummy MAC if the MAC is not already present */
                if (IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
                                "AUTO MAC %s created for neigh %s on VNI %u",
                memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
                memset(&zmac->flags, 0, sizeof(uint32_t));
                SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
 +      } else {
 +              if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
 +                      /*
 +                       * We don't change the MAC to local upon a neighbor
 +                       * learn event, we wait for the explicit local MAC
 +                       * learn. However, we have to compute its sequence
 +                       * number in preparation for when it actually turns
 +                       * local.
 +                       */
 +                      upd_mac_seq = true;
 +              }
        }
  
 -      /* If same entry already exists, it might be a change or it might be a
 -       * move from remote to local.
 -       */
 +      /* Check if the neighbor exists. */
        n = zvni_neigh_lookup(zvni, ip);
 -      if (n) {
 +      if (!n) {
 +              /* New neighbor - create */
 +              n = zvni_neigh_add(zvni, ip, macaddr);
 +              if (!n) {
 +                      flog_err(
 +                              ZEBRA_ERR_MAC_ADD_FAILED,
 +                              "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
 +                              ipaddr2str(ip, buf2, sizeof(buf2)),
 +                              prefix_mac2str(macaddr, buf, sizeof(buf)),
 +                              ifp->name, ifp->ifindex, zvni->vni);
 +                      return -1;
 +              }
 +              /* Set "local" forwarding info. */
 +              SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
 +              n->ifindex = ifp->ifindex;
++              check_rbit = true;
 +      } else {
                if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
 -
 +                      /* If there is no MAC change, BGP isn't interested. */
+                       if (router_flag !=
+                           (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
+                                       ? 1 : 0))
+                               check_rbit = true;
                        if (memcmp(n->emac.octet, macaddr->octet,
                                   ETH_ALEN) == 0) {
                                /* Update any params and return - client doesn't
                                 * care about a purely local change.
                                 */
                                n->ifindex = ifp->ifindex;
-                               return 0;
-                       }
+                       } else {
  
-                       /* If the MAC has changed, need to issue a delete
-                        * first as this means a different MACIP route.
-                        * Also, need to do some unlinking/relinking.
-                        * We also need to update the MAC's sequence number
-                        * in different situations.
-                        */
-                       if (IS_ZEBRA_NEIGH_ACTIVE(n))
-                               zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
-                                                             &n->emac, 0);
-                       old_zmac = zvni_mac_lookup(zvni, &n->emac);
-                       if (old_zmac) {
-                               old_mac_seq = CHECK_FLAG(old_zmac->flags,
-                                                        ZEBRA_MAC_REMOTE) ?
-                                       old_zmac->rem_seq : old_zmac->loc_seq;
-                               neigh_mac_change = upd_mac_seq = true;
-                               listnode_delete(old_zmac->neigh_list, n);
-                               zvni_deref_ip2mac(zvni, old_zmac, 0);
-                       }
 -                              /* If the MAC has changed,
 -                               * need to issue a delete first
 -                               * as this means a different MACIP route.
 -                               * Also, need to do some unlinking/relinking.
++                              /* If the MAC has changed, need to issue a
++                               * delete first as this means a different
++                               * MACIP route. Also, need to do some
++                               * unlinking/relinking. We also need to
++                               * update the MAC's sequence number
++                               * in different situations.
+                                */
 -                              zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
 -                                                    &n->emac, 0);
++                              if (IS_ZEBRA_NEIGH_ACTIVE(n))
++                                      zvni_neigh_send_del_to_client(
++                                              zvni->vni, &n->ip, &n->emac, 0);
+                               old_zmac = zvni_mac_lookup(zvni, &n->emac);
+                               if (old_zmac) {
 -                                      listnode_delete(old_zmac->neigh_list, n);
++                                      old_mac_seq =
++                                              CHECK_FLAG(old_zmac->flags,
++                                                         ZEBRA_MAC_REMOTE) ?
++                                                      old_zmac->rem_seq :
++                                                      old_zmac->loc_seq;
++                                      neigh_mac_change = upd_mac_seq = true;
++                                      listnode_delete(
++                                              old_zmac->neigh_list, n);
+                                       zvni_deref_ip2mac(zvni, old_zmac, 0);
+                               }
  
-                       /* Update the forwarding info. */
-                       n->ifindex = ifp->ifindex;
-                       memcpy(&n->emac, macaddr, ETH_ALEN);
+                               /* Update the forwarding info. */
+                               n->ifindex = ifp->ifindex;
+                               memcpy(&n->emac, macaddr, ETH_ALEN);
  
-                       /* Link to new MAC */
-                       listnode_add_sort(zmac->neigh_list, n);
+                               /* Link to new MAC */
+                               listnode_add_sort(zmac->neigh_list, n);
+                       }
  
 -              } else
 -              /* Neighbor has moved from remote to local. */
 -              {
 -                      /* If MAC has changed, do the unlink/link */
 +              } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
 +                      /*
 +                       * Neighbor has moved from remote to local. Its
 +                       * MAC could have also changed as part of the move.
 +                       */
                        if (memcmp(n->emac.octet, macaddr->octet,
                                   ETH_ALEN) != 0) {
                                old_zmac = zvni_mac_lookup(zvni, &n->emac);
                        n->r_vtep_ip.s_addr = 0;
                        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
                        n->ifindex = ifp->ifindex;
+                       check_rbit = true;
                }
 -      } else {
 -              /* New neighbor - create */
 -              n = zvni_neigh_add(zvni, ip, macaddr);
 -              if (!n) {
 -                      flog_err(
 -                              ZEBRA_ERR_MAC_ADD_FAILED,
 -                              "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
 -                              ipaddr2str(ip, buf2, sizeof(buf2)),
 -                              prefix_mac2str(macaddr, buf, sizeof(buf)),
 -                              ifp->name, ifp->ifindex, zvni->vni);
 -                      return -1;
 -              }
 -              /* Set "local" forwarding info. */
 -              SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
 -              n->ifindex = ifp->ifindex;
 -              check_rbit = true;
 +      }
 +
 +      /* If MAC was previously remote, or the neighbor had a different
 +       * MAC earlier, recompute the sequence number.
 +       */
 +      if (upd_mac_seq) {
 +              uint32_t seq1, seq2;
 +
 +              seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) ?
 +                     zmac->rem_seq + 1 : zmac->loc_seq;
 +              seq2 = neigh_mac_change ? old_mac_seq + 1 : 0;
 +              mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ?
 +                            MAX(seq1, seq2) : zmac->loc_seq;
        }
  
+       /*Mark Router flag (R-bit) */
+       if (router_flag)
+               SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+       else
+               UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
        /* Before we program this in BGP, we need to check if MAC is locally
 -       * learnt as well
 +       * learnt. If not, force neighbor to be inactive and reset its seq.
         */
        if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
 -              if (IS_ZEBRA_DEBUG_VXLAN)
 -                      zlog_debug(
 -                              "Skipping neigh %s add to client as MAC %s is not local on VNI %u with flags 0x%x",
 -                              ipaddr2str(ip, buf2, sizeof(buf2)),
 -                              prefix_mac2str(macaddr, buf, sizeof(buf)),
 -                              zvni->vni, n->flags);
 -
 +              ZEBRA_NEIGH_SET_INACTIVE(n);
 +              n->loc_seq = 0;
 +              zmac->loc_seq = mac_new_seq;
                return 0;
        }
  
-       /* Set router flag (R-bit) */
-       if (router_flag)
-               SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+       if (!check_rbit) {
++              return 0;
++      }
 +
 +      /* If the MAC's sequence number has changed, inform the MAC and all
 +       * neighbors associated with the MAC to BGP, else just inform this
 +       * neighbor.
 +       */
 +      if (upd_mac_seq && zmac->loc_seq != mac_new_seq) {
                if (IS_ZEBRA_DEBUG_VXLAN)
 -                      zlog_debug(
 -                              "Skipping neigh %s with MAC %s on VNI %u add to client as router flag is not set.",
 -                              ipaddr2str(ip, buf2, sizeof(buf2)),
 -                              prefix_mac2str(macaddr, buf, sizeof(buf)),
 -                              zvni->vni);
 +                      zlog_debug("Seq changed for MAC %s VNI %u - old %u new %u",
 +                                 prefix_mac2str(macaddr, buf, sizeof(buf)),
 +                                 zvni->vni, zmac->loc_seq, mac_new_seq);
 +              zmac->loc_seq = mac_new_seq;
 +              if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
 +                                              zmac->flags, zmac->loc_seq))
 +                      return -1;
 +              zvni_process_neigh_on_local_mac_change(zvni, zmac, 1);
                return 0;
        }
  
@@@ -4002,440 -3976,73 +4024,446 @@@ static int zebra_vxlan_readd_remote_rma
        return 0;
  }
  
 -/* Public functions */
 -
 -int is_l3vni_for_prefix_routes_only(vni_t vni)
 +/* Process a remote MACIP add from BGP. */
 +static void process_remote_macip_add(vni_t vni,
 +                                   struct ethaddr *macaddr,
 +                                   uint16_t ipa_len,
 +                                   struct ipaddr *ipaddr,
 +                                   uint8_t flags,
 +                                   uint32_t seq,
 +                                   struct in_addr vtep_ip)
  {
 -      zebra_l3vni_t *zl3vni = NULL;
 -
 -      zl3vni = zl3vni_lookup(vni);
 -      if (!zl3vni)
 -              return 0;
 -
 -      return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
 -}
 +      zebra_vni_t *zvni;
 +      zebra_vtep_t *zvtep;
 +      zebra_mac_t *mac, *old_mac;
 +      zebra_neigh_t *n = NULL;
 +      int update_mac = 0, update_neigh = 0;
 +      char buf[ETHER_ADDR_STRLEN];
 +      char buf1[INET6_ADDRSTRLEN];
 +      struct interface *ifp = NULL;
 +      struct zebra_if *zif = NULL;
 +      uint32_t tmp_seq;
 +      uint8_t sticky = 0;
 +      u_char remote_gw = 0;
++      uint8_t router_flag = 0;
  
 -/* handle evpn route in vrf table */
 -void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
 -                                  struct ipaddr *vtep_ip,
 -                                  struct prefix *host_prefix)
 -{
 -      zebra_l3vni_t *zl3vni = NULL;
 -      struct ipaddr ipv4_vtep;
 +      /* Locate VNI hash entry - expected to exist. */
 +      zvni = zvni_lookup(vni);
 +      if (!zvni) {
 +              zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni);
 +              return;
 +      }
  
 -      zl3vni = zl3vni_from_vrf(vrf_id);
 -      if (!zl3vni || !is_l3vni_oper_up(zl3vni))
 +      ifp = zvni->vxlan_if;
 +      if (ifp)
 +              zif = ifp->info;
 +      if (!ifp ||
 +          !if_is_operative(ifp) ||
 +          !zif ||
 +          !zif->brslave_info.br_if) {
 +              zlog_warn("Ignoring remote MACIP ADD VNI %u, invalid interface state or info",
 +                        vni);
                return;
 +      }
  
 -      /*
 -       * add the next hop neighbor -
 -       * neigh to be installed is the ipv6 nexthop neigh
 +      /* The remote VTEP specified should normally exist, but it is
 +       * possible that when peering comes up, peer may advertise MACIP
 +       * routes before advertising type-3 routes.
         */
 -      zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
 +      zvtep = zvni_vtep_find(zvni, &vtep_ip);
 +      if (!zvtep) {
 +              if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
 +                      flog_err(
 +                              ZEBRA_ERR_VTEP_ADD_FAILED,
 +                              "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
 +                              vni, zvni);
 +                      return;
 +              }
  
 -      /*
 -       * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
 -       * address. Rmac is programmed against the ipv4 vtep because we only
 -       * support ipv4 tunnels in the h/w right now
 -       */
 -      memset(&ipv4_vtep, 0, sizeof(struct ipaddr));
 -      ipv4_vtep.ipa_type = IPADDR_V4;
 -      if (vtep_ip->ipa_type == IPADDR_V6)
 -              ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
 -                                       &(ipv4_vtep.ipaddr_v4));
 -      else
 -              memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
 -                     sizeof(struct in_addr));
 +              zvni_vtep_install(zvni, &vtep_ip);
 +      }
  
 -      /*
 -       * add the rmac - remote rmac to be installed is against the ipv4
 -       * nexthop address
 -       */
 -      zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix);
 -}
 +      sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
 +      remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
++      router_flag = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
  
 -/* handle evpn vrf route delete */
 -void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
 -                                  struct ipaddr *vtep_ip,
 -                                  struct prefix *host_prefix)
 -{
 -      zebra_l3vni_t *zl3vni = NULL;
 -      zebra_neigh_t *nh = NULL;
 -      zebra_mac_t *zrmac = NULL;
 +      mac = zvni_mac_lookup(zvni, macaddr);
  
 -      zl3vni = zl3vni_from_vrf(vrf_id);
 -      if (!zl3vni)
 +      /* Ignore if the mac is already present as a gateway mac */
 +      if (mac &&
 +          CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
 +          CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
 +              if (IS_ZEBRA_DEBUG_VXLAN)
 +                      zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
 +                                 vni,
 +                                 prefix_mac2str(macaddr, buf, sizeof(buf)),
 +                                 ipa_len ? " IP " : "",
 +                                 ipa_len ?
 +                                 ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
                return;
 +      }
  
 -      /* find the next hop entry and rmac entry */
 -      nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
 +      /* check if the remote MAC is unknown or has a change.
 +       * If so, that needs to be updated first. Note that client could
 +       * install MAC and MACIP separately or just install the latter.
 +       */
 +      if (!mac
 +          || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
 +          || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0) != sticky
 +          || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0)
 +              != remote_gw
 +          || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
 +          || seq != mac->rem_seq)
 +              update_mac = 1;
 +
 +      if (update_mac) {
 +              if (!mac) {
 +                      mac = zvni_mac_add(zvni, macaddr);
 +                      if (!mac) {
 +                              zlog_warn(
 +                                      "Failed to add MAC %s VNI %u Remote VTEP %s",
 +                                      prefix_mac2str(macaddr, buf,
 +                                                     sizeof(buf)),
 +                                      vni, inet_ntoa(vtep_ip));
 +                              return;
 +                      }
 +
 +                      /* Is this MAC created for a MACIP? */
 +                      if (ipa_len)
 +                              SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
 +              } else {
 +                      const char *mac_type;
 +
 +                      /* When host moves but changes its (MAC,IP)
 +                       * binding, BGP may install a MACIP entry that
 +                       * corresponds to "older" location of the host
 +                       * in transient situations (because {IP1,M1}
 +                       * is a different route from {IP1,M2}). Check
 +                       * the sequence number and ignore this update
 +                       * if appropriate.
 +                       */
 +                      if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
 +                              tmp_seq = mac->loc_seq;
 +                              mac_type = "local";
 +                      } else {
 +                              tmp_seq = mac->rem_seq;
 +                              mac_type = "remote";
 +                      }
 +                      if (seq < tmp_seq) {
 +                              if (IS_ZEBRA_DEBUG_VXLAN)
 +                                      zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u",
 +                                      vni,
 +                                      prefix_mac2str(macaddr,
 +                                                     buf, sizeof(buf)),
 +                                      ipa_len ? " IP " : "",
 +                                      ipa_len ?
 +                                      ipaddr2str(ipaddr,
 +                                                 buf1, sizeof(buf1)) : "",
 +                                      mac_type,
 +                                      tmp_seq);
 +                              return;
 +                      }
 +              }
 +
 +              /* Set "auto" and "remote" forwarding info. */
 +              UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
 +              memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
 +              SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
 +              mac->fwd_info.r_vtep_ip = vtep_ip;
 +
 +              if (sticky)
 +                      SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
 +              else
 +                      UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
 +
 +              if (remote_gw)
 +                      SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
 +              else
 +                      UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
 +
 +              zvni_process_neigh_on_remote_mac_add(zvni, mac);
 +
 +              /* Install the entry. */
 +              zvni_mac_install(zvni, mac);
 +      }
 +
 +      /* Update seq number. */
 +      mac->rem_seq = seq;
 +
 +      /* If there is no IP, return after clearing AUTO flag of MAC. */
 +      if (!ipa_len) {
 +              UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
 +              return;
 +      }
 +
 +      /* Check if the remote neighbor itself is unknown or has a
 +       * change. If so, create or update and then install the entry.
 +       */
 +      n = zvni_neigh_lookup(zvni, ipaddr);
 +      if (!n
 +          || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
 +          || (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0)
 +          || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)
++          || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0)
++              != router_flag)
 +          || seq != n->rem_seq)
 +              update_neigh = 1;
 +
 +      if (update_neigh) {
 +              if (!n) {
 +                      n = zvni_neigh_add(zvni, ipaddr, macaddr);
 +                      if (!n) {
 +                              zlog_warn(
 +                                      "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
 +                                      ipaddr2str(ipaddr, buf1,
 +                                                 sizeof(buf1)),
 +                                      prefix_mac2str(macaddr, buf,
 +                                                     sizeof(buf)),
 +                                      vni, inet_ntoa(vtep_ip));
 +                              return;
 +                      }
 +
 +              } else {
 +                      const char *n_type;
 +
 +                      /* When host moves but changes its (MAC,IP)
 +                       * binding, BGP may install a MACIP entry that
 +                       * corresponds to "older" location of the host
 +                       * in transient situations (because {IP1,M1}
 +                       * is a different route from {IP1,M2}). Check
 +                       * the sequence number and ignore this update
 +                       * if appropriate.
 +                       */
 +                      if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
 +                              tmp_seq = n->loc_seq;
 +                              n_type = "local";
 +                      } else {
 +                              tmp_seq = n->rem_seq;
 +                              n_type = "remote";
 +                      }
 +                      if (seq < tmp_seq) {
 +                              if (IS_ZEBRA_DEBUG_VXLAN)
 +                                      zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u",
 +                                      vni,
 +                                      prefix_mac2str(macaddr,
 +                                                     buf, sizeof(buf)),
 +                                      ipa_len ? " IP " : "",
 +                                      ipa_len ?
 +                                      ipaddr2str(ipaddr,
 +                                                 buf1, sizeof(buf1)) : "",
 +                                      n_type,
 +                                      tmp_seq);
 +                              return;
 +                      }
 +                      if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) {
 +                              /* MAC change, send a delete for old
 +                               * neigh if learnt locally.
 +                               */
 +                              if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) &&
 +                                  IS_ZEBRA_NEIGH_ACTIVE(n))
 +                                      zvni_neigh_send_del_to_client(
 +                                              zvni->vni, &n->ip,
 +                                              &n->emac, 0);
 +
 +                              /* update neigh list for macs */
 +                              old_mac = zvni_mac_lookup(zvni, &n->emac);
 +                              if (old_mac) {
 +                                      listnode_delete(old_mac->neigh_list, n);
 +                                      zvni_deref_ip2mac(zvni, old_mac, 1);
 +                              }
 +                              listnode_add_sort(mac->neigh_list, n);
 +                              memcpy(&n->emac, macaddr, ETH_ALEN);
 +                      }
 +              }
 +
 +              /* Set "remote" forwarding info. */
 +              UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
 +              n->r_vtep_ip = vtep_ip;
 +              SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
 +
 +              /* Set router flag (R-bit) to this Neighbor entry */
 +              if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
 +                      SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
++              else
++                      UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
 +
 +              /* Install the entry. */
 +              zvni_neigh_install(zvni, n);
 +      }
 +
 +      /* Update seq number. */
 +      n->rem_seq = seq;
 +}
 +
 +/* Process a remote MACIP delete from BGP. */
 +static void process_remote_macip_del(vni_t vni,
 +                                   struct ethaddr *macaddr,
 +                                   uint16_t ipa_len,
 +                                   struct ipaddr *ipaddr,
 +                                   struct in_addr vtep_ip)
 +{
 +      zebra_vni_t *zvni;
 +      zebra_mac_t *mac = NULL;
 +      zebra_neigh_t *n = NULL;
 +      struct interface *ifp = NULL;
 +      struct zebra_if *zif = NULL;
 +      char buf[ETHER_ADDR_STRLEN];
 +      char buf1[INET6_ADDRSTRLEN];
 +
 +      /* Locate VNI hash entry - expected to exist. */
 +      zvni = zvni_lookup(vni);
 +      if (!zvni) {
 +              if (IS_ZEBRA_DEBUG_VXLAN)
 +                      zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni);
 +              return;
 +      }
 +
 +      ifp = zvni->vxlan_if;
 +      if (ifp)
 +              zif = ifp->info;
 +      if (!ifp ||
 +          !if_is_operative(ifp) ||
 +          !zif ||
 +          !zif->brslave_info.br_if) {
 +              if (IS_ZEBRA_DEBUG_VXLAN)
 +                      zlog_debug("Ignoring remote MACIP DEL VNI %u, invalid interface state or info",
 +                                 vni);
 +              return;
 +      }
 +
 +      /* The remote VTEP specified is normally expected to exist, but
 +       * it is possible that the peer may delete the VTEP before deleting
 +       * any MACs referring to the VTEP, in which case the handler (see
 +       * remote_vtep_del) would have already deleted the MACs.
 +       */
 +      if (!zvni_vtep_find(zvni, &vtep_ip))
 +              return;
 +
 +      mac = zvni_mac_lookup(zvni, macaddr);
 +      if (ipa_len)
 +              n = zvni_neigh_lookup(zvni, ipaddr);
 +
 +      if (n && !mac) {
 +              zlog_warn("Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL",
 +                        prefix_mac2str(macaddr, buf, sizeof(buf)),
 +                        ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni);
 +              return;
 +      }
 +
 +      /* If the remote mac or neighbor doesn't exist there is nothing
 +       * more to do. Otherwise, uninstall the entry and then remove it.
 +       */
 +      if (!mac && !n)
 +              return;
 +
 +      /* Ignore the delete if this mac is a gateway mac-ip */
 +      if (mac
 +          && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
 +          && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
 +              zlog_warn(
 +                      "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
 +                      vni,
 +                      prefix_mac2str(macaddr, buf, sizeof(buf)),
 +                      ipa_len ? " IP " : "",
 +                      ipa_len ?
 +                      ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
 +              return;
 +      }
 +
 +      /* Uninstall remote neighbor or MAC. */
 +      if (n) {
 +              /* When the MAC changes for an IP, it is possible the
 +               * client may update the new MAC before trying to delete the
 +               * "old" neighbor (as these are two different MACIP routes).
 +               * Do the delete only if the MAC matches.
 +               */
 +              if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
 +                  && (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
 +                      zvni_neigh_uninstall(zvni, n);
 +                      zvni_neigh_del(zvni, n);
 +                      zvni_deref_ip2mac(zvni, mac, 1);
 +              }
 +      } else {
 +              if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
 +                      zvni_process_neigh_on_remote_mac_del(zvni, mac);
 +
 +                      if (list_isempty(mac->neigh_list)) {
 +                              zvni_mac_uninstall(zvni, mac, 0);
 +                              zvni_mac_del(zvni, mac);
 +                      } else
 +                              SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
 +              }
 +      }
 +}
 +
 +
 +/* Public functions */
 +
 +int is_l3vni_for_prefix_routes_only(vni_t vni)
 +{
 +      zebra_l3vni_t *zl3vni = NULL;
 +
 +      zl3vni = zl3vni_lookup(vni);
 +      if (!zl3vni)
 +              return 0;
 +
 +      return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
 +}
 +
 +/* handle evpn route in vrf table */
 +void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
 +                                  struct ipaddr *vtep_ip,
 +                                  struct prefix *host_prefix)
 +{
 +      zebra_l3vni_t *zl3vni = NULL;
 +      struct ipaddr ipv4_vtep;
 +
 +      zl3vni = zl3vni_from_vrf(vrf_id);
 +      if (!zl3vni || !is_l3vni_oper_up(zl3vni))
 +              return;
 +
 +      /*
 +       * add the next hop neighbor -
 +       * neigh to be installed is the ipv6 nexthop neigh
 +       */
 +      zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
 +
 +      /*
 +       * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
 +       * address. Rmac is programmed against the ipv4 vtep because we only
 +       * support ipv4 tunnels in the h/w right now
 +       */
 +      memset(&ipv4_vtep, 0, sizeof(struct ipaddr));
 +      ipv4_vtep.ipa_type = IPADDR_V4;
 +      if (vtep_ip->ipa_type == IPADDR_V6)
 +              ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
 +                                       &(ipv4_vtep.ipaddr_v4));
 +      else
 +              memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
 +                     sizeof(struct in_addr));
 +
 +      /*
 +       * add the rmac - remote rmac to be installed is against the ipv4
 +       * nexthop address
 +       */
 +      zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix);
 +}
 +
 +/* handle evpn vrf route delete */
 +void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
 +                                  struct ipaddr *vtep_ip,
 +                                  struct prefix *host_prefix)
 +{
 +      zebra_l3vni_t *zl3vni = NULL;
 +      zebra_neigh_t *nh = NULL;
 +      zebra_mac_t *zrmac = NULL;
 +
 +      zl3vni = zl3vni_from_vrf(vrf_id);
 +      if (!zl3vni)
 +              return;
 +
 +      /* find the next hop entry and rmac entry */
 +      nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
        if (!nh)
                return;
        zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac);
@@@ -5511,18 -5226,181 +5540,17 @@@ void zebra_vxlan_remote_macip_add(ZAPI_
  
                if (IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
 -                              "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s",
 +                              "Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s",
 +                              vni,
                                prefix_mac2str(&macaddr, buf, sizeof(buf)),
 -                              ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
 -                              inet_ntoa(vtep_ip), flags,
 +                              ipa_len ? " IP " : "",
 +                              ipa_len ?
 +                              ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
 +                              flags, seq, inet_ntoa(vtep_ip),
                                zebra_route_string(client->proto));
  
 -              /* Locate VNI hash entry - expected to exist. */
 -              zvni = zvni_lookup(vni);
 -              if (!zvni) {
 -                      zlog_warn(
 -                              "Failed to locate VNI hash upon remote MACIP ADD, VNI %u",
 -                              vni);
 -                      continue;
 -              }
 -              ifp = zvni->vxlan_if;
 -              if (!ifp) {
 -                      zlog_warn(
 -                              "VNI %u hash %p doesn't have intf upon remote MACIP add",
 -                              vni, zvni);
 -                      continue;
 -              }
 -              zif = ifp->info;
 -
 -              /* If down or not mapped to a bridge, we're done. */
 -              if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
 -                      continue;
 -
 -              /* The remote VTEP specified should normally exist, but it is
 -               * possible
 -               * that when peering comes up, peer may advertise MACIP routes
 -               * before
 -               * advertising type-3 routes.
 -               */
 -              zvtep = zvni_vtep_find(zvni, &vtep_ip);
 -              if (!zvtep) {
 -                      if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
 -                              flog_err(
 -                                      ZEBRA_ERR_VTEP_ADD_FAILED,
 -                                      "Failed to add remote VTEP, VNI %u zvni %p",
 -                                      vni, zvni);
 -                              continue;
 -                      }
 -
 -                      zvni_vtep_install(zvni, &vtep_ip);
 -              }
 -
 -              mac = zvni_mac_lookup(zvni, &macaddr);
 -
 -              /* Ignore the update if the mac is already present
 -                 as a gateway mac */
 -              if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
 -                  && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
 -                      if (IS_ZEBRA_DEBUG_VXLAN)
 -                              zlog_debug(
 -                                      "%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac",
 -                                      zvrf_id(zvrf),
 -                                      prefix_mac2str(&macaddr, buf,
 -                                                     sizeof(buf)),
 -                                      ipaddr2str(&ip, buf1, sizeof(buf1)),
 -                                      vni);
 -                      continue;
 -              }
 -
 -              /* check if the remote MAC is unknown or has a change.
 -               * If so, that needs to be updated first. Note that client could
 -               * install MAC and MACIP separately or just install the latter.
 -               */
 -              if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
 -                  || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0)
 -                             != sticky
 -                  || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0)
 -                             != remote_gw
 -                  || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip))
 -                      update_mac = 1;
 -
 -              if (update_mac) {
 -                      if (!mac) {
 -                              mac = zvni_mac_add(zvni, &macaddr);
 -                              if (!mac) {
 -                                      zlog_warn(
 -                                              "Failed to add MAC %s VNI %u Remote VTEP %s",
 -                                              prefix_mac2str(&macaddr, buf,
 -                                                             sizeof(buf)),
 -                                              vni, inet_ntoa(vtep_ip));
 -                                      return;
 -                              }
 -
 -                              /* Is this MAC created for a MACIP? */
 -                              if (ipa_len)
 -                                      SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
 -                      }
 -
 -                      /* Set "auto" and "remote" forwarding info. */
 -                      UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
 -                      memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
 -                      SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
 -                      mac->fwd_info.r_vtep_ip = vtep_ip;
 -
 -                      if (sticky)
 -                              SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
 -                      else
 -                              UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
 -
 -                      if (remote_gw)
 -                              SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
 -                      else
 -                              UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
 -
 -                      zvni_process_neigh_on_remote_mac_add(zvni, mac);
 -
 -                      /* Install the entry. */
 -                      zvni_mac_install(zvni, mac);
 -              }
 -
 -              /* If there is no IP, continue - after clearing AUTO flag of
 -               * MAC. */
 -              if (!ipa_len) {
 -                      UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
 -                      continue;
 -              }
 -
 -              /* Check if the remote neighbor itself is unknown or has a
 -               * change.
 -               * If so, create or update and then install the entry.
 -               */
 -              n = zvni_neigh_lookup(zvni, &ip);
 -              if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
 -                  || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0)
 -                      != router_flag)
 -                  || (memcmp(&n->emac, &macaddr, sizeof(macaddr)) != 0)
 -                  || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip))
 -                      update_neigh = 1;
 -
 -              if (update_neigh) {
 -                      if (!n) {
 -                              n = zvni_neigh_add(zvni, &ip, &macaddr);
 -                              if (!n) {
 -                                      zlog_warn(
 -                                              "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
 -                                              ipaddr2str(&ip, buf1,
 -                                                         sizeof(buf1)),
 -                                              prefix_mac2str(&macaddr, buf,
 -                                                             sizeof(buf)),
 -                                              vni, inet_ntoa(vtep_ip));
 -                                      return;
 -                              }
 -
 -                      } else if (memcmp(&n->emac, &macaddr, sizeof(macaddr))
 -                                 != 0) {
 -                              /* MAC change, update neigh list for old and new
 -                               * mac */
 -                              old_mac = zvni_mac_lookup(zvni, &n->emac);
 -                              if (old_mac) {
 -                                      listnode_delete(old_mac->neigh_list, n);
 -                                      zvni_deref_ip2mac(zvni, old_mac, 1);
 -                              }
 -                              listnode_add_sort(mac->neigh_list, n);
 -                              memcpy(&n->emac, &macaddr, ETH_ALEN);
 -                      }
 -
 -                      /* Set "remote" forwarding info. */
 -                      UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
 -                      /* TODO: Handle MAC change. */
 -                      n->r_vtep_ip = vtep_ip;
 -                      SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
 -
 -                      /* Set router flag (R-bit) to this Neighbor entry */
 -                      if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
 -                              SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
 -                      else
 -                              UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
--
 -                      /* Install the entry. */
 -                      zvni_neigh_install(zvni, n);
 -              }
 +              process_remote_macip_add(vni, &macaddr, ipa_len, &ip,
 +                                       flags, seq, vtep_ip);
        }
  
  stream_failure: