]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: VNI and VTEP handling
authorvivek <vivek@cumulusnetworks.com>
Mon, 15 May 2017 05:38:26 +0000 (22:38 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 12 Jul 2017 16:26:02 +0000 (12:26 -0400)
Implement fundamental handling for VNIs and VTEPs:
- Handle EVPN enable/disable by client (advertise-all-vni)
- Create/update/delete VNIs based on VxLAN interface events and inform
client
- Handle VTEP add/delete from client and install into kernel
- New debug command for VxLAN/EVPN
- kernel interface (Linux/netlink only)

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
18 files changed:
lib/log.c
lib/zclient.h
zebra/Makefile.am
zebra/debug.c
zebra/debug.h
zebra/if_netlink.c
zebra/interface.c
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zebra_l2.c
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vxlan.c [new file with mode: 0644]
zebra/zebra_vxlan.h [new file with mode: 0644]
zebra/zebra_vxlan_null.c [new file with mode: 0644]
zebra/zserv.c
zebra/zserv.h

index 1c61d72168ed35f507c360a14463bdade3157b1c..7a7545201df6c9bee30e7fe8702516ec2c1e6af8 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -946,6 +946,11 @@ static const struct zebra_desc_table command_types[] = {
   DESC_ENTRY    (ZEBRA_LABEL_MANAGER_CONNECT),
   DESC_ENTRY    (ZEBRA_GET_LABEL_CHUNK),
   DESC_ENTRY    (ZEBRA_RELEASE_LABEL_CHUNK),
+  DESC_ENTRY    (ZEBRA_ADVERTISE_ALL_VNI),
+  DESC_ENTRY    (ZEBRA_VNI_ADD),
+  DESC_ENTRY    (ZEBRA_VNI_DEL),
+  DESC_ENTRY    (ZEBRA_REMOTE_VTEP_ADD),
+  DESC_ENTRY    (ZEBRA_REMOTE_VTEP_DEL),
 };
 #undef DESC_ENTRY
 
index 59412fdd4c5487da5b5868f7a5fd1e91598505cf..0c9f70751c4ed425d23d3ddb20dfc9b2b0fe593c 100644 (file)
@@ -96,6 +96,11 @@ typedef enum {
   ZEBRA_FEC_REGISTER,
   ZEBRA_FEC_UNREGISTER,
   ZEBRA_FEC_UPDATE,
+  ZEBRA_ADVERTISE_ALL_VNI,
+  ZEBRA_VNI_ADD,
+  ZEBRA_VNI_DEL,
+  ZEBRA_REMOTE_VTEP_ADD,
+  ZEBRA_REMOTE_VTEP_DEL,
 } zebra_message_types_t;
 
 struct redist_proto
index 25e6b1bc1b3c531a3103b35a636c32df6bcbdb27..2bb9da0a9e47396fea5ffe31ed590d768cf56ada 100644 (file)
@@ -34,6 +34,7 @@ zebra_SOURCES = \
        zebra_mroute.c \
        label_manager.c \
        zebra_l2.c \
+       zebra_vxlan.c \
        # end
 
 noinst_HEADERS = \
@@ -44,7 +45,7 @@ noinst_HEADERS = \
        zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
        zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
        kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h \
-       zebra_l2.h zebra_vxlan_private.h
+       zebra_l2.h zebra_vxlan_private.h zebra_vxlan.h
 
 zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP)
 
index ba2a9ad2a3746995449c7783d69bcb65a24cdfbe..0b0a0e9886f5c83d1dee2d5e99a0948c93484039 100644 (file)
@@ -31,6 +31,7 @@ unsigned long zebra_debug_rib;
 unsigned long zebra_debug_fpm;
 unsigned long zebra_debug_nht;
 unsigned long zebra_debug_mpls;
