From 13d60d351c4c70e8a2949ef45d88ec4efe382367 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 14 May 2017 22:38:26 -0700 Subject: [PATCH] zebra: VNI and VTEP handling 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 Reviewed-by: Donald Sharp --- lib/log.c | 5 + lib/zclient.h | 5 + zebra/Makefile.am | 3 +- zebra/debug.c | 34 ++ zebra/debug.h | 4 + zebra/if_netlink.c | 9 + zebra/interface.c | 7 + zebra/rt.h | 5 + zebra/rt_netlink.c | 67 +++ zebra/rt_socket.c | 13 + zebra/zebra_l2.c | 15 +- zebra/zebra_vrf.c | 5 + zebra/zebra_vrf.h | 9 + zebra/zebra_vxlan.c | 905 +++++++++++++++++++++++++++++++++++++++ zebra/zebra_vxlan.h | 59 +++ zebra/zebra_vxlan_null.c | 89 ++++ zebra/zserv.c | 13 +- zebra/zserv.h | 2 + 18 files changed, 1246 insertions(+), 3 deletions(-) create mode 100644 zebra/zebra_vxlan.c create mode 100644 zebra/zebra_vxlan.h create mode 100644 zebra/zebra_vxlan_null.c diff --git a/lib/log.c b/lib/log.c index 1c61d7216..7a7545201 100644 --- 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 diff --git a/lib/zclient.h b/lib/zclient.h index 59412fdd4..0c9f70751 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -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 diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 25e6b1bc1..2bb9da0a9 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -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) diff --git a/zebra/debug.c b/zebra/debug.c index ba2a9ad2a..0b0a0e988 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -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 [] [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 []", @@ -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); diff --git a/zebra/debug.h b/zebra/debug.h index 0a50da817..5687a3516 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -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); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 972e6447f..d0907a267 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -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) diff --git a/zebra/interface.c b/zebra/interface.c index 78ba8cdde..87b0896f9 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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); diff --git a/zebra/rt.h b/zebra/rt.h index a39af87b5..10ca6c95c 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -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 */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 471f65058..7ff03e7c0 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -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. */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 9859a3162..bf7e3403e 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -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; +} diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 5dd83baed..b71b96a18 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -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); } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 165689267..32c636e5e 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -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; diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 790e2e53d..29f7df00f 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -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 index 000000000..fcf432847 --- /dev/null +++ b/zebra/zebra_vxlan.c @@ -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 + +#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 index 000000000..0e8d783a3 --- /dev/null +++ b/zebra/zebra_vxlan.h @@ -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 + +#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 index 000000000..532ab6429 --- /dev/null +++ b/zebra/zebra_vxlan_null.c @@ -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 + +#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) +{ +} diff --git a/zebra/zserv.c b/zebra/zserv.c index 3da94459f..c6a9c38c3 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -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; } diff --git a/zebra/zserv.h b/zebra/zserv.h index dcc98d83f..c8f006d44 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -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; -- 2.39.5