mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 10:54:47 +00:00
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 <vivek@cumulusnetworks.com> Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
18a7a601c7
commit
13d60d351c
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
905
zebra/zebra_vxlan.c
Normal file
905
zebra/zebra_vxlan.c
Normal file
@ -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);
|
||||
}
|
59
zebra/zebra_vxlan.h
Normal file
59
zebra/zebra_vxlan.h
Normal file
@ -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 */
|
89
zebra/zebra_vxlan_null.c
Normal file
89
zebra/zebra_vxlan_null.c
Normal file
@ -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)
|
||||
{
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user