+unsigned long zebra_debug_vxlan;
 
 DEFUN (show_debugging_zebra,
        show_debugging_zebra_cmd,
@@ -121,6 +122,17 @@ DEFUN (debug_zebra_mpls,
   return CMD_WARNING;
 }
 
+DEFUN (debug_zebra_vxlan,
+       debug_zebra_vxlan_cmd,
+       "debug zebra vxlan",
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra VxLAN (EVPN)\n")
+{
+  zebra_debug_vxlan = ZEBRA_DEBUG_VXLAN;
+  return CMD_WARNING;
+}
+
 DEFUN (debug_zebra_packet,
        debug_zebra_packet_cmd,
        "debug zebra packet [<recv|send>] [detail]",
@@ -251,6 +263,18 @@ DEFUN (no_debug_zebra_mpls,
   return CMD_SUCCESS;
 }
 
+DEFUN (no_debug_zebra_vxlan,
+       no_debug_zebra_vxlan_cmd,
+       "no debug zebra vxlan",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra VxLAN (EVPN)\n")
+{
+  zebra_debug_vxlan = 0;
+  return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_zebra_packet,
        no_debug_zebra_packet_cmd,
        "no debug zebra packet [<recv|send>]",
@@ -419,6 +443,11 @@ config_write_debug (struct vty *vty)
       vty_out (vty, "debug zebra mpls%s", VTYNL);
       write++;
     }
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    {
+      vty_out (vty, "debug zebra vxlan%s", VTY_NEWLINE);
+      write++;
+    }
   return write;
 }
 
@@ -431,6 +460,7 @@ zebra_debug_init (void)
   zebra_debug_rib = 0;
   zebra_debug_fpm = 0;
   zebra_debug_mpls = 0;
+  zebra_debug_vxlan = 0;
 
   install_node (&debug_node, config_write_debug);
 
@@ -439,6 +469,7 @@ zebra_debug_init (void)
   install_element (ENABLE_NODE, &debug_zebra_events_cmd);
   install_element (ENABLE_NODE, &debug_zebra_nht_cmd);
   install_element (ENABLE_NODE, &debug_zebra_mpls_cmd);
+  install_element (ENABLE_NODE, &debug_zebra_vxlan_cmd);
   install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
   install_element (ENABLE_NODE, &debug_zebra_kernel_cmd);
   install_element (ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd);
@@ -448,6 +479,7 @@ zebra_debug_init (void)
   install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
   install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd);
   install_element (ENABLE_NODE, &no_debug_zebra_mpls_cmd);
+  install_element (ENABLE_NODE, &no_debug_zebra_vxlan_cmd);
   install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
   install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
   install_element (ENABLE_NODE, &no_debug_zebra_kernel_msgdump_cmd);
@@ -458,6 +490,7 @@ zebra_debug_init (void)
   install_element (CONFIG_NODE, &debug_zebra_events_cmd);
   install_element (CONFIG_NODE, &debug_zebra_nht_cmd);
   install_element (CONFIG_NODE, &debug_zebra_mpls_cmd);
+  install_element (CONFIG_NODE, &debug_zebra_vxlan_cmd);
   install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
   install_element (CONFIG_NODE, &debug_zebra_kernel_cmd);
   install_element (CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd);
@@ -467,6 +500,7 @@ zebra_debug_init (void)
   install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
   install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd);
   install_element (CONFIG_NODE, &no_debug_zebra_mpls_cmd);
+  install_element (CONFIG_NODE, &no_debug_zebra_vxlan_cmd);
   install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
   install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
   install_element (CONFIG_NODE, &no_debug_zebra_kernel_msgdump_cmd);
index 0a50da8176242b7c3aa121beb5eb3733bbfba534..5687a3516b9c4304938f94ed83612320c6be2abb 100644 (file)
@@ -42,6 +42,8 @@
 
 #define ZEBRA_DEBUG_MPLS    0x01
 
+#define ZEBRA_DEBUG_VXLAN   0x01
+
 /* Debug related macro. */
 #define IS_ZEBRA_DEBUG_EVENT  (zebra_debug_event & ZEBRA_DEBUG_EVENT)
 
@@ -63,6 +65,7 @@
 #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
 #define IS_ZEBRA_DEBUG_NHT  (zebra_debug_nht & ZEBRA_DEBUG_NHT)
 #define IS_ZEBRA_DEBUG_MPLS  (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
+#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
 
 extern unsigned long zebra_debug_event;
 extern unsigned long zebra_debug_packet;
@@ -71,6 +74,7 @@ extern unsigned long zebra_debug_rib;
 extern unsigned long zebra_debug_fpm;
 extern unsigned long zebra_debug_nht;
 extern unsigned long zebra_debug_mpls;
+extern unsigned long zebra_debug_vxlan;
 
 extern void zebra_debug_init (void);
 
index 972e6447f6cf6b2f15c7fae61ec5d4678448c1ee..d0907a267094a692088d4cd2e7c1837daf845acb 100644 (file)
@@ -710,6 +710,15 @@ interface_lookup_netlink (struct zebra_ns *zns)
   if (ret < 0)
     return ret;
 
+  /* Get interface information - for bridge interfaces. */
+  ret = netlink_request_intf_addr (zns, AF_BRIDGE, RTM_GETLINK,
+                                   RTEXT_FILTER_BRVLAN);
+  if (ret < 0)
+    return ret;
+  ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 0);
+  if (ret < 0)
+    return ret;
+
   /* Get IPv4 address of the interfaces. */
   ret = netlink_request_intf_addr (zns, AF_INET, RTM_GETADDR, 0);
   if (ret < 0)
index 78ba8cdde814c55c41707d8c187e579a00727895..87b0896f9fe3add3417fe3a9235f3c804382f35a 100644 (file)
@@ -47,6 +47,7 @@
 #include "zebra/zebra_ptm.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/interface.h"
+#include "zebra/zebra_vxlan.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -880,6 +881,9 @@ if_up (struct interface *ifp)
   rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
 
   zebra_vrf_static_route_interface_fixup (ifp);
+
+  if (IS_ZEBRA_IF_VXLAN (ifp))
+    zebra_vxlan_if_up (ifp);
 }
 
 /* Interface goes down.  We have to manage different behavior of based
@@ -893,6 +897,9 @@ if_down (struct interface *ifp)
   zif->down_count++;
   quagga_timestamp (2, zif->down_last, sizeof (zif->down_last));
 
+  if (IS_ZEBRA_IF_VXLAN (ifp))
+    zebra_vxlan_if_down (ifp);
+
   /* Notify to the protocol daemons. */
   zebra_interface_down_update (ifp);
 
index a39af87b5ac59a80d11265b618fe3a8d2edde525..10ca6c95cf634eb50d3f593aeac9c26fd541479c 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "prefix.h"
 #include "if.h"
+#include "vxlan.h"
 #include "zebra/rib.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_mpls.h"
@@ -41,4 +42,8 @@ extern int kernel_del_lsp (zebra_lsp_t *);
 extern int mpls_kernel_init (void);
 
 extern int kernel_get_ipmr_sg_stats (void *mroute);
+extern int kernel_add_vtep (vni_t vni, struct interface *ifp,
+                            struct in_addr *vtep_ip);
+extern int kernel_del_vtep (vni_t vni, struct interface *ifp,
+                            struct in_addr *vtep_ip);
 #endif /* _ZEBRA_RT_H */
index 471f6505886caf91236c892924f432e1c9700d2e..7ff03e7c04faacabbc2b13efcf029e6000eab2b3 100644 (file)
@@ -41,6 +41,7 @@
 #include "vrf.h"
 #include "vty.h"
 #include "mpls.h"
+#include "vxlan.h"
 
 #include "zebra/zserv.h"
 #include "zebra/zebra_ns.h"
@@ -1555,6 +1556,72 @@ kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen)
                              lla, llalen);
 }
 
+/*
+ * 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_list_update (struct interface *ifp,
+                                 struct in_addr *vtep_ip,
+                                 int cmd)
+{
+  struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
+  struct
+    {
+      struct nlmsghdr         n;
+      struct ndmsg            ndm;
+      char                    buf[256];
+    } req;
+  u_char dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+  memset(&req.n, 0, sizeof(req.n));
+  memset(&req.ndm, 0, sizeof(req.ndm));
+
+  req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+  req.n.nlmsg_flags = NLM_F_REQUEST;
+  if (cmd == RTM_NEWNEIGH)
+    req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND);
+  req.n.nlmsg_type = cmd;
+  req.ndm.ndm_family = PF_BRIDGE;
+  req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT;
+  req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master"
+
+
+  addattr_l (&req.n, sizeof (req), NDA_LLADDR, &dst_mac, 6);
+  req.ndm.ndm_ifindex = ifp->ifindex;
+  addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip->s_addr, 4);
+
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
+}
+
+/*
+ * Add remote VTEP for this VxLAN interface (VNI). In Linux, this involves adding
+ * a "flood" MAC FDB entry.
+ */
+int
+kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
+{
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("Install %s into flood list for VNI %u intf %s(%u)",
+                inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex);
+
+  return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_NEWNEIGH);
+}
+
+/*
+ * Remove remote VTEP for this VxLAN interface (VNI). In Linux, this involves
+ * deleting the "flood" MAC FDB entry.
+ */
+int
+kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
+{
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("Uninstall %s from flood list for VNI %u intf %s(%u)",
+                inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex);
+
+  return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_DELNEIGH);
+}
+
 /*
  * MPLS label forwarding table change via netlink interface.
  */
index 9859a31627ee07d2367e0a14176072a747498101..bf7e3403e44b4810fb692dcfa386c9fc234c20ab 100644 (file)
@@ -29,6 +29,7 @@
 #include "sockunion.h"
 #include "log.h"
 #include "privs.h"
+#include "vxlan.h"
 
 #include "zebra/debug.h"
 #include "zebra/rib.h"
@@ -428,3 +429,15 @@ kernel_get_ipmr_sg_stats (void *mroute)
 {
   return 0;
 }
+
+int
+kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
+{
+  return 0;
+}
+
+int
+kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
+{
+  return 0;
+}
index 5dd83baeddd8dd865be5efae42fc98a2f7610b19..b71b96a18b7059ad5555cdb0e87b8a01301ab3ef 100644 (file)
@@ -42,6 +42,7 @@
 #include "zebra/zebra_vrf.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/zebra_l2.h"
+#include "zebra/zebra_vxlan.h"
 
 /* definitions */
 
@@ -175,6 +176,7 @@ zebra_l2_vxlanif_add_update (struct interface *ifp,
   if (add)
     {
       memcpy (&zif->l2info.vxl, vxlan_info, sizeof (*vxlan_info));
+      zebra_vxlan_if_add (ifp);
       return;
     }
 
@@ -183,6 +185,7 @@ zebra_l2_vxlanif_add_update (struct interface *ifp,
     return;
 
   zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
+  zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_LOCAL_IP_CHANGE);
 }
 
 /*
@@ -193,11 +196,17 @@ zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
                                      vlanid_t access_vlan)
 {
   struct zebra_if *zif;
+  vlanid_t old_access_vlan;
 
   zif = ifp->info;
   assert(zif);
 
+  old_access_vlan = zif->l2info.vxl.access_vlan;
+  if (old_access_vlan == access_vlan)
+    return;
+
   zif->l2info.vxl.access_vlan = access_vlan;
+  zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_VLAN_CHANGE);
 }
 
 /*
@@ -206,7 +215,7 @@ zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
 void
 zebra_l2_vxlanif_del (struct interface *ifp)
 {
-  /* No action currently. */
+  zebra_vxlan_if_del (ifp);
 }
 
 /*
@@ -235,4 +244,8 @@ zebra_l2if_update_bridge_slave (struct interface *ifp,
     zebra_l2_map_slave_to_bridge (&zif->brslave_info);
   else if (old_bridge_ifindex != IFINDEX_INTERNAL)
     zebra_l2_unmap_slave_from_bridge (&zif->brslave_info);
+
+  /* In the case of VxLAN, invoke the handler for EVPN. */
+  if (zif->zif_type == ZEBRA_IF_VXLAN)
+    zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_MASTER_CHANGE);
 }
index 165689267517d3d8f4f5f8d80ac2d25df760a503..32c636e5e7cb127e4d22a292fc69c1c7e17b452a 100644 (file)
@@ -37,6 +37,7 @@
 #include "zebra/zebra_static.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_mpls.h"
+#include "zebra/zebra_vxlan.h"
 
 extern struct zebra_t zebrad;
 
@@ -244,6 +245,9 @@ zebra_vrf_delete (struct vrf *vrf)
                rib_close_table (zvrf->other_table[afi][table_id]);
        }
 
+      /* Cleanup Vxlan table and update kernel */
+      zebra_vxlan_close_tables (zvrf);
+
       zebra_mpls_close_tables (zvrf);
 
       for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp))
@@ -421,6 +425,7 @@ zebra_vrf_alloc (void)
       zvrf->import_check_table[afi] = table;
     }
 
+  zebra_vxlan_init_tables (zvrf);
   zebra_mpls_init_tables (zvrf);
 
   return zvrf;
index 790e2e53d28f587241cd94b5fceddfe72d6af47c..29f7df00fdff6c23083b98dbee9fc762bcc6eb22 100644 (file)
@@ -95,6 +95,15 @@ struct zebra_vrf
   u_int16_t mpls_flags;
 #define MPLS_FLAG_SCHEDULE_LSPS    (1 << 0)
 
+  /*
+   * VNI hash table (for EVPN). Only in default instance.
+   */
+  struct hash *vni_table;
+  /*
+   * Whether EVPN is enabled or not.
+   */
+  int advertise_all_vni;
+
   /* Route Installs */
   uint64_t installs;
   uint64_t removals;
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
new file mode 100644 (file)
index 0000000..fcf4328
--- /dev/null
@@ -0,0 +1,905 @@
+/*
+ * Zebra EVPN for VxLAN code
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "log.h"
+#include "linklist.h"
+#include "stream.h"
+#include "hash.h"
+#include "jhash.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_vxlan_private.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zebra_l2.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, ZVNI,      "VNI hash");
+DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
+
+/* definitions */
+
+
+/* static function declarations */
+static unsigned int
+vni_hash_keymake (void *p);
+static int
+vni_hash_cmp (const void *p1, const void *p2);
+static void *
+zvni_alloc (void *p);
+static zebra_vni_t *
+zvni_lookup (struct zebra_vrf *zvrf, vni_t vni);
+static zebra_vni_t *
+zvni_add (struct zebra_vrf *zvrf, vni_t vni);
+static int
+zvni_del (struct zebra_vrf *zvrf, zebra_vni_t *zvni);
+static int
+zvni_send_add_to_client (struct zebra_vrf *zvrf, zebra_vni_t *zvni);
+static int
+zvni_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni);
+static void
+zvni_build_hash_table (struct zebra_vrf *zvrf);
+static int
+zvni_vtep_match (struct in_addr *vtep_ip, zebra_vtep_t *zvtep);
+static zebra_vtep_t *
+zvni_vtep_find (zebra_vni_t *zvni, struct in_addr *vtep_ip);
+static zebra_vtep_t *
+zvni_vtep_add (zebra_vni_t *zvni, struct in_addr *vtep_ip);
+static int
+zvni_vtep_del (zebra_vni_t *zvni, zebra_vtep_t *zvtep);
+static int
+zvni_vtep_del_all (zebra_vni_t *zvni, int uninstall);
+static int
+zvni_vtep_install (zebra_vni_t *zvni, struct in_addr *vtep_ip);
+static int
+zvni_vtep_uninstall (zebra_vni_t *zvni, struct in_addr *vtep_ip);
+
+
+/* Private functions */
+
+/*
+ * Hash function for VNI.
+ */
+static unsigned int
+vni_hash_keymake (void *p)
+{
+  const zebra_vni_t *zvni = p;
+
+  return (jhash_1word(zvni->vni, 0));
+}
+
+/*
+ * Compare 2 VNI hash entries.
+ */
+static int
+vni_hash_cmp (const void *p1, const void *p2)
+{
+  const zebra_vni_t *zvni1 = p1;
+  const zebra_vni_t *zvni2 = p2;
+
+  return (zvni1->vni == zvni2->vni);
+}
+
+/*
+ * Callback to allocate VNI hash entry.
+ */
+static void *
+zvni_alloc (void *p)
+{
+  const zebra_vni_t *tmp_vni = p;
+  zebra_vni_t *zvni;
+
+  zvni = XCALLOC (MTYPE_ZVNI, sizeof(zebra_vni_t));
+  zvni->vni = tmp_vni->vni;
+  return ((void *)zvni);
+}
+
+/*
+ * Look up VNI hash entry.
+ */
+static zebra_vni_t *
+zvni_lookup (struct zebra_vrf *zvrf, vni_t vni)
+{
+  zebra_vni_t tmp_vni;
+  zebra_vni_t *zvni = NULL;
+
+  memset (&tmp_vni, 0, sizeof (zebra_vni_t));
+  tmp_vni.vni = vni;
+  zvni = hash_lookup (zvrf->vni_table, &tmp_vni);
+
+  return zvni;
+}
+
+/*
+ * Add VNI hash entry.
+ */
+static zebra_vni_t *
+zvni_add (struct zebra_vrf *zvrf, vni_t vni)
+{
+  zebra_vni_t tmp_zvni;
+  zebra_vni_t *zvni = NULL;
+
+  memset (&tmp_zvni, 0, sizeof (zebra_vni_t));
+  tmp_zvni.vni = vni;
+  zvni = hash_get (zvrf->vni_table, &tmp_zvni, zvni_alloc);
+  assert (zvni);
+
+  return zvni;
+}
+
+/*
+ * Delete VNI hash entry.
+ */
+static int
+zvni_del (struct zebra_vrf *zvrf, zebra_vni_t *zvni)
+{
+  zebra_vni_t *tmp_zvni;
+
+  zvni->vxlan_if = NULL;
+
+  /* Free the VNI hash entry and allocated memory. */
+  tmp_zvni = hash_release (zvrf->vni_table, zvni);
+  if (tmp_zvni)
+    XFREE(MTYPE_ZVNI, tmp_zvni);
+
+  return 0;
+}
+
+/*
+ * Inform BGP about local VNI addition.
+ */
+static int
+zvni_send_add_to_client (struct zebra_vrf *zvrf,
+                         zebra_vni_t *zvni)
+{
+  struct zserv *client;
+  struct stream *s;
+
+  client = zebra_find_client (ZEBRA_ROUTE_BGP);
+  /* BGP may not be running. */
+  if (!client)
+    return 0;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  zserv_create_header (s, ZEBRA_VNI_ADD, zvrf_id (zvrf));
+  stream_putl (s, zvni->vni);
+  stream_put_in_addr (s, &zvni->local_vtep_ip);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Send VNI_ADD %u %s to %s",
+                zvrf_id (zvrf), zvni->vni,
+                inet_ntoa(zvni->local_vtep_ip),
+                zebra_route_string (client->proto));
+
+  client->vniadd_cnt++;
+  return zebra_server_send_message(client);
+}
+
+/*
+ * Inform BGP about local VNI deletion.
+ */
+static int
+zvni_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni)
+{
+  struct zserv *client;
+  struct stream *s;
+
+  client = zebra_find_client (ZEBRA_ROUTE_BGP);
+  /* BGP may not be running. */
+  if (!client)
+    return 0;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  zserv_create_header (s, ZEBRA_VNI_DEL, zvrf_id (zvrf));
+  stream_putl (s, vni);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Send VNI_DEL %u to %s", zvrf_id (zvrf), vni,
+                zebra_route_string (client->proto));
+
+  client->vnidel_cnt++;
+  return zebra_server_send_message(client);
+}
+
+/*
+ * Build the VNI hash table by going over the VxLAN interfaces. This
+ * is called when EVPN (advertise-all-vni) is enabled.
+ */
+static void
+zvni_build_hash_table (struct zebra_vrf *zvrf)
+{
+  struct listnode *node;
+  struct interface *ifp;
+
+  /* Walk VxLAN interfaces and create VNI hash. */
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (zvrf_id (zvrf)), node, ifp))
+    {
+      struct zebra_if *zif;
+      struct zebra_l2info_vxlan *vxl;
+      zebra_vni_t *zvni;
+      vni_t vni;
+
+      zif = ifp->info;
+      if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+        continue;
+      vxl = &zif->l2info.vxl;
+
+      vni = vxl->vni;
+
+      if (IS_ZEBRA_DEBUG_VXLAN)
+        zlog_debug ("%u:Create VNI hash for intf %s(%u) VNI %u local IP %s",
+                    zvrf_id (zvrf), ifp->name, ifp->ifindex, vni,
+                    inet_ntoa (vxl->vtep_ip));
+
+      /* VNI hash entry is not expected to exist. */
+      zvni = zvni_lookup (zvrf, vni);
+      if (zvni)
+        {
+          zlog_err ("VNI hash already present for VRF %d IF %s(%u) VNI %u",
+                    zvrf_id (zvrf), ifp->name, ifp->ifindex, vni);
+          continue;
+        }
+
+      zvni = zvni_add (zvrf, vni);
+      if (!zvni)
+        {
+          zlog_err ("Failed to add VNI hash, VRF %d IF %s(%u) VNI %u",
+                    zvrf_id (zvrf), ifp->name, ifp->ifindex, vni);
+          return;
+        }
+
+      zvni->local_vtep_ip = vxl->vtep_ip;
+      zvni->vxlan_if = ifp;
+
+      /* Inform BGP if interface is up and mapped to bridge. */
+      if (if_is_operative (ifp) &&
+          zif->brslave_info.br_if)
+        zvni_send_add_to_client (zvrf, zvni);
+    }
+}
+
+/*
+ * See if remote VTEP matches with prefix.
+ */
+static int
+zvni_vtep_match (struct in_addr *vtep_ip, zebra_vtep_t *zvtep)
+{
+  return (IPV4_ADDR_SAME (vtep_ip, &zvtep->vtep_ip));
+}
+
+/*
+ * Locate remote VTEP in VNI hash table.
+ */
+static zebra_vtep_t *
+zvni_vtep_find (zebra_vni_t *zvni, struct in_addr *vtep_ip)
+{
+  zebra_vtep_t *zvtep;
+
+  if (!zvni)
+    return NULL;
+
+  for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next)
+    {
+      if (zvni_vtep_match (vtep_ip, zvtep))
+        break;
+    }
+
+  return zvtep;
+}
+
+/*
+ * Add remote VTEP to VNI hash table.
+ */
+static zebra_vtep_t *
+zvni_vtep_add (zebra_vni_t *zvni, struct in_addr *vtep_ip)
+{
+  zebra_vtep_t *zvtep;
+
+  zvtep = XCALLOC (MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t));
+  if (!zvtep)
+    {
+      zlog_err ("Failed to alloc VTEP entry, VNI %u", zvni->vni);
+      return NULL;
+    }
+
+  zvtep->vtep_ip = *vtep_ip;
+
+  if (zvni->vteps)
+    zvni->vteps->prev = zvtep;
+  zvtep->next = zvni->vteps;
+  zvni->vteps = zvtep;
+
+  return zvtep;
+}
+
+/*
+ * Remove remote VTEP from VNI hash table.
+ */
+static int
+zvni_vtep_del (zebra_vni_t *zvni, zebra_vtep_t *zvtep)
+{
+  if (zvtep->next)
+    zvtep->next->prev = zvtep->prev;
+  if (zvtep->prev)
+    zvtep->prev->next = zvtep->next;
+  else
+    zvni->vteps = zvtep->next;
+
+  zvtep->prev = zvtep->next = NULL;
+  XFREE (MTYPE_ZVNI_VTEP, zvtep);
+
+  return 0;
+}
+
+/*
+ * Delete all remote VTEPs for this VNI (upon VNI delete). Also
+ * uninstall from kernel if asked to.
+ */
+static int
+zvni_vtep_del_all (zebra_vni_t *zvni, int uninstall)
+{
+  zebra_vtep_t *zvtep, *zvtep_next;
+
+  if (!zvni)
+    return -1;
+
+  for (zvtep = zvni->vteps; zvtep; zvtep = zvtep_next)
+    {
+      zvtep_next = zvtep->next;
+      if (uninstall)
+        zvni_vtep_uninstall (zvni, &zvtep->vtep_ip);
+      zvni_vtep_del (zvni, zvtep);
+    }
+
+  return 0;
+}
+
+/*
+ * Install remote VTEP into the kernel.
+ */
+static int
+zvni_vtep_install (zebra_vni_t *zvni, struct in_addr *vtep_ip)
+{
+  return kernel_add_vtep (zvni->vni, zvni->vxlan_if, vtep_ip);
+}
+
+/*
+ * Uninstall remote VTEP from the kernel.
+ */
+static int
+zvni_vtep_uninstall (zebra_vni_t *zvni, struct in_addr *vtep_ip)
+{
+  if (!zvni->vxlan_if)
+    {
+      zlog_err ("VNI %u hash %p couldn't be uninstalled - no intf",
+                zvni->vni, zvni);
+      return -1;
+    }
+
+  return kernel_del_vtep (zvni->vni, zvni->vxlan_if, vtep_ip);
+}
+
+/*
+ * Cleanup VNI/VTEP and update kernel
+ */
+static void
+zvni_cleanup_all (struct hash_backet *backet, void *zvrf)
+{
+  zebra_vni_t *zvni;
+
+  zvni = (zebra_vni_t *) backet->data;
+  if (!zvni)
+    return;
+
+  /* Free up all remote VTEPs, if any. */
+  zvni_vtep_del_all (zvni, 1);
+
+  /* Delete the hash entry. */
+  zvni_del (zvrf, zvni);
+}
+
+
+/* Public functions */
+
+/*
+ * Handle message from client to delete a remote VTEP for a VNI.
+ */
+int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock,
+                                 u_short length, struct zebra_vrf *zvrf)
+{
+  struct stream *s;
+  u_short l = 0;
+  vni_t vni;
+  struct in_addr vtep_ip;
+  zebra_vni_t *zvni;
+  zebra_vtep_t *zvtep;
+
+  s = client->ibuf;
+
+  while (l < length)
+    {
+      /* Obtain each remote VTEP and process. */
+      vni = (vni_t) stream_getl (s);
+      l += 4;
+      vtep_ip.s_addr = stream_get_ipv4 (s);
+      l += IPV4_MAX_BYTELEN;
+
+      if (IS_ZEBRA_DEBUG_VXLAN)
+        zlog_debug ("%u:Recv VTEP_DEL %s VNI %u from %s",
+                    zvrf_id (zvrf), inet_ntoa (vtep_ip),
+                    vni, zebra_route_string (client->proto));
+
+      /* Locate VNI hash entry - expected to exist. */
+      zvni = zvni_lookup (zvrf, vni);
+      if (!zvni)
+        {
+          if (IS_ZEBRA_DEBUG_VXLAN)
+            zlog_debug ("Failed to locate VNI hash upon remote VTEP DEL, "
+                        "VRF %d VNI %u", zvrf_id (zvrf), vni);
+          continue;
+        }
+
+      /* If the remote VTEP does not exist, there's nothing more to do.
+       * Otherwise, uninstall any remote MACs pointing to this VTEP and
+       * then, the VTEP entry itself and remove it.
+       */
+      zvtep = zvni_vtep_find (zvni, &vtep_ip);
+      if (!zvtep)
+        continue;
+
+      zvni_vtep_uninstall (zvni, &vtep_ip);
+      zvni_vtep_del (zvni, zvtep);
+    }
+
+  return 0;
+}
+
+/*
+ * Handle message from client to add a remote VTEP for a VNI.
+ */
+int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock,
+                                 u_short length, struct zebra_vrf *zvrf)
+{
+  struct stream *s;
+  u_short l = 0;
+  vni_t vni;
+  struct in_addr vtep_ip;
+  zebra_vni_t *zvni;
+
+  assert (EVPN_ENABLED (zvrf));
+
+  s = client->ibuf;
+
+  while (l < length)
+    {
+      /* Obtain each remote VTEP and process. */
+      vni = (vni_t) stream_getl (s);
+      l += 4;
+      vtep_ip.s_addr = stream_get_ipv4 (s);
+      l += IPV4_MAX_BYTELEN;
+
+      if (IS_ZEBRA_DEBUG_VXLAN)
+        zlog_debug ("%u:Recv VTEP_ADD %s VNI %u from %s",
+                    zvrf_id (zvrf), inet_ntoa (vtep_ip),
+                    vni, zebra_route_string (client->proto));
+
+      /* Locate VNI hash entry - expected to exist. */
+      zvni = zvni_lookup (zvrf, vni);
+      if (!zvni)
+        {
+          zlog_err ("Failed to locate VNI hash upon remote VTEP ADD, VRF %d VNI %u",
+                    zvrf_id (zvrf), vni);
+          continue;
+        }
+      if (!zvni->vxlan_if)
+        {
+          zlog_err ("VNI %u hash %p doesn't have intf upon remote VTEP ADD",
+                    zvni->vni, zvni);
+          continue;
+        }
+
+
+      /* If the remote VTEP already exists, or the local VxLAN interface is
+       * not up (should be a transient event),  there's nothing more to do.
+       * Otherwise, add and install the entry.
+       */
+      if (zvni_vtep_find (zvni, &vtep_ip))
+        continue;
+
+      if (!if_is_operative (zvni->vxlan_if))
+        continue;
+
+      if (zvni_vtep_add (zvni, &vtep_ip) == NULL)
+        {
+          zlog_err ("Failed to add remote VTEP, VRF %d VNI %u zvni %p",
+                    zvrf_id (zvrf), vni, zvni);
+          continue;
+        }
+
+      zvni_vtep_install (zvni, &vtep_ip);
+    }
+
+  return 0;
+}
+
+/*
+ * Handle VxLAN interface down - update BGP if required, and do
+ * internal cleanup.
+ */
+int
+zebra_vxlan_if_down (struct interface *ifp)
+{
+  struct zebra_if *zif;
+  struct zebra_vrf *zvrf;
+  zebra_vni_t *zvni;
+  struct zebra_l2info_vxlan *vxl;
+  vni_t vni;
+
+  /* Locate VRF corresponding to interface. */
+  zvrf = vrf_info_lookup(ifp->vrf_id);
+  assert(zvrf);
+
+  /* If EVPN is not enabled, nothing further to be done. */
+  if (!EVPN_ENABLED(zvrf))
+    return 0;
+
+  zif = ifp->info;
+  assert(zif);
+  vxl = &zif->l2info.vxl;
+  vni = vxl->vni;
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Intf %s(%u) VNI %u is DOWN",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+
+  /* Locate hash entry; it is expected to exist. */
+  zvni = zvni_lookup (zvrf, vni);
+  if (!zvni)
+    {
+      zlog_err ("Failed to locate VNI hash at DOWN, VRF %d IF %s(%u) VNI %u",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+      return -1;
+    }
+
+  assert (zvni->vxlan_if == ifp);
+
+  /* Delete this VNI from BGP. */
+  zvni_send_del_to_client (zvrf, zvni->vni);
+
+  /* Free up all remote VTEPs, if any. */
+  zvni_vtep_del_all (zvni, 1);
+
+  return 0;
+}
+
+/*
+ * Handle VxLAN interface up - update BGP if required.
+ */
+int
+zebra_vxlan_if_up (struct interface *ifp)
+{
+  struct zebra_if *zif;
+  struct zebra_vrf *zvrf;
+  zebra_vni_t *zvni;
+  struct zebra_l2info_vxlan *vxl;
+  vni_t vni;
+
+  /* Locate VRF corresponding to interface. */
+  zvrf = vrf_info_lookup(ifp->vrf_id);
+  assert(zvrf);
+
+  /* If EVPN is not enabled, nothing further to be done. */
+  if (!EVPN_ENABLED(zvrf))
+    return 0;
+
+  zif = ifp->info;
+  assert(zif);
+  vxl = &zif->l2info.vxl;
+  vni = vxl->vni;
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Intf %s(%u) VNI %u is UP",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+
+  /* Locate hash entry; it is expected to exist. */
+  zvni = zvni_lookup (zvrf, vni);
+  if (!zvni)
+    {
+      zlog_err ("Failed to locate VNI hash at UP, VRF %d IF %s(%u) VNI %u",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+      return -1;
+    }
+
+  assert (zvni->vxlan_if == ifp);
+
+  /* If part of a bridge, inform BGP about this VNI. */
+  if (zif->brslave_info.br_if)
+    zvni_send_add_to_client (zvrf, zvni);
+
+  return 0;
+}
+
+/*
+ * Handle VxLAN interface delete. Locate and remove entry in hash table
+ * and update BGP, if required.
+ */
+int
+zebra_vxlan_if_del (struct interface *ifp)
+{
+  struct zebra_if *zif;
+  struct zebra_vrf *zvrf;
+  zebra_vni_t *zvni;
+  struct zebra_l2info_vxlan *vxl;
+  vni_t vni;
+
+  /* Locate VRF corresponding to interface. */
+  zvrf = vrf_info_lookup(ifp->vrf_id);
+  assert(zvrf);
+
+  /* If EVPN is not enabled, nothing further to be done. */
+  if (!EVPN_ENABLED(zvrf))
+    return 0;
+
+  zif = ifp->info;
+  assert(zif);
+  vxl = &zif->l2info.vxl;
+  vni = vxl->vni;
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Del intf %s(%u) VNI %u",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+
+  /* Locate hash entry; it is expected to exist. */
+  zvni = zvni_lookup (zvrf, vni);
+  if (!zvni)
+    {
+      zlog_err ("Failed to locate VNI hash at del, VRF %d IF %s(%u) VNI %u",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+      return 0;
+    }
+
+  /* Delete VNI from BGP. */
+  zvni_send_del_to_client (zvrf, zvni->vni);
+
+  /* Free up all remote VTEPs, if any. */
+  zvni_vtep_del_all (zvni, 0);
+
+  /* Delete the hash entry. */
+  if (zvni_del (zvrf, zvni))
+    {
+      zlog_err ("Failed to del VNI hash %p, VRF %d IF %s(%u) VNI %u",
+                zvni, ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni);
+      return -1;
+    }
+
+  return 0;
+}
+
+/*
+ * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
+ */
+int
+zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags)
+{
+  struct zebra_if *zif;
+  struct zebra_vrf *zvrf;
+  zebra_vni_t *zvni;
+  struct zebra_l2info_vxlan *vxl;
+  vni_t vni;
+
+  /* Locate VRF corresponding to interface. */
+  zvrf = vrf_info_lookup(ifp->vrf_id);
+  assert(zvrf);
+
+  /* If EVPN is not enabled, nothing further to be done. */
+  if (!EVPN_ENABLED(zvrf))
+    return 0;
+
+  zif = ifp->info;
+  assert(zif);
+  vxl = &zif->l2info.vxl;
+  vni = vxl->vni;
+
+  /* Update VNI hash. */
+  zvni = zvni_lookup (zvrf, vni);
+  if (!zvni)
+    {
+      zlog_err ("Failed to find VNI hash on update, VRF %d IF %s(%u) VNI %u",
+                ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+      return -1;
+    }
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Update intf %s(%u) VNI %u VLAN %u local IP %s "
+                "master %u chg 0x%x",
+                ifp->vrf_id, ifp->name, ifp->ifindex,
+                vni, vxl->access_vlan,
+                inet_ntoa (vxl->vtep_ip),
+                zif->brslave_info.bridge_ifindex, chgflags);
+
+  /* Removed from bridge? */
+  if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) &&
+      (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL))
+    {
+      /* Delete from client, remove all remote VTEPs */
+      zvni_send_del_to_client (zvrf, zvni->vni);
+      zvni_vtep_del_all (zvni, 1);
+    }
+
+  zvni->local_vtep_ip = vxl->vtep_ip;
+  zvni->vxlan_if = ifp;
+
+  /* Take further actions needed. Note that if we are here, there is a
+   * change of interest.
+   */
+  /* If down or not mapped to a bridge, we're done. */
+  if (!if_is_operative (ifp) || !zif->brslave_info.br_if)
+    return 0;
+
+  /* Inform BGP. */
+  zvni_send_add_to_client (zvrf, zvni);
+
+  return 0;
+}
+
+/*
+ * Handle VxLAN interface add.
+ */
+int
+zebra_vxlan_if_add (struct interface *ifp)
+{
+  struct zebra_if *zif;
+  struct zebra_vrf *zvrf;
+  zebra_vni_t *zvni;
+  struct zebra_l2info_vxlan *vxl;
+  vni_t vni;
+
+  /* Locate VRF corresponding to interface. */
+  zvrf = vrf_info_lookup(ifp->vrf_id);
+  assert(zvrf);
+
+  /* If EVPN is not enabled, nothing further to be done. */
+  if (!EVPN_ENABLED(zvrf))
+    return 0;
+
+  zif = ifp->info;
+  assert(zif);
+  vxl = &zif->l2info.vxl;
+  vni = vxl->vni;
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:Add intf %s(%u) VNI %u VLAN %u local IP %s master %u",
+                ifp->vrf_id, ifp->name, ifp->ifindex,
+                vni, vxl->access_vlan,
+                inet_ntoa (vxl->vtep_ip),
+                zif->brslave_info.bridge_ifindex);
+
+  /* Create or update VNI hash. */
+  zvni = zvni_lookup (zvrf, vni);
+  if (!zvni)
+    {
+      zvni = zvni_add (zvrf, vni);
+      if (!zvni)
+        {
+          zlog_err ("Failed to add VNI hash, VRF %d IF %s(%u) VNI %u",
+                    ifp->vrf_id, ifp->name, ifp->ifindex, vni);
+          return -1;
+        }
+    }
+
+  zvni->local_vtep_ip = vxl->vtep_ip;
+  zvni->vxlan_if = ifp;
+
+  /* If down or not mapped to a bridge, we're done. */
+  if (!if_is_operative (ifp) || !zif->brslave_info.br_if)
+    return 0;
+
+  /* Inform BGP */
+  zvni_send_add_to_client (zvrf, zvni);
+
+  return 0;
+}
+
+/*
+ * Handle message from client to learn (or stop learning) about VNIs and MACs.
+ * When enabled, the VNI hash table will be built and MAC FDB table read;
+ * when disabled, the entries should be deleted and remote VTEPs and MACs
+ * uninstalled from the kernel.
+ */
+int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock,
+                                   u_short length, struct zebra_vrf *zvrf)
+{
+  struct stream *s;
+  int advertise;
+
+  s = client->ibuf;
+  advertise = stream_getc (s);
+
+  if (IS_ZEBRA_DEBUG_VXLAN)
+    zlog_debug ("%u:EVPN VNI Adv %s, currently %s",
+                zvrf_id (zvrf), advertise ? "enabled" : "disabled",
+                EVPN_ENABLED(zvrf) ? "enabled" : "disabled");
+
+  if (zvrf->advertise_all_vni == advertise)
+    return 0;
+
+  zvrf->advertise_all_vni = advertise;
+  if (EVPN_ENABLED(zvrf))
+    {
+      /* Build VNI hash table and inform BGP. */
+      zvni_build_hash_table (zvrf);
+    }
+  else
+    {
+      /* Cleanup VTEPs for all VNIs - uninstall from
+       * kernel and free entries.
+       */
+      hash_iterate (zvrf->vni_table, zvni_cleanup_all, zvrf);
+    }
+
+  return 0;
+}
+
+/*
+ * Allocate VNI hash table for this VRF and do other initialization.
+ * NOTE: Currently supported only for default VRF.
+ */
+void
+zebra_vxlan_init_tables (struct zebra_vrf *zvrf)
+{
+  if (!zvrf)
+    return;
+  zvrf->vni_table = hash_create(vni_hash_keymake,
+                               vni_hash_cmp,
+                               "Zebra VRF VNI Table");
+}
+
+/* Close all VNI handling */
+void
+zebra_vxlan_close_tables (struct zebra_vrf *zvrf)
+{
+  hash_iterate (zvrf->vni_table, zvni_cleanup_all, zvrf);
+}
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
new file mode 100644 (file)
index 0000000..0e8d783
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Zebra VxLAN (EVPN) Data structures and definitions
+ * These are public definitions referenced by other files.
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_VXLAN_H
+#define _ZEBRA_VXLAN_H
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+#include "zebra/interface.h"
+#include "zebra/zebra_vrf.h"
+
+/* Is EVPN enabled? */
+#define EVPN_ENABLED(zvrf)  (zvrf)->advertise_all_vni
+
+/* VxLAN interface change flags of interest. */
+#define ZEBRA_VXLIF_LOCAL_IP_CHANGE     0x1
+#define ZEBRA_VXLIF_MASTER_CHANGE       0x2
+#define ZEBRA_VXLIF_VLAN_CHANGE         0x4
+
+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);
+extern int zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags);
+extern int zebra_vxlan_if_del (struct interface *ifp);
+extern int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock,
+                                        u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock,
+                                        u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock,
+                                          u_short length, struct zebra_vrf *zvrf);
+extern void zebra_vxlan_init_tables (struct zebra_vrf *zvrf);
+extern void zebra_vxlan_close_tables (struct zebra_vrf *);
+
+#endif /* _ZEBRA_VXLAN_H */
diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c
new file mode 100644 (file)
index 0000000..532ab64
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Zebra VxLAN (EVPN)
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "zebra/debug.h"
+#include "zebra/zserv.h"
+#include "zebra/rib.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_l2.h"
+#include "zebra/zebra_vxlan.h"
+
+int
+zebra_vxlan_if_up (struct interface *ifp)
+{
+  return 0;
+}
+
+int
+zebra_vxlan_if_down (struct interface *ifp)
+{
+  return 0;
+}
+
+int
+zebra_vxlan_if_add (struct interface *ifp)
+{
+  return 0;
+}
+
+int
+zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags)
+{
+  return 0;
+}
+
+int
+zebra_vxlan_if_del (struct interface *ifp)
+{
+  return 0;
+}
+
+int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock,
+                                 u_short length, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock,
+                                 u_short length, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock,
+                                   u_short length, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+void
+zebra_vxlan_init_tables (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_vxlan_close_tables (struct zebra_vrf *zvrf)
+{
+}
index 3da94459f7711cc4b376841de0000aef8f433735..c6a9c38c35981a683a25fc7c98e1a871655b1b83 100644 (file)
@@ -54,6 +54,7 @@
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_mroute.h"
 #include "zebra/label_manager.h"
+#include "zebra/zebra_vxlan.h"
 
 /* Event list of zebra. */
 enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -2434,6 +2435,15 @@ zebra_client_read (struct thread *thread)
     case ZEBRA_FEC_UNREGISTER:
       zserv_fec_unregister (client, sock, length);
       break;
+    case ZEBRA_ADVERTISE_ALL_VNI:
+      zebra_vxlan_advertise_all_vni (client, sock, length, zvrf);
+      break;
+    case ZEBRA_REMOTE_VTEP_ADD:
+      zebra_vxlan_remote_vtep_add (client, sock, length, zvrf);
+      break;
+    case ZEBRA_REMOTE_VTEP_DEL:
+      zebra_vxlan_remote_vtep_del (client, sock, length, zvrf);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;
@@ -2725,7 +2735,8 @@ zebra_show_client_detail (struct vty *vty, struct zserv *client)
        client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
   vty_outln (vty, "Interface Up Notifications: %d",client->ifup_cnt);
   vty_outln (vty, "Interface Down Notifications: %d",client->ifdown_cnt);
-
+  vty_outln (vty, "VNI add notifications: %d", client->vniadd_cnt);
+  vty_outln (vty, "VNI delete notifications: %d", client->vnidel_cnt);
   vty_out (vty, VTYNL);
   return;
 }
index dcc98d83f75c9a7206f9f6d56edd6fe830494391..c8f006d44b7c8781092028a6e72507bb68bc2839 100644 (file)
@@ -105,6 +105,8 @@ struct zserv
   u_int32_t vrfdel_cnt;
   u_int32_t if_vrfchg_cnt;
   u_int32_t bfd_client_reg_cnt;
+  u_int32_t vniadd_cnt;
+  u_int32_t vnidel_cnt;
 
   time_t connect_time;
   time_t last_read_time;