2017-05-15 07:38:26 +02:00
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "hash.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "if.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "jhash.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "linklist.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "log.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "prefix.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "stream.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "table.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "vlan.h"
|
|
|
|
#include "vxlan.h"
|
2018-07-07 06:46:46 +02:00
|
|
|
#ifdef GNU_LINUX
|
|
|
|
#include <linux/neighbour.h>
|
|
|
|
#endif
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
#include "zebra/zebra_router.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "zebra/debug.h"
|
|
|
|
#include "zebra/interface.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "zebra/rib.h"
|
|
|
|
#include "zebra/rt.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "zebra/rt_netlink.h"
|
|
|
|
#include "zebra/zebra_errors.h"
|
|
|
|
#include "zebra/zebra_l2.h"
|
|
|
|
#include "zebra/zebra_memory.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "zebra/zebra_ns.h"
|
|
|
|
#include "zebra/zebra_vrf.h"
|
|
|
|
#include "zebra/zebra_vxlan.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "zebra/zebra_vxlan_private.h"
|
2019-01-11 19:31:46 +01:00
|
|
|
#include "zebra/zebra_router.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-16 23:57:42 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
|
2017-07-17 14:03:14 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
|
2017-10-08 03:49:27 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
|
2017-05-15 07:38:26 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
|
2017-07-17 14:03:14 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
|
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
|
2019-03-26 21:30:29 +01:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
|
2017-05-15 07:38:26 +02:00
|
|
|
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
|
|
|
|
bool delete, const char *reason), (rmac, zl3vni, delete, reason))
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/* definitions */
|
2019-03-19 18:37:22 +01:00
|
|
|
/* PMSI strings. */
|
|
|
|
#define VXLAN_FLOOD_STR_NO_INFO "-"
|
|
|
|
#define VXLAN_FLOOD_STR_DEFAULT VXLAN_FLOOD_STR_NO_INFO
|
|
|
|
static const struct message zvtep_flood_str[] = {
|
|
|
|
{VXLAN_FLOOD_DISABLED, VXLAN_FLOOD_STR_NO_INFO},
|
|
|
|
{VXLAN_FLOOD_PIM_SM, "PIM-SM"},
|
|
|
|
{VXLAN_FLOOD_HEAD_END_REPL, "HER"},
|
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
/* static function declarations */
|
2018-03-06 20:02:52 +01:00
|
|
|
static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
|
|
|
|
uint16_t cmd);
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt);
|
|
|
|
static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt);
|
|
|
|
static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
|
2017-06-22 01:37:51 +02:00
|
|
|
void **args);
|
2017-10-17 13:32:31 +02:00
|
|
|
static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
|
|
|
|
json_object *json);
|
2017-10-17 14:25:47 +02:00
|
|
|
static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
|
|
|
|
json_object *json);
|
2018-10-26 22:57:23 +02:00
|
|
|
static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json);
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt);
|
|
|
|
static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt);
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print(zebra_vni_t *zvni, void **ctxt);
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct ipaddr *ip, uint8_t flags,
|
2019-01-15 00:19:48 +01:00
|
|
|
uint32_t seq, int state, uint16_t cmd);
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int neigh_hash_keymake(const void *p);
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_neigh_alloc(void *p);
|
2017-07-06 00:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
|
|
|
|
struct ethaddr *mac);
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n);
|
|
|
|
static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip);
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct ethaddr *macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint8_t flags, uint32_t seq);
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct ethaddr *macaddr,
|
2019-01-15 00:19:48 +01:00
|
|
|
uint8_t flags, int state);
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
|
|
|
|
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
|
zebra: probe local inactive neigh
In extended-mobility case ({IP1, MAC} binding),
when a MAC moves from local to remote, binding
changes to {IP2, MAC}, local neigh (IP1) marked
as inactive in frr.
The evpn draft recommends to probe the entry once
local binding changes from local to remote.
Once the probe is set for the local neigh entry,
kernel will attempt refresh the entry via sending
unicast address resolution message, if host does not
reply, it will mark FAILED state.
For FAILED entry, kernel triggers delete neigh
request, which result in frr to remove inactive entry.
In absence of probing and aging out entry,
if MAC moves back to local with {IP3, MAC},
frr will mark both IP1 and IP3 as active and sends
type-2 update for both.
The IP1 may not be active host and still frr advertises
the route.
Ticket:CM-22864
Testing Done:
Validate the MAC mobilty in extended mobility scenario,
where local inactive entry gets removed once MAC moves
to remote state.
Once probe is set to the local entry, kernel triggers
reachability of the neigh/arp entry, since MAC moved remote,
ARP request goes to remote VTEP where host is not residing,
thus local neigh entry goes to failed state.
Frr receives neighbor delete faster and removes the entry.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-01-29 00:37:03 +01:00
|
|
|
static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n);
|
2017-10-08 03:49:27 +02:00
|
|
|
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
|
2018-03-06 20:02:52 +01:00
|
|
|
struct interface *br_if);
|
|
|
|
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
|
2019-08-02 08:33:24 +02:00
|
|
|
static struct interface *zvni_map_to_macvlan(struct interface *br_if,
|
|
|
|
struct interface *svi_if);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* l3-vni next-hop neigh related APIs */
|
2017-10-13 10:13:48 +02:00
|
|
|
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
|
2017-10-08 03:49:27 +02:00
|
|
|
struct ipaddr *ip);
|
|
|
|
static void *zl3vni_nh_alloc(void *p);
|
|
|
|
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
|
|
|
|
struct ipaddr *vtep_ip,
|
|
|
|
struct ethaddr *rmac);
|
|
|
|
static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
|
|
|
static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
2017-10-13 10:13:48 +02:00
|
|
|
static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* l3-vni rmac related APIs */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
|
2017-10-13 10:13:48 +02:00
|
|
|
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
|
2017-10-08 03:49:27 +02:00
|
|
|
struct ethaddr *rmac);
|
|
|
|
static void *zl3vni_rmac_alloc(void *p);
|
|
|
|
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
|
|
|
|
struct ethaddr *rmac);
|
|
|
|
static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
|
|
|
|
static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* l3-vni related APIs*/
|
|
|
|
static zebra_l3vni_t *zl3vni_lookup(vni_t vni);
|
|
|
|
static void *zl3vni_alloc(void *p);
|
|
|
|
static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
|
|
|
|
static int zl3vni_del(zebra_l3vni_t *zl3vni);
|
|
|
|
static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni);
|
|
|
|
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
|
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int mac_hash_keymake(const void *p);
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool mac_cmp(const void *p1, const void *p2);
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_mac_alloc(void *p);
|
|
|
|
static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr);
|
|
|
|
static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac);
|
|
|
|
static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip);
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint8_t flags, uint32_t seq);
|
2018-10-11 17:48:42 +02:00
|
|
|
static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr);
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
|
|
|
|
struct interface *br_if, vlanid_t vid);
|
|
|
|
static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac);
|
2018-08-29 02:02:40 +02:00
|
|
|
static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac);
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int vni_hash_keymake(const void *p);
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_alloc(void *p);
|
2017-09-18 23:45:34 +02:00
|
|
|
static zebra_vni_t *zvni_lookup(vni_t vni);
|
|
|
|
static zebra_vni_t *zvni_add(vni_t vni);
|
|
|
|
static int zvni_del(zebra_vni_t *zvni);
|
|
|
|
static int zvni_send_add_to_client(zebra_vni_t *zvni);
|
|
|
|
static int zvni_send_del_to_client(vni_t vni);
|
2019-01-24 10:12:36 +01:00
|
|
|
static void zvni_build_hash_table(void);
|
2017-07-17 14:03:14 +02:00
|
|
|
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);
|
2019-03-19 18:37:22 +01:00
|
|
|
static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip,
|
|
|
|
int flood_control);
|
2017-07-17 14:03:14 +02:00
|
|
|
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);
|
2019-03-19 18:37:22 +01:00
|
|
|
static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip);
|
2017-06-28 10:51:10 +02:00
|
|
|
static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
|
|
|
|
static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
|
|
|
|
static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
|
|
|
|
struct ethaddr *macaddr, struct ipaddr *ip);
|
|
|
|
static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
|
|
|
|
struct ipaddr *ip);
|
|
|
|
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
|
2017-09-18 23:45:34 +02:00
|
|
|
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
|
2019-02-05 17:38:35 +01:00
|
|
|
static int advertise_svi_macip_enabled(zebra_vni_t *zvni);
|
2018-11-02 16:30:41 +01:00
|
|
|
static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
|
|
|
|
zebra_mac_t *old_zmac,
|
|
|
|
zebra_mac_t *new_zmac,
|
|
|
|
zebra_neigh_t *nbr);
|
2018-08-29 02:22:04 +02:00
|
|
|
static int remote_neigh_count(zebra_mac_t *zmac);
|
|
|
|
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac);
|
2018-11-04 17:20:11 +01:00
|
|
|
static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t);
|
|
|
|
static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t);
|
2018-11-17 05:38:39 +01:00
|
|
|
static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
|
|
|
|
zebra_neigh_t *nbr,
|
|
|
|
struct in_addr vtep_ip,
|
|
|
|
bool do_dad,
|
|
|
|
bool *is_dup_detect,
|
|
|
|
bool is_local);
|
2018-11-18 01:03:19 +01:00
|
|
|
static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
|
|
|
|
zebra_mac_t *mac,
|
|
|
|
struct in_addr vtep_ip,
|
|
|
|
bool do_dad,
|
|
|
|
bool *is_dup_detect,
|
|
|
|
bool is_local);
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p);
|
2019-03-19 21:15:23 +01:00
|
|
|
static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2);
|
|
|
|
static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
|
|
|
|
struct in_addr sip, struct in_addr mcast_grp);
|
|
|
|
static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf,
|
|
|
|
struct in_addr sip, struct in_addr mcast_grp);
|
2019-03-19 21:26:22 +01:00
|
|
|
static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
|
|
|
|
struct in_addr mcast_grp);
|
|
|
|
static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
|
|
|
|
struct in_addr mcast_grp);
|
|
|
|
static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
static void zvni_send_mac_to_client(zebra_vni_t *zvn);
|
|
|
|
static void zvni_send_neigh_to_client(zebra_vni_t *zvni);
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/* Private functions */
|
2018-05-17 01:24:22 +02:00
|
|
|
static int host_rb_entry_compare(const struct host_rb_entry *hle1,
|
2018-05-21 13:18:18 +02:00
|
|
|
const struct host_rb_entry *hle2)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
if (hle1->p.family < hle2->p.family)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (hle1->p.family > hle2->p.family)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (hle1->p.prefixlen < hle2->p.prefixlen)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (hle1->p.prefixlen > hle2->p.prefixlen)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (hle1->p.family == AF_INET) {
|
|
|
|
if (hle1->p.u.prefix4.s_addr < hle2->p.u.prefix4.s_addr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (hle1->p.u.prefix4.s_addr > hle2->p.u.prefix4.s_addr)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
2018-09-05 23:04:35 +02:00
|
|
|
} else if (hle1->p.family == AF_INET6) {
|
|
|
|
return memcmp(&hle1->p.u.prefix6, &hle2->p.u.prefix6,
|
|
|
|
IPV6_MAX_BYTELEN);
|
2018-05-17 01:24:22 +02:00
|
|
|
} else {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("%s: Unexpected family type: %d",
|
|
|
|
__PRETTY_FUNCTION__, hle1->p.family);
|
2018-05-17 01:24:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_GENERATE(host_rb_tree_entry, host_rb_entry, hl_entry, host_rb_entry_compare);
|
2018-05-17 01:24:22 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
struct host_rb_entry *hle;
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, hrbe)
|
2018-05-17 01:24:22 +02:00
|
|
|
count++;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-05 07:30:53 +02:00
|
|
|
/*
|
|
|
|
* Return number of valid MACs in a VNI's MAC hash table - all
|
|
|
|
* remote MACs and non-internal (auto) local MACs count.
|
|
|
|
*/
|
2018-03-27 21:13:34 +02:00
|
|
|
static uint32_t num_valid_macs(zebra_vni_t *zvni)
|
2017-10-05 07:30:53 +02:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs = 0;
|
2017-10-05 07:30:53 +02:00
|
|
|
struct hash *hash;
|
2019-02-19 16:46:52 +01:00
|
|
|
struct hash_bucket *hb;
|
2017-10-05 07:30:53 +02:00
|
|
|
zebra_mac_t *mac;
|
|
|
|
|
|
|
|
hash = zvni->mac_table;
|
|
|
|
if (!hash)
|
|
|
|
return num_macs;
|
|
|
|
for (i = 0; i < hash->size; i++) {
|
|
|
|
for (hb = hash->index[i]; hb; hb = hb->next) {
|
|
|
|
mac = (zebra_mac_t *)hb->data;
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|
2018-07-28 20:23:10 +02:00
|
|
|
|| CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
|
2017-10-05 07:30:53 +02:00
|
|
|
|| !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
|
|
|
|
num_macs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_macs;
|
|
|
|
}
|
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
static uint32_t num_dup_detected_macs(zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
uint32_t num_macs = 0;
|
|
|
|
struct hash *hash;
|
2019-02-19 16:46:52 +01:00
|
|
|
struct hash_bucket *hb;
|
2018-11-04 19:17:29 +01:00
|
|
|
zebra_mac_t *mac;
|
|
|
|
|
|
|
|
hash = zvni->mac_table;
|
|
|
|
if (!hash)
|
|
|
|
return num_macs;
|
|
|
|
for (i = 0; i < hash->size; i++) {
|
|
|
|
for (hb = hash->index[i]; hb; hb = hb->next) {
|
|
|
|
mac = (zebra_mac_t *)hb->data;
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
|
|
|
num_macs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_macs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t num_dup_detected_neighs(zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
uint32_t num_neighs = 0;
|
|
|
|
struct hash *hash;
|
2019-02-19 16:46:52 +01:00
|
|
|
struct hash_bucket *hb;
|
2018-11-04 19:17:29 +01:00
|
|
|
zebra_neigh_t *nbr;
|
|
|
|
|
|
|
|
hash = zvni->neigh_table;
|
|
|
|
if (!hash)
|
|
|
|
return num_neighs;
|
|
|
|
for (i = 0; i < hash->size; i++) {
|
|
|
|
for (hb = hash->index[i]; hb; hb = hb->next) {
|
|
|
|
nbr = (zebra_neigh_t *)hb->data;
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
|
|
|
|
num_neighs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_neighs;
|
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
static int advertise_gw_macip_enabled(zebra_vni_t *zvni)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
2019-02-19 21:37:59 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2017-06-28 10:51:10 +02:00
|
|
|
if (zvrf && zvrf->advertise_gw_macip)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (zvni && zvni->advertise_gw_macip)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-05 17:38:35 +01:00
|
|
|
static int advertise_svi_macip_enabled(zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
2019-02-21 18:08:36 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2019-02-05 17:38:35 +01:00
|
|
|
if (zvrf && zvrf->advertise_svi_macip)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (zvni && zvni->advertise_svi_macip)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* As part Duplicate Address Detection (DAD) for IP mobility
|
2018-11-17 02:30:15 +01:00
|
|
|
* MAC binding changes, ensure to inherit duplicate flag
|
|
|
|
* from MAC.
|
2018-11-02 16:30:41 +01:00
|
|
|
*/
|
|
|
|
static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
|
|
|
|
zebra_mac_t *old_zmac,
|
|
|
|
zebra_mac_t *new_zmac,
|
|
|
|
zebra_neigh_t *nbr)
|
|
|
|
{
|
|
|
|
bool is_old_mac_dup = false;
|
|
|
|
bool is_new_mac_dup = false;
|
|
|
|
|
|
|
|
if (!zvrf->dup_addr_detect)
|
|
|
|
return 0;
|
|
|
|
/* Check old or new MAC is detected as duplicate
|
|
|
|
* mark this neigh as duplicate
|
|
|
|
*/
|
|
|
|
if (old_zmac)
|
|
|
|
is_old_mac_dup = CHECK_FLAG(old_zmac->flags,
|
|
|
|
ZEBRA_MAC_DUPLICATE);
|
|
|
|
if (new_zmac)
|
|
|
|
is_new_mac_dup = CHECK_FLAG(new_zmac->flags,
|
|
|
|
ZEBRA_MAC_DUPLICATE);
|
|
|
|
/* Old and/or new MAC can be in duplicate state,
|
|
|
|
* based on that IP/Neigh Inherits the flag.
|
|
|
|
* If New MAC is marked duplicate, inherit to the IP.
|
|
|
|
* If old MAC is duplicate but new MAC is not, clear
|
|
|
|
* duplicate flag for IP and reset detection params
|
|
|
|
* and let IP DAD retrigger.
|
|
|
|
*/
|
|
|
|
if (is_new_mac_dup && !CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
|
|
|
SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
/* Capture Duplicate detection time */
|
|
|
|
nbr->dad_dup_detect_time = monotime(NULL);
|
2019-03-22 18:02:07 +01:00
|
|
|
/* Mark neigh inactive */
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(nbr);
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
return 1;
|
|
|
|
} else if (is_old_mac_dup && !is_new_mac_dup) {
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->detect_start_time.tv_usec = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-18 01:03:19 +01:00
|
|
|
static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
|
|
|
|
zebra_mac_t *mac,
|
|
|
|
struct in_addr vtep_ip,
|
|
|
|
bool do_dad,
|
|
|
|
bool *is_dup_detect,
|
|
|
|
bool is_local)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *nbr;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct timeval elapsed = {0, 0};
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
bool reset_params = false;
|
|
|
|
|
|
|
|
if (!(zvrf->dup_addr_detect && do_dad))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* MAC is detected as duplicate,
|
|
|
|
* Local MAC event -> hold on advertising to BGP.
|
|
|
|
* Remote MAC event -> hold on installing it.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&mac->macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
mac->flags, mac->dad_count,
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
|
|
|
|
/* For duplicate MAC do not update
|
|
|
|
* client but update neigh due to
|
|
|
|
* this MAC update.
|
|
|
|
*/
|
|
|
|
if (zvrf->dad_freeze)
|
2018-12-17 23:36:27 +01:00
|
|
|
*is_dup_detect = true;
|
2018-11-18 01:03:19 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if detection time (M-secs) expired.
|
|
|
|
* Reset learn count and detection start time.
|
|
|
|
*/
|
|
|
|
monotime_since(&mac->detect_start_time, &elapsed);
|
|
|
|
reset_params = (elapsed.tv_sec > zvrf->dad_time);
|
|
|
|
if (is_local && !reset_params) {
|
|
|
|
/* RFC-7432: A PE/VTEP that detects a MAC mobility
|
|
|
|
* event via LOCAL learning starts an M-second timer.
|
|
|
|
*
|
|
|
|
* NOTE: This is the START of the probe with count is
|
|
|
|
* 0 during LOCAL learn event.
|
|
|
|
* (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
|
|
|
|
*/
|
|
|
|
reset_params = !mac->dad_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reset_params) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u"
|
|
|
|
, __PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&mac->macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
mac->flags, mac->dad_count);
|
|
|
|
|
|
|
|
mac->dad_count = 0;
|
|
|
|
/* Start dup. addr detection (DAD) start time,
|
|
|
|
* ONLY during LOCAL learn.
|
|
|
|
*/
|
|
|
|
if (is_local)
|
|
|
|
monotime(&mac->detect_start_time);
|
|
|
|
|
|
|
|
} else if (!is_local) {
|
|
|
|
/* For REMOTE MAC, increment detection count
|
|
|
|
* ONLY while in probe window, once window passed,
|
|
|
|
* next local learn event should trigger DAD.
|
|
|
|
*/
|
|
|
|
mac->dad_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For LOCAL MAC learn event, once count is reset above via either
|
|
|
|
* initial/start detection time or passed the probe time, the count
|
|
|
|
* needs to be incremented.
|
|
|
|
*/
|
|
|
|
if (is_local)
|
|
|
|
mac->dad_count++;
|
|
|
|
|
|
|
|
if (mac->dad_count >= zvrf->dad_max_moves) {
|
|
|
|
flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
|
|
|
|
"VNI %u: MAC %s detected as duplicate during %s VTEP %s",
|
|
|
|
mac->zvni->vni,
|
|
|
|
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
|
|
|
|
is_local ? "local update, last" :
|
|
|
|
"remote update, from", inet_ntoa(vtep_ip));
|
|
|
|
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
|
|
|
|
|
|
|
/* Capture Duplicate detection time */
|
|
|
|
mac->dad_dup_detect_time = monotime(NULL);
|
|
|
|
|
|
|
|
/* Mark all IPs/Neighs as duplicate
|
|
|
|
* associcated with this MAC
|
|
|
|
*/
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
|
|
|
|
|
|
|
|
/* Ony Mark IPs which are Local */
|
|
|
|
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
|
|
|
|
nbr->dad_dup_detect_time = monotime(NULL);
|
|
|
|
|
|
|
|
flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
|
|
|
"VNI %u: MAC %s IP %s detected as duplicate during %s update, inherit duplicate from MAC",
|
|
|
|
mac->zvni->vni,
|
|
|
|
prefix_mac2str(&mac->macaddr,
|
|
|
|
buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
|
|
|
|
is_local ? "local" : "remote");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start auto recovery timer for this MAC */
|
|
|
|
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
|
|
|
|
if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start"
|
|
|
|
, __PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&mac->macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
mac->flags, zvrf->dad_freeze_time);
|
|
|
|
|
2019-01-11 19:31:46 +01:00
|
|
|
thread_add_timer(zrouter.master,
|
2018-11-18 01:03:19 +01:00
|
|
|
zebra_vxlan_dad_mac_auto_recovery_exp,
|
|
|
|
mac, zvrf->dad_freeze_time,
|
|
|
|
&mac->dad_mac_auto_recovery_timer);
|
|
|
|
}
|
|
|
|
|
2018-12-17 23:36:27 +01:00
|
|
|
/* In case of local update, do not inform to client (BGPd),
|
2018-11-18 01:03:19 +01:00
|
|
|
* upd_neigh for neigh sequence change.
|
|
|
|
*/
|
|
|
|
if (zvrf->dad_freeze)
|
2018-12-17 23:36:27 +01:00
|
|
|
*is_dup_detect = true;
|
2018-11-18 01:03:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-17 05:38:39 +01:00
|
|
|
static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
|
|
|
|
zebra_neigh_t *nbr,
|
|
|
|
struct in_addr vtep_ip,
|
|
|
|
bool do_dad,
|
|
|
|
bool *is_dup_detect,
|
|
|
|
bool is_local)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct timeval elapsed = {0, 0};
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
bool reset_params = false;
|
|
|
|
|
|
|
|
if (!zvrf->dup_addr_detect)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* IP is detected as duplicate or inherit dup
|
|
|
|
* state, hold on to install as remote entry
|
|
|
|
* only if freeze is enabled.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: duplicate addr MAC %s IP %s flags 0x%x skip installing, learn count %u recover time %u",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
|
|
|
|
nbr->flags, nbr->dad_count,
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
|
|
|
|
if (zvrf->dad_freeze)
|
|
|
|
*is_dup_detect = true;
|
2019-01-24 21:19:53 +01:00
|
|
|
|
2018-11-17 05:38:39 +01:00
|
|
|
/* warn-only action, neigh will be installed.
|
|
|
|
* freeze action, it wil not be installed.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!do_dad)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Check if detection time (M-secs) expired.
|
|
|
|
* Reset learn count and detection start time.
|
|
|
|
* During remote mac add, count should already be 1
|
|
|
|
* via local learning.
|
|
|
|
*/
|
|
|
|
monotime_since(&nbr->detect_start_time, &elapsed);
|
|
|
|
reset_params = (elapsed.tv_sec > zvrf->dad_time);
|
|
|
|
|
|
|
|
if (is_local && !reset_params) {
|
|
|
|
/* RFC-7432: A PE/VTEP that detects a MAC mobility
|
|
|
|
* event via LOCAL learning starts an M-second timer.
|
|
|
|
*
|
|
|
|
* NOTE: This is the START of the probe with count is
|
|
|
|
* 0 during LOCAL learn event.
|
|
|
|
*/
|
|
|
|
reset_params = !nbr->dad_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reset_params) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: duplicate addr MAC %s IP %s flags 0x%x detection time passed, reset learn count %u",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
|
|
|
|
nbr->flags, nbr->dad_count);
|
|
|
|
/* Reset learn count but do not start detection
|
|
|
|
* during REMOTE learn event.
|
|
|
|
*/
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
/* Start dup. addr detection (DAD) start time,
|
|
|
|
* ONLY during LOCAL learn.
|
|
|
|
*/
|
|
|
|
if (is_local)
|
|
|
|
monotime(&nbr->detect_start_time);
|
|
|
|
|
|
|
|
} else if (!is_local) {
|
|
|
|
/* For REMOTE IP/Neigh, increment detection count
|
|
|
|
* ONLY while in probe window, once window passed,
|
|
|
|
* next local learn event should trigger DAD.
|
|
|
|
*/
|
|
|
|
nbr->dad_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For LOCAL IP/Neigh learn event, once count is reset above via either
|
|
|
|
* initial/start detection time or passed the probe time, the count
|
|
|
|
* needs to be incremented.
|
|
|
|
*/
|
|
|
|
if (is_local)
|
|
|
|
nbr->dad_count++;
|
|
|
|
|
|
|
|
if (nbr->dad_count >= zvrf->dad_max_moves) {
|
|
|
|
flog_warn(EC_ZEBRA_DUP_IP_DETECTED,
|
|
|
|
"VNI %u: MAC %s IP %s detected as duplicate during %s VTEP %s",
|
|
|
|
nbr->zvni->vni,
|
|
|
|
prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
|
|
|
|
is_local ? "local update, last" :
|
|
|
|
"remote update, from",
|
|
|
|
inet_ntoa(vtep_ip));
|
|
|
|
|
|
|
|
SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
|
|
|
|
/* Capture Duplicate detection time */
|
|
|
|
nbr->dad_dup_detect_time = monotime(NULL);
|
|
|
|
|
|
|
|
/* Start auto recovery timer for this IP */
|
|
|
|
THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
|
|
|
|
if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
|
|
|
|
nbr->flags, zvrf->dad_freeze_time);
|
|
|
|
|
2019-01-11 19:31:46 +01:00
|
|
|
thread_add_timer(zrouter.master,
|
2018-11-17 05:38:39 +01:00
|
|
|
zebra_vxlan_dad_ip_auto_recovery_exp,
|
|
|
|
nbr, zvrf->dad_freeze_time,
|
|
|
|
&nbr->dad_ip_auto_recovery_timer);
|
|
|
|
}
|
|
|
|
if (zvrf->dad_freeze)
|
|
|
|
*is_dup_detect = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Helper function to determine maximum width of neighbor IP address for
|
|
|
|
* display - just because we're dealing with IPv6 addresses that can
|
|
|
|
* widely vary.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
|
|
|
int width;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
n = (zebra_neigh_t *)bucket->data;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2018-09-14 15:47:41 +02:00
|
|
|
ipaddr2str(&n->ip, buf, sizeof(buf));
|
|
|
|
width = strlen(buf);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (width > wctx->addr_width)
|
|
|
|
wctx->addr_width = width;
|
2018-07-07 06:46:46 +02:00
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print a specific neighbor entry.
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2018-08-20 22:00:50 +02:00
|
|
|
const char *type_str;
|
|
|
|
const char *state_str;
|
|
|
|
bool flags_present = false;
|
2018-11-17 02:30:15 +01:00
|
|
|
struct zebra_vrf *zvrf = NULL;
|
2018-11-04 18:36:47 +01:00
|
|
|
struct timeval detect_start_time = {0, 0};
|
2019-07-10 16:16:59 +02:00
|
|
|
char timebuf[MONOTIME_STRLEN];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2019-03-22 11:08:01 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2018-11-17 02:30:15 +01:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2));
|
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
|
2018-08-20 22:00:50 +02:00
|
|
|
type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ?
|
|
|
|
"local" : "remote";
|
|
|
|
state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
|
2017-06-22 01:37:51 +02:00
|
|
|
vty = (struct vty *)ctxt;
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty, "IP: %s\n",
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
2018-08-20 22:00:50 +02:00
|
|
|
vty_out(vty, " Type: %s\n", type_str);
|
|
|
|
vty_out(vty, " State: %s\n", state_str);
|
|
|
|
vty_out(vty, " MAC: %s\n",
|
2017-06-22 01:37:51 +02:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
|
|
|
} else {
|
|
|
|
json_object_string_add(json, "ip", buf2);
|
2018-08-20 22:00:50 +02:00
|
|
|
json_object_string_add(json, "type", type_str);
|
|
|
|
json_object_string_add(json, "state", state_str);
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_string_add(json, "mac", buf1);
|
|
|
|
}
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
2017-07-06 00:03:14 +02:00
|
|
|
if (json == NULL) {
|
2018-08-20 22:00:50 +02:00
|
|
|
vty_out(vty, " Remote VTEP: %s\n",
|
2017-06-22 01:37:51 +02:00
|
|
|
inet_ntoa(n->r_vtep_ip));
|
2017-07-06 00:03:14 +02:00
|
|
|
} else
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_string_add(json, "remoteVtep",
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
|
|
|
}
|
2017-11-13 12:19:52 +01:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
|
2018-08-20 22:00:50 +02:00
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, " Flags: Default-gateway");
|
|
|
|
flags_present = true;
|
|
|
|
} else
|
2017-11-13 12:19:52 +01:00
|
|
|
json_object_boolean_true_add(json, "defaultGateway");
|
|
|
|
}
|
2018-07-07 06:46:46 +02:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) {
|
2018-08-20 22:00:50 +02:00
|
|
|
if (!json) {
|
|
|
|
vty_out(vty,
|
|
|
|
flags_present ? " ,Router" : " Flags: Router");
|
|
|
|
flags_present = true;
|
|
|
|
}
|
2018-07-07 06:46:46 +02:00
|
|
|
}
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (json == NULL) {
|
2018-08-20 22:00:50 +02:00
|
|
|
if (flags_present)
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, " Local Seq: %u Remote Seq: %u\n",
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->loc_seq, n->rem_seq);
|
2018-11-04 18:36:47 +01:00
|
|
|
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
|
|
|
vty_out(vty, " Duplicate, detected at %s",
|
2019-07-10 16:16:59 +02:00
|
|
|
time_to_string(n->dad_dup_detect_time,
|
|
|
|
timebuf));
|
2018-11-04 18:36:47 +01:00
|
|
|
} else if (n->dad_count) {
|
|
|
|
monotime_since(&n->detect_start_time,
|
|
|
|
&detect_start_time);
|
|
|
|
if (detect_start_time.tv_sec <= zvrf->dad_time) {
|
2019-07-10 16:16:59 +02:00
|
|
|
time_to_string(n->detect_start_time.tv_sec,
|
|
|
|
timebuf);
|
2018-11-04 18:36:47 +01:00
|
|
|
vty_out(vty,
|
|
|
|
" Duplicate detection started at %s, detection count %u\n",
|
2019-07-10 16:16:59 +02:00
|
|
|
timebuf, n->dad_count);
|
2018-11-04 18:36:47 +01:00
|
|
|
}
|
|
|
|
}
|
2018-08-20 22:00:50 +02:00
|
|
|
} else {
|
|
|
|
json_object_int_add(json, "localSequence", n->loc_seq);
|
|
|
|
json_object_int_add(json, "remoteSequence", n->rem_seq);
|
2018-11-04 18:36:47 +01:00
|
|
|
json_object_int_add(json, "detectionCount",
|
|
|
|
n->dad_count);
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
|
|
|
|
json_object_boolean_true_add(json, "isDuplicate");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json, "isDuplicate");
|
|
|
|
|
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print neighbor hash entry - called for display of all neighbors.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json_vni = NULL, *json_row = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n;
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
2018-08-20 22:00:50 +02:00
|
|
|
const char *state_str;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
vty = wctx->vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_vni = wctx->json;
|
2019-02-19 16:46:52 +01:00
|
|
|
n = (zebra_neigh_t *)bucket->data;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_vni)
|
|
|
|
json_row = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2));
|
2018-08-20 22:00:50 +02:00
|
|
|
state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)
|
|
|
|
return;
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_vni == NULL) {
|
2019-06-03 21:11:17 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %u/%u\n",
|
2018-08-20 22:00:50 +02:00
|
|
|
-wctx->addr_width, buf2, "local",
|
2019-06-03 21:11:17 +02:00
|
|
|
state_str, buf1, n->loc_seq, n->rem_seq);
|
2017-06-22 01:37:51 +02:00
|
|
|
} else {
|
|
|
|
json_object_string_add(json_row, "type", "local");
|
2018-08-20 22:00:50 +02:00
|
|
|
json_object_string_add(json_row, "state", state_str);
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_string_add(json_row, "mac", buf1);
|
2018-08-20 22:00:50 +02:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
|
|
|
|
json_object_boolean_true_add(
|
|
|
|
json_row, "defaultGateway");
|
|
|
|
json_object_int_add(json_row, "localSequence",
|
|
|
|
n->loc_seq);
|
|
|
|
json_object_int_add(json_row, "remoteSequence",
|
|
|
|
n->rem_seq);
|
2018-11-04 18:36:47 +01:00
|
|
|
json_object_int_add(json_row, "detectionCount",
|
|
|
|
n->dad_count);
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
|
|
|
|
json_object_boolean_true_add(json_row,
|
|
|
|
"isDuplicate");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json_row,
|
|
|
|
"isDuplicate");
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->count++;
|
2018-08-20 22:00:50 +02:00
|
|
|
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
|
|
|
|
!IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json_vni == NULL) {
|
|
|
|
if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
|
|
|
|
(wctx->count == 0))
|
2019-06-21 07:37:02 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n",
|
2018-08-20 22:00:50 +02:00
|
|
|
-wctx->addr_width, "Neighbor", "Type",
|
2019-06-21 07:37:02 +02:00
|
|
|
"State", "MAC", "Remote VTEP",
|
|
|
|
"Seq #'s");
|
2019-06-03 21:11:17 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %-21s %u/%u\n",
|
2018-08-20 22:00:50 +02:00
|
|
|
-wctx->addr_width, buf2, "remote", state_str,
|
2019-06-03 21:11:17 +02:00
|
|
|
buf1, inet_ntoa(n->r_vtep_ip), n->loc_seq, n->rem_seq);
|
2017-06-22 01:37:51 +02:00
|
|
|
} else {
|
2018-08-20 22:00:50 +02:00
|
|
|
json_object_string_add(json_row, "type", "remote");
|
|
|
|
json_object_string_add(json_row, "state", state_str);
|
|
|
|
json_object_string_add(json_row, "mac", buf1);
|
|
|
|
json_object_string_add(json_row, "remoteVtep",
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
|
|
|
|
json_object_boolean_true_add(json_row,
|
|
|
|
"defaultGateway");
|
|
|
|
json_object_int_add(json_row, "localSequence",
|
|
|
|
n->loc_seq);
|
|
|
|
json_object_int_add(json_row, "remoteSequence",
|
|
|
|
n->rem_seq);
|
2018-11-04 18:36:47 +01:00
|
|
|
json_object_int_add(json_row, "detectionCount",
|
|
|
|
n->dad_count);
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
|
|
|
|
json_object_boolean_true_add(json_row,
|
|
|
|
"isDuplicate");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json_row,
|
|
|
|
"isDuplicate");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2018-08-20 22:00:50 +02:00
|
|
|
wctx->count++;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json_vni)
|
|
|
|
json_object_object_add(json_vni, buf2, json_row);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 10:56:52 +01:00
|
|
|
/*
|
|
|
|
* Print neighbor hash entry in detail - called for display of all neighbors.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt)
|
2018-11-22 10:56:52 +01:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
json_object *json_vni = NULL, *json_row = NULL;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
|
|
|
|
|
|
|
vty = wctx->vty;
|
|
|
|
json_vni = wctx->json;
|
2019-02-19 16:46:52 +01:00
|
|
|
n = (zebra_neigh_t *)bucket->data;
|
2018-11-22 10:56:52 +01:00
|
|
|
if (!n)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ipaddr2str(&n->ip, buf, sizeof(buf));
|
|
|
|
if (json_vni)
|
|
|
|
json_row = json_object_new_object();
|
|
|
|
|
|
|
|
zvni_print_neigh(n, vty, json_row);
|
|
|
|
|
|
|
|
if (json_vni)
|
|
|
|
json_object_object_add(json_vni, buf, json_row);
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Print neighbors for all VNI.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
|
2017-06-22 01:37:51 +02:00
|
|
|
void **args)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL, *json_vni = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_neigh;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
2018-11-04 19:17:29 +01:00
|
|
|
uint32_t print_dup;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (json_object *)args[1];
|
2018-11-04 19:17:29 +01:00
|
|
|
print_dup = (uint32_t)(uintptr_t)args[2];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2018-08-15 21:56:53 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
|
|
|
if (print_dup)
|
|
|
|
num_neigh = num_dup_detected_neighs(zvni);
|
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
if (json == NULL) {
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
|
|
|
|
zvni->vni, num_neigh);
|
2018-07-07 06:46:46 +02:00
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_object_int_add(json_vni, "numArpNd", num_neigh);
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
|
|
|
}
|
2018-11-04 19:17:29 +01:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!num_neigh) {
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Since we have IPv6 addresses to deal with which can vary widely in
|
|
|
|
* size, we try to be a bit more elegant in display by first computing
|
|
|
|
* the maximum width.
|
|
|
|
*/
|
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json_vni;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
if (json == NULL) {
|
2019-06-03 21:11:17 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n",
|
2018-08-20 22:00:50 +02:00
|
|
|
-wctx.addr_width, "IP", "Type",
|
2019-06-03 21:11:17 +02:00
|
|
|
"State", "MAC", "Remote VTEP", "Seq #'s");
|
2018-07-07 06:46:46 +02:00
|
|
|
}
|
2018-11-04 19:17:29 +01:00
|
|
|
if (print_dup)
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash,
|
|
|
|
&wctx);
|
|
|
|
else
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt)
|
2018-11-04 19:17:29 +01:00
|
|
|
{
|
|
|
|
zebra_neigh_t *nbr;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
nbr = (zebra_neigh_t *)bucket->data;
|
2018-11-04 19:17:29 +01:00
|
|
|
if (!nbr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni_print_neigh_hash(bucket, ctxt);
|
2018-11-04 19:17:29 +01:00
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_dad_neigh_hash_detail(struct hash_bucket *bucket,
|
2018-11-22 10:56:52 +01:00
|
|
|
void *ctxt)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *nbr;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
nbr = (zebra_neigh_t *)bucket->data;
|
2018-11-22 10:56:52 +01:00
|
|
|
if (!nbr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni_print_neigh_hash_detail(bucket, ctxt);
|
2018-11-22 10:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print neighbors for all VNIs in detail.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_neigh_hash_all_vni_detail(struct hash_bucket *bucket,
|
2018-11-22 10:56:52 +01:00
|
|
|
void **args)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
json_object *json = NULL, *json_vni = NULL;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
uint32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
uint32_t print_dup;
|
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (json_object *)args[1];
|
|
|
|
print_dup = (uint32_t)(uintptr_t)args[2];
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2018-11-22 10:56:52 +01:00
|
|
|
if (!zvni) {
|
|
|
|
if (json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
|
|
|
|
if (print_dup && num_dup_detected_neighs(zvni) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty,
|
|
|
|
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
|
|
|
|
zvni->vni, num_neigh);
|
|
|
|
} else {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_object_int_add(json_vni, "numArpNd", num_neigh);
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
|
|
|
}
|
|
|
|
if (!num_neigh) {
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
|
|
|
wctx.json = json_vni;
|
|
|
|
|
|
|
|
if (print_dup)
|
|
|
|
hash_iterate(zvni->neigh_table,
|
|
|
|
zvni_print_dad_neigh_hash_detail, &wctx);
|
|
|
|
else
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash_detail,
|
|
|
|
&wctx);
|
|
|
|
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
|
|
|
|
2017-10-17 01:51:32 +02:00
|
|
|
/* print a specific next hop for an l3vni */
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json_hosts = NULL;
|
2018-05-17 14:18:23 +02:00
|
|
|
struct host_rb_entry *hle;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2017-10-17 13:32:31 +02:00
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, "Ip: %s\n",
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
|
|
|
vty_out(vty, " RMAC: %s\n",
|
2018-03-06 20:02:52 +01:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
2018-05-17 14:18:23 +02:00
|
|
|
vty_out(vty, " Refcount: %d\n",
|
|
|
|
rb_host_count(&n->host_rb));
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Prefixes:\n");
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
|
2017-10-17 13:32:31 +02:00
|
|
|
vty_out(vty, " %s\n",
|
2018-05-17 14:18:23 +02:00
|
|
|
prefix2str(&hle->p, buf2, sizeof(buf2)));
|
2017-10-17 13:32:31 +02:00
|
|
|
} else {
|
|
|
|
json_hosts = json_object_new_array();
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json, "ip", ipaddr2str(&(n->ip), buf2, sizeof(buf2)));
|
|
|
|
json_object_string_add(
|
|
|
|
json, "routerMac",
|
|
|
|
prefix_mac2str(&n->emac, buf2, sizeof(buf2)));
|
2018-05-17 14:18:23 +02:00
|
|
|
json_object_int_add(json, "refCount",
|
|
|
|
rb_host_count(&n->host_rb));
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object_array_add(json_hosts,
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_new_string(prefix2str(
|
2018-05-17 14:18:23 +02:00
|
|
|
&hle->p, buf2, sizeof(buf2))));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_object_add(json, "prefixList", json_hosts);
|
2017-10-17 13:32:31 +02:00
|
|
|
}
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print a specific RMAC entry */
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
|
2017-10-17 14:25:47 +02:00
|
|
|
json_object *json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[PREFIX_STRLEN];
|
2017-10-17 14:25:47 +02:00
|
|
|
json_object *json_hosts = NULL;
|
2018-05-17 01:24:22 +02:00
|
|
|
struct host_rb_entry *hle;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2017-10-17 14:25:47 +02:00
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, "MAC: %s\n",
|
|
|
|
prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
|
|
|
|
vty_out(vty, " Remote VTEP: %s\n",
|
|
|
|
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
|
2018-05-17 14:10:41 +02:00
|
|
|
vty_out(vty, " Refcount: %d\n", rb_host_count(&zrmac->host_rb));
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Prefixes:\n");
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
|
2017-10-17 14:25:47 +02:00
|
|
|
vty_out(vty, " %s\n",
|
2018-05-17 01:24:22 +02:00
|
|
|
prefix2str(&hle->p, buf2, sizeof(buf2)));
|
2017-10-17 14:25:47 +02:00
|
|
|
} else {
|
|
|
|
json_hosts = json_object_new_array();
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json, "routerMac",
|
|
|
|
prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "vtepIp",
|
2017-10-17 14:25:47 +02:00
|
|
|
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
|
2018-05-17 14:10:41 +02:00
|
|
|
json_object_int_add(json, "refCount",
|
|
|
|
rb_host_count(&zrmac->host_rb));
|
2018-08-20 22:00:50 +02:00
|
|
|
json_object_int_add(json, "localSequence", zrmac->loc_seq);
|
|
|
|
json_object_int_add(json, "remoteSequence", zrmac->rem_seq);
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
|
2018-05-17 01:24:22 +02:00
|
|
|
json_object_array_add(
|
|
|
|
json_hosts,
|
|
|
|
json_object_new_string(prefix2str(
|
|
|
|
&hle->p, buf2, sizeof(buf2))));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_object_add(json, "prefixList", json_hosts);
|
2017-10-17 14:25:47 +02:00
|
|
|
}
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Print a specific MAC entry.
|
|
|
|
*/
|
2018-10-26 22:57:23 +02:00
|
|
|
static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
2019-02-25 18:37:34 +01:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2017-07-06 00:03:14 +02:00
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2018-11-04 18:36:47 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
struct timeval detect_start_time = {0, 0};
|
2019-07-10 16:16:59 +02:00
|
|
|
char timebuf[MONOTIME_STRLEN];
|
2018-11-04 18:36:47 +01:00
|
|
|
|
2019-03-22 11:08:01 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
vty = (struct vty *)ctxt;
|
2018-10-26 22:57:23 +02:00
|
|
|
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
if (json) {
|
|
|
|
json_object *json_mac = json_object_new_object();
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct interface *ifp;
|
|
|
|
ifindex_t ifindex;
|
|
|
|
|
|
|
|
ifindex = mac->fwd_info.local.ifindex;
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
ifp = if_lookup_by_index_per_ns(zns, ifindex);
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
json_object_string_add(json_mac, "type", "local");
|
|
|
|
json_object_string_add(json_mac, "intf", ifp->name);
|
|
|
|
json_object_int_add(json_mac, "ifindex", ifindex);
|
|
|
|
if (mac->fwd_info.local.vid)
|
|
|
|
json_object_int_add(json_mac, "vlan",
|
|
|
|
mac->fwd_info.local.vid);
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
json_object_string_add(json_mac, "type", "remote");
|
|
|
|
json_object_string_add(
|
|
|
|
json_mac, "remoteVtep",
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
|
2018-10-29 18:16:14 +01:00
|
|
|
json_object_string_add(json_mac, "type", "auto");
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
|
|
|
|
json_object_boolean_true_add(json_mac, "stickyMac");
|
2017-11-13 12:19:52 +01:00
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
|
|
|
|
json_object_boolean_true_add(json_mac,
|
|
|
|
"defaultGateway");
|
2017-11-13 12:19:52 +01:00
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
|
|
|
|
json_object_boolean_true_add(json_mac,
|
|
|
|
"remoteGatewayMac");
|
2018-07-10 02:44:44 +02:00
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
json_object_int_add(json_mac, "localSequence", mac->loc_seq);
|
|
|
|
json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
2018-11-04 18:36:47 +01:00
|
|
|
json_object_int_add(json_mac, "detectionCount", mac->dad_count);
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
|
|
|
json_object_boolean_true_add(json_mac, "isDuplicate");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json_mac, "isDuplicate");
|
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
/* print all the associated neigh */
|
|
|
|
if (!listcount(mac->neigh_list))
|
|
|
|
json_object_string_add(json_mac, "neighbors", "none");
|
|
|
|
else {
|
|
|
|
json_object *json_active_nbrs = json_object_new_array();
|
|
|
|
json_object *json_inactive_nbrs =
|
|
|
|
json_object_new_array();
|
|
|
|
json_object *json_nbrs = json_object_new_object();
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n))
|
|
|
|
json_object_array_add(
|
|
|
|
json_active_nbrs,
|
|
|
|
json_object_new_string(
|
|
|
|
ipaddr2str(
|
|
|
|
&n->ip, buf2,
|
|
|
|
sizeof(buf2))));
|
|
|
|
else
|
|
|
|
json_object_array_add(
|
|
|
|
json_inactive_nbrs,
|
|
|
|
json_object_new_string(
|
|
|
|
ipaddr2str(
|
|
|
|
&n->ip, buf2,
|
|
|
|
sizeof(buf2))));
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object_object_add(json_nbrs, "active",
|
|
|
|
json_active_nbrs);
|
|
|
|
json_object_object_add(json_nbrs, "inactive",
|
|
|
|
json_inactive_nbrs);
|
|
|
|
json_object_object_add(json_mac, "neighbors",
|
|
|
|
json_nbrs);
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
json_object_object_add(json, buf1, json_mac);
|
|
|
|
} else {
|
|
|
|
vty_out(vty, "MAC: %s\n", buf1);
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct interface *ifp;
|
|
|
|
ifindex_t ifindex;
|
|
|
|
|
|
|
|
ifindex = mac->fwd_info.local.ifindex;
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
ifp = if_lookup_by_index_per_ns(zns, ifindex);
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex);
|
|
|
|
if (mac->fwd_info.local.vid)
|
|
|
|
vty_out(vty, " VLAN: %u",
|
|
|
|
mac->fwd_info.local.vid);
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
vty_out(vty, " Remote VTEP: %s",
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
|
|
|
|
vty_out(vty, " Auto Mac ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
|
|
|
|
vty_out(vty, " Sticky Mac ");
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
|
|
|
|
vty_out(vty, " Default-gateway Mac ");
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
|
|
|
|
vty_out(vty, " Remote-gateway Mac ");
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, " Local Seq: %u Remote Seq: %u", mac->loc_seq,
|
|
|
|
mac->rem_seq);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
|
2018-11-04 18:36:47 +01:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
|
|
|
vty_out(vty, " Duplicate, detected at %s",
|
2019-07-10 16:16:59 +02:00
|
|
|
time_to_string(mac->dad_dup_detect_time,
|
|
|
|
timebuf));
|
2018-11-04 18:36:47 +01:00
|
|
|
} else if (mac->dad_count) {
|
|
|
|
monotime_since(&mac->detect_start_time,
|
|
|
|
&detect_start_time);
|
|
|
|
if (detect_start_time.tv_sec <= zvrf->dad_time) {
|
2019-07-10 16:16:59 +02:00
|
|
|
time_to_string(mac->detect_start_time.tv_sec,
|
|
|
|
timebuf);
|
2018-11-04 18:36:47 +01:00
|
|
|
vty_out(vty,
|
|
|
|
" Duplicate detection started at %s, detection count %u\n",
|
2019-07-10 16:16:59 +02:00
|
|
|
timebuf, mac->dad_count);
|
2018-11-04 18:36:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
/* print all the associated neigh */
|
|
|
|
vty_out(vty, " Neighbors:\n");
|
|
|
|
if (!listcount(mac->neigh_list))
|
|
|
|
vty_out(vty, " No Neighbors\n");
|
|
|
|
else {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
|
|
|
|
vty_out(vty, " %s %s\n",
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)),
|
|
|
|
(IS_ZEBRA_NEIGH_ACTIVE(n)
|
|
|
|
? "Active"
|
|
|
|
: "Inactive"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print MAC hash entry - called for display of all MACs.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json_mac_hdr = NULL, *json_mac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *mac;
|
2019-02-25 18:37:34 +01:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
|
|
|
|
|
|
|
vty = wctx->vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_mac_hdr = wctx->json;
|
2019-02-19 16:46:52 +01:00
|
|
|
mac = (zebra_mac_t *)bucket->data;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json_mac_hdr)
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
|
2018-08-20 22:00:50 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
ifindex_t ifindex;
|
|
|
|
struct interface *ifp;
|
|
|
|
vlanid_t vid;
|
|
|
|
|
2018-08-20 22:00:50 +02:00
|
|
|
if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
|
|
|
|
return;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
ifindex = mac->fwd_info.local.ifindex;
|
|
|
|
ifp = if_lookup_by_index_per_ns(zns, ifindex);
|
|
|
|
if (!ifp) // unexpected
|
|
|
|
return;
|
|
|
|
vid = mac->fwd_info.local.vid;
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s", buf1, "local",
|
|
|
|
ifp->name);
|
|
|
|
else {
|
|
|
|
json_object_string_add(json_mac, "type", "local");
|
|
|
|
json_object_string_add(json_mac, "intf", ifp->name);
|
|
|
|
}
|
|
|
|
if (vid) {
|
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, " %-5u", vid);
|
|
|
|
else
|
|
|
|
json_object_int_add(json_mac, "vlan", vid);
|
2019-06-17 07:25:53 +02:00
|
|
|
} else /* No vid? fill out the space */
|
2019-06-21 07:37:02 +02:00
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, " %-5s", "");
|
2018-08-20 22:00:50 +02:00
|
|
|
if (json_mac_hdr == NULL) {
|
2019-06-21 07:37:02 +02:00
|
|
|
vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty, "\n");
|
2018-08-20 22:00:50 +02:00
|
|
|
} else {
|
|
|
|
json_object_int_add(json_mac, "localSequence",
|
|
|
|
mac->loc_seq);
|
|
|
|
json_object_int_add(json_mac, "remoteSequence",
|
|
|
|
mac->rem_seq);
|
2018-11-04 18:36:47 +01:00
|
|
|
json_object_int_add(json_mac, "detectionCount",
|
|
|
|
mac->dad_count);
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
|
|
|
json_object_boolean_true_add(json_mac,
|
|
|
|
"isDuplicate");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json_mac,
|
|
|
|
"isDuplicate");
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_object_add(json_mac_hdr, buf1, json_mac);
|
2018-08-20 22:00:50 +02:00
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->count++;
|
2018-08-20 22:00:50 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
2018-08-20 22:00:50 +02:00
|
|
|
|
|
|
|
if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
|
|
|
|
!IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
|
|
|
|
&wctx->r_vtep_ip))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json_mac_hdr == NULL) {
|
|
|
|
if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
|
|
|
|
(wctx->count == 0)) {
|
|
|
|
vty_out(vty, "\nVNI %u\n\n", wctx->zvni->vni);
|
2019-06-17 07:25:53 +02:00
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s %s\n",
|
|
|
|
"MAC", "Type", "Intf/Remote VTEP",
|
|
|
|
"VLAN", "Seq #'s");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2019-06-17 07:25:53 +02:00
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s %u/%u\n", buf1,
|
|
|
|
"remote", inet_ntoa(mac->fwd_info.r_vtep_ip),
|
|
|
|
"", mac->loc_seq, mac->rem_seq);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2018-08-20 22:00:50 +02:00
|
|
|
json_object_string_add(json_mac, "type", "remote");
|
|
|
|
json_object_string_add(json_mac, "remoteVtep",
|
2017-06-22 01:37:51 +02:00
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
2018-08-20 22:00:50 +02:00
|
|
|
json_object_object_add(json_mac_hdr, buf1, json_mac);
|
|
|
|
json_object_int_add(json_mac, "localSequence",
|
|
|
|
mac->loc_seq);
|
|
|
|
json_object_int_add(json_mac, "remoteSequence",
|
|
|
|
mac->rem_seq);
|
2018-11-04 18:36:47 +01:00
|
|
|
json_object_int_add(json_mac, "detectionCount",
|
|
|
|
mac->dad_count);
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
|
|
|
json_object_boolean_true_add(json_mac,
|
|
|
|
"isDuplicate");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json_mac,
|
|
|
|
"isDuplicate");
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2018-08-20 22:00:50 +02:00
|
|
|
|
|
|
|
wctx->count++;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
/* Print Duplicate MAC */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
|
2018-11-04 19:17:29 +01:00
|
|
|
{
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
mac = (zebra_mac_t *)bucket->data;
|
2018-11-04 19:17:29 +01:00
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni_print_mac_hash(bucket, ctxt);
|
2018-11-04 19:17:29 +01:00
|
|
|
}
|
|
|
|
|
2018-11-22 09:18:10 +01:00
|
|
|
/*
|
|
|
|
* Print MAC hash entry in detail - called for display of all MACs.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
|
2018-11-22 09:18:10 +01:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
json_object *json_mac_hdr = NULL;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
2019-02-25 18:37:34 +01:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2018-11-22 09:18:10 +01:00
|
|
|
|
|
|
|
vty = wctx->vty;
|
|
|
|
json_mac_hdr = wctx->json;
|
2019-02-19 16:46:52 +01:00
|
|
|
mac = (zebra_mac_t *)bucket->data;
|
2018-11-22 09:18:10 +01:00
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wctx->count++;
|
|
|
|
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
|
|
|
|
|
|
|
|
zvni_print_mac(mac, vty, json_mac_hdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print Duplicate MAC in detail */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_dad_mac_hash_detail(struct hash_bucket *bucket,
|
2018-11-22 09:18:10 +01:00
|
|
|
void *ctxt)
|
|
|
|
{
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
mac = (zebra_mac_t *)bucket->data;
|
2018-11-22 09:18:10 +01:00
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni_print_mac_hash_detail(bucket, ctxt);
|
2018-11-22 09:18:10 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Print MACs for all VNI.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL, *json_vni = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
2017-06-22 01:37:51 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vty = (struct vty *)wctx->vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json = (struct json_object *)wctx->json;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->zvni = zvni;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/*We are iterating over a new VNI, set the count to 0*/
|
|
|
|
wctx->count = 0;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
if (wctx->print_dup)
|
|
|
|
num_macs = num_dup_detected_macs(zvni);
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json) {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
|
|
|
|
zvni->vni, num_macs);
|
2019-06-17 07:25:53 +02:00
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC",
|
|
|
|
"Type", "Intf/Remote VTEP", "VLAN", "Seq #'s");
|
2017-06-22 01:37:51 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json_vni, "numMacs", num_macs);
|
|
|
|
}
|
2018-11-04 19:17:29 +01:00
|
|
|
|
|
|
|
if (!num_macs) {
|
|
|
|
if (json) {
|
|
|
|
json_object_int_add(json_vni, "numMacs", num_macs);
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
/* assign per-vni to wctx->json object to fill macs
|
|
|
|
* under the vni. Re-assign primary json object to fill
|
|
|
|
* next vni information.
|
|
|
|
*/
|
|
|
|
wctx->json = json_mac;
|
2018-11-04 19:17:29 +01:00
|
|
|
if (wctx->print_dup)
|
|
|
|
hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, wctx);
|
|
|
|
else
|
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx->json = json;
|
|
|
|
if (json) {
|
|
|
|
if (wctx->count)
|
|
|
|
json_object_object_add(json_vni, "macs", json_mac);
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 09:18:10 +01:00
|
|
|
/*
|
|
|
|
* Print MACs in detail for all VNI.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_mac_hash_all_vni_detail(struct hash_bucket *bucket,
|
2018-11-22 09:18:10 +01:00
|
|
|
void *ctxt)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
json_object *json = NULL, *json_vni = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
uint32_t num_macs;
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
|
|
|
vty = (struct vty *)wctx->vty;
|
|
|
|
json = (struct json_object *)wctx->json;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2018-11-22 09:18:10 +01:00
|
|
|
if (!zvni) {
|
|
|
|
if (json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
wctx->zvni = zvni;
|
|
|
|
|
|
|
|
/*We are iterating over a new VNI, set the count to 0*/
|
|
|
|
wctx->count = 0;
|
|
|
|
|
|
|
|
num_macs = num_valid_macs(zvni);
|
|
|
|
if (!num_macs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (wctx->print_dup && (num_dup_detected_macs(zvni) == 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json) {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
|
|
|
|
zvni->vni, num_macs);
|
|
|
|
} else
|
|
|
|
json_object_int_add(json_vni, "numMacs", num_macs);
|
|
|
|
}
|
|
|
|
/* assign per-vni to wctx->json object to fill macs
|
|
|
|
* under the vni. Re-assign primary json object to fill
|
|
|
|
* next vni information.
|
|
|
|
*/
|
|
|
|
wctx->json = json_mac;
|
|
|
|
if (wctx->print_dup)
|
|
|
|
hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash_detail,
|
|
|
|
wctx);
|
|
|
|
else
|
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash_detail, wctx);
|
|
|
|
wctx->json = json;
|
|
|
|
if (json) {
|
|
|
|
if (wctx->count)
|
|
|
|
json_object_object_add(json_vni, "macs", json_mac);
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct nh_walk_ctx *wctx = NULL;
|
|
|
|
struct vty *vty = NULL;
|
2017-10-17 12:48:06 +02:00
|
|
|
struct json_object *json_vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct json_object *json_nh = NULL;
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2017-10-13 10:13:48 +02:00
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
wctx = (struct nh_walk_ctx *)ctx;
|
|
|
|
vty = wctx->vty;
|
2017-10-17 12:48:06 +02:00
|
|
|
json_vni = wctx->json;
|
|
|
|
if (json_vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
json_nh = json_object_new_object();
|
2019-02-19 16:46:52 +01:00
|
|
|
n = (zebra_neigh_t *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-10-17 12:48:06 +02:00
|
|
|
if (!json_vni) {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-15s %-17s\n",
|
2017-10-13 10:13:48 +02:00
|
|
|
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
|
2017-11-15 10:01:00 +01:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json_nh, "nexthopIp",
|
2017-10-17 12:48:06 +02:00
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json_nh, "routerMac",
|
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
2017-10-17 12:48:06 +02:00
|
|
|
json_object_object_add(json_vni,
|
|
|
|
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
|
|
|
|
json_nh);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
|
2017-10-17 12:48:06 +02:00
|
|
|
void **args)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_vni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
uint32_t num_nh = 0;
|
2017-10-17 12:48:06 +02:00
|
|
|
struct nh_walk_ctx wctx;
|
2017-10-13 10:13:48 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
2017-10-17 12:48:06 +02:00
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (struct json_object *)args[1];
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zl3vni = (zebra_l3vni_t *)bucket->data;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
num_nh = hashcount(zl3vni->nh_table);
|
|
|
|
if (!num_nh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json) {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json == NULL) {
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
|
2017-10-13 10:13:48 +02:00
|
|
|
} else
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json_vni, "numNextHops", num_nh);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2017-10-17 12:48:06 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct nh_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.json = json_vni;
|
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
|
|
|
|
if (json)
|
2017-10-13 10:13:48 +02:00
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
|
2017-10-17 13:59:42 +02:00
|
|
|
void **args)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_vni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_rmacs;
|
2017-10-17 13:59:42 +02:00
|
|
|
struct rmac_walk_ctx wctx;
|
2017-10-08 03:49:27 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
2017-10-17 13:59:42 +02:00
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (struct json_object *)args[1];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zl3vni = (zebra_l3vni_t *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
num_rmacs = hashcount(zl3vni->rmac_table);
|
|
|
|
if (!num_rmacs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json) {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json == NULL) {
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "\nVNI %u #RMACs %u\n\n", zl3vni->vni, num_rmacs);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json_vni, "numRmacs", num_rmacs);
|
|
|
|
|
|
|
|
/* assign per-vni to wctx->json object to fill macs
|
|
|
|
* under the vni. Re-assign primary json object to fill
|
|
|
|
* next vni information.
|
|
|
|
*/
|
2017-10-17 13:59:42 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.json = json_vni;
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
|
|
|
|
if (json)
|
2017-10-08 03:49:27 +02:00
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_mac_t *zrmac = NULL;
|
|
|
|
struct rmac_walk_ctx *wctx = NULL;
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
struct json_object *json = NULL;
|
|
|
|
struct json_object *json_rmac = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
|
|
|
|
wctx = (struct rmac_walk_ctx *)ctx;
|
|
|
|
vty = wctx->vty;
|
|
|
|
json = wctx->json;
|
|
|
|
if (json)
|
|
|
|
json_rmac = json_object_new_object();
|
2019-02-19 16:46:52 +01:00
|
|
|
zrmac = (zebra_mac_t *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!json) {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-17s %-21s\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
|
2018-03-06 20:02:52 +01:00
|
|
|
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json_rmac, "routerMac",
|
|
|
|
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json_rmac, "vtepIp",
|
2017-10-08 03:49:27 +02:00
|
|
|
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_object_add(
|
|
|
|
json, prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
|
|
|
|
json_rmac);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print a specific L3 VNI entry */
|
|
|
|
static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
|
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
json_object *json_vni_list = NULL;
|
|
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
|
|
|
|
vty = ctx[0];
|
|
|
|
json = ctx[1];
|
|
|
|
|
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, "VNI: %u\n", zl3vni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Type: %s\n", "L3");
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, " Tenant VRF: %s\n", zl3vni_vrf_name(zl3vni));
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Local Vtep Ip: %s\n",
|
2017-10-31 00:58:15 +01:00
|
|
|
inet_ntoa(zl3vni->local_vtep_ip));
|
2017-10-08 03:49:27 +02:00
|
|
|
vty_out(vty, " Vxlan-Intf: %s\n",
|
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, " SVI-If: %s\n", zl3vni_svi_if_name(zl3vni));
|
|
|
|
vty_out(vty, " State: %s\n", zl3vni_state2str(zl3vni));
|
2018-02-06 23:28:22 +01:00
|
|
|
vty_out(vty, " VNI Filter: %s\n",
|
2018-03-06 20:02:52 +01:00
|
|
|
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
|
|
|
|
? "prefix-routes-only"
|
|
|
|
: "none");
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Router MAC: %s\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " L2 VNIs: ");
|
2017-10-08 03:49:27 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni))
|
|
|
|
vty_out(vty, "%u ", zvni->vni);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
} else {
|
|
|
|
json_vni_list = json_object_new_array();
|
|
|
|
json_object_int_add(json, "vni", zl3vni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "type", "L3");
|
|
|
|
json_object_string_add(json, "localVtepIp",
|
2017-10-31 00:58:15 +01:00
|
|
|
inet_ntoa(zl3vni->local_vtep_ip));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "vxlanIntf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "sviIntf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_svi_if_name(zl3vni));
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(json, "state", zl3vni_state2str(zl3vni));
|
|
|
|
json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni));
|
|
|
|
json_object_string_add(
|
|
|
|
json, "routerMac",
|
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
|
|
|
json_object_string_add(
|
|
|
|
json, "vniFilter",
|
|
|
|
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
|
|
|
|
? "prefix-routes-only"
|
|
|
|
: "none");
|
2017-10-08 03:49:27 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
|
|
|
|
json_object_array_add(json_vni_list,
|
|
|
|
json_object_new_int(zvni->vni));
|
|
|
|
}
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_object_add(json, "l2Vnis", json_vni_list);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Print a specific VNI entry.
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print(zebra_vni_t *zvni, void **ctxt)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
zebra_vtep_t *zvtep;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
|
|
|
uint32_t num_neigh;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_vtep_list = NULL;
|
|
|
|
json_object *json_ip_str = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
vty = ctxt[0];
|
|
|
|
json = ctxt[1];
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (json == NULL) {
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty, "VNI: %u\n", zvni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Type: %s\n", "L2");
|
|
|
|
vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_int_add(json, "vni", zvni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "type", "L2");
|
2017-10-08 03:49:27 +02:00
|
|
|
json_object_string_add(json, "vrf",
|
|
|
|
vrf_id_to_name(zvni->vrf_id));
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (!zvni->vxlan_if) { // unexpected
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " VxLAN interface: unknown\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-06-22 01:37:51 +02:00
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
2017-11-15 10:01:00 +01:00
|
|
|
if (json == NULL) {
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, " VxLAN interface: %s\n", zvni->vxlan_if->name);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex);
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, " Local VTEP IP: %s\n",
|
2017-06-22 01:37:51 +02:00
|
|
|
inet_ntoa(zvni->local_vtep_ip));
|
2019-03-19 17:10:47 +01:00
|
|
|
vty_out(vty, " Mcast group: %s\n",
|
|
|
|
inet_ntoa(zvni->mcast_grp));
|
2017-11-15 10:01:00 +01:00
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_string_add(json, "vxlanInterface",
|
|
|
|
zvni->vxlan_if->name);
|
|
|
|
json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
|
|
|
|
json_object_string_add(json, "vtepIp",
|
|
|
|
inet_ntoa(zvni->local_vtep_ip));
|
2019-03-19 17:10:47 +01:00
|
|
|
json_object_string_add(json, "mcastGroup",
|
|
|
|
inet_ntoa(zvni->mcast_grp));
|
2017-07-07 01:33:50 +02:00
|
|
|
json_object_string_add(json, "advertiseGatewayMacip",
|
|
|
|
zvni->advertise_gw_macip ? "Yes" : "No");
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
|
|
|
json_object_int_add(json, "numArpNd", num_neigh);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vteps) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " No remote VTEPs known for this VNI\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " Remote VTEPs for this VNI:\n");
|
|
|
|
else
|
|
|
|
json_vtep_list = json_object_new_array();
|
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
2019-03-19 18:37:22 +01:00
|
|
|
const char *flood_str = lookup_msg(zvtep_flood_str,
|
|
|
|
zvtep->flood_control,
|
|
|
|
VXLAN_FLOOD_STR_DEFAULT);
|
|
|
|
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty, " %s flood: %s\n",
|
|
|
|
inet_ntoa(zvtep->vtep_ip),
|
|
|
|
flood_str);
|
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
json_ip_str = json_object_new_string(
|
2019-03-19 18:37:22 +01:00
|
|
|
inet_ntoa(zvtep->vtep_ip));
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_array_add(json_vtep_list,
|
2019-03-19 18:37:22 +01:00
|
|
|
json_ip_str);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, "numRemoteVteps",
|
|
|
|
json_vtep_list);
|
|
|
|
}
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty,
|
|
|
|
" Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
|
|
|
vty_out(vty,
|
|
|
|
" Number of ARPs (IPv4 and IPv6, local and remote) "
|
|
|
|
"known for this VNI: %u\n",
|
|
|
|
num_neigh);
|
2017-07-07 01:33:50 +02:00
|
|
|
vty_out(vty, " Advertise-gw-macip: %s\n",
|
|
|
|
zvni->advertise_gw_macip ? "Yes" : "No");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* print a L3 VNI hash entry */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[])
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
2017-10-17 11:59:35 +02:00
|
|
|
json_object *json_vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
2017-10-17 11:59:35 +02:00
|
|
|
vty = (struct vty *)ctx[0];
|
|
|
|
json = (json_object *)ctx[1];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zl3vni = (zebra_l3vni_t *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!json) {
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n",
|
|
|
|
zl3vni->vni, "L3", zl3vni_vxlan_if_name(zl3vni),
|
2017-11-15 10:01:00 +01:00
|
|
|
hashcount(zl3vni->rmac_table),
|
2018-03-06 20:02:52 +01:00
|
|
|
hashcount(zl3vni->nh_table), "n/a",
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni_vrf_name(zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-10-17 11:59:35 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_object_int_add(json_vni, "vni", zl3vni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json_vni, "vxlanIf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json_vni, "numMacs",
|
|
|
|
hashcount(zl3vni->rmac_table));
|
|
|
|
json_object_int_add(json_vni, "numArpNd",
|
|
|
|
hashcount(zl3vni->nh_table));
|
|
|
|
json_object_string_add(json_vni, "numRemoteVteps", "n/a");
|
|
|
|
json_object_string_add(json_vni, "type", "L3");
|
|
|
|
json_object_string_add(json_vni, "tenantVrf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_vrf_name(zl3vni));
|
2017-10-17 11:59:35 +02:00
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:33:43 +01:00
|
|
|
/* Private Structure to pass callback data for hash iterator */
|
|
|
|
struct zvni_evpn_show {
|
|
|
|
struct vty *vty;
|
|
|
|
json_object *json;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* print a L3 VNI hash entry in detail*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
|
2018-11-15 18:33:43 +01:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
json_object *json = NULL;
|
|
|
|
bool use_json = false;
|
|
|
|
struct zvni_evpn_show *zes = data;
|
|
|
|
|
|
|
|
vty = zes->vty;
|
|
|
|
json = zes->json;
|
|
|
|
|
|
|
|
if (json)
|
|
|
|
use_json = true;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zl3vni = (zebra_l3vni_t *)bucket->data;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni, use_json);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Print a VNI hash entry - called for display of all VNIs.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[])
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_vteps = 0;
|
|
|
|
uint32_t num_macs = 0;
|
|
|
|
uint32_t num_neigh = 0;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_vni = NULL;
|
|
|
|
json_object *json_ip_str = NULL;
|
|
|
|
json_object *json_vtep_list = NULL;
|
|
|
|
|
|
|
|
vty = ctxt[0];
|
|
|
|
json = ctxt[1];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep = zvni->vteps;
|
|
|
|
while (zvtep) {
|
|
|
|
num_vteps++;
|
|
|
|
zvtep = zvtep->next;
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
|
2017-11-15 10:01:00 +01:00
|
|
|
zvni->vni, "L2",
|
2017-06-22 01:37:51 +02:00
|
|
|
zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
|
2018-03-06 20:02:52 +01:00
|
|
|
num_macs, num_neigh, num_vteps,
|
2017-10-08 03:49:27 +02:00
|
|
|
vrf_id_to_name(zvni->vrf_id));
|
2017-06-22 01:37:51 +02:00
|
|
|
else {
|
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
|
|
|
json_vni = json_object_new_object();
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json_vni, "vni", zvni->vni);
|
|
|
|
json_object_string_add(json_vni, "type", "L2");
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_string_add(json_vni, "vxlanIf",
|
|
|
|
zvni->vxlan_if ? zvni->vxlan_if->name
|
|
|
|
: "unknown");
|
|
|
|
json_object_int_add(json_vni, "numMacs", num_macs);
|
|
|
|
json_object_int_add(json_vni, "numArpNd", num_neigh);
|
|
|
|
json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json_vni, "tenantVrf",
|
|
|
|
vrf_id_to_name(zvni->vrf_id));
|
2017-06-22 01:37:51 +02:00
|
|
|
if (num_vteps) {
|
|
|
|
json_vtep_list = json_object_new_array();
|
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
|
|
|
json_ip_str = json_object_new_string(
|
|
|
|
inet_ntoa(zvtep->vtep_ip));
|
|
|
|
json_object_array_add(json_vtep_list,
|
|
|
|
json_ip_str);
|
|
|
|
}
|
|
|
|
json_object_object_add(json_vni, "remoteVteps",
|
|
|
|
json_vtep_list);
|
|
|
|
}
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-15 18:33:43 +01:00
|
|
|
/*
|
|
|
|
* Print a VNI hash entry in detail - called for display of all VNIs.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_print_hash_detail(struct hash_bucket *bucket, void *data)
|
2018-11-15 18:33:43 +01:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
json_object *json = NULL;
|
|
|
|
bool use_json = false;
|
|
|
|
struct zvni_evpn_show *zes = data;
|
|
|
|
|
|
|
|
vty = zes->vty;
|
|
|
|
json = zes->json;
|
|
|
|
|
|
|
|
if (json)
|
|
|
|
use_json = true;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
zebra_vxlan_print_vni(vty, zes->zvrf, zvni->vni, use_json);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Inform BGP about local MACIP.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
|
2018-03-27 21:13:34 +02:00
|
|
|
struct ipaddr *ip, uint8_t flags,
|
2019-01-15 00:19:48 +01:00
|
|
|
uint32_t seq, int state, uint16_t cmd)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
int ipa_len;
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
struct stream *s = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-19 21:45:38 +01:00
|
|
|
zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_putl(s, vni);
|
2017-08-03 14:43:56 +02:00
|
|
|
stream_put(s, macaddr->octet, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ip) {
|
|
|
|
ipa_len = 0;
|
|
|
|
if (IS_IPADDR_V4(ip))
|
|
|
|
ipa_len = IPV4_MAX_BYTELEN;
|
|
|
|
else if (IS_IPADDR_V6(ip))
|
|
|
|
ipa_len = IPV6_MAX_BYTELEN;
|
|
|
|
|
|
|
|
stream_putl(s, ipa_len); /* IP address length */
|
|
|
|
if (ipa_len)
|
|
|
|
stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
|
|
|
|
} else
|
|
|
|
stream_putl(s, 0); /* Just MAC. */
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (cmd == ZEBRA_MACIP_ADD) {
|
|
|
|
stream_putc(s, flags); /* sticky mac/gateway mac */
|
|
|
|
stream_putl(s, seq); /* sequence number */
|
2019-01-15 00:19:48 +01:00
|
|
|
} else {
|
|
|
|
stream_putl(s, state); /* state - active/inactive */
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-06-28 10:51:10 +02:00
|
|
|
zlog_debug(
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
"Send MACIP %s flags 0x%x MAC %s IP %s seq %u L2-VNI %u to %s",
|
2018-03-06 20:02:52 +01:00
|
|
|
(cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
|
2017-06-28 10:51:10 +02:00
|
|
|
zebra_route_string(client->proto));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (cmd == ZEBRA_MACIP_ADD)
|
|
|
|
client->macipadd_cnt++;
|
|
|
|
else
|
|
|
|
client->macipdel_cnt++;
|
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make hash key for neighbors.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int neigh_hash_keymake(const void *p)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const zebra_neigh_t *n = p;
|
|
|
|
const struct ipaddr *ip = &n->ip;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_IPADDR_V4(ip))
|
|
|
|
return jhash_1word(ip->ipaddr_v4.s_addr, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return jhash2(ip->ipaddr_v6.s6_addr32,
|
2019-03-23 14:53:58 +01:00
|
|
|
array_size(ip->ipaddr_v6.s6_addr32), 0);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Compare two neighbor hash structures.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool neigh_cmp(const void *p1, const void *p2)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_neigh_t *n1 = p1;
|
|
|
|
const zebra_neigh_t *n2 = p2;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (n1 == NULL && n2 == NULL)
|
2018-10-17 21:27:12 +02:00
|
|
|
return true;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (n1 == NULL || n2 == NULL)
|
2018-10-17 21:27:12 +02:00
|
|
|
return false;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2018-10-17 21:31:09 +02:00
|
|
|
static int neigh_list_cmp(void *p1, void *p2)
|
|
|
|
{
|
|
|
|
const zebra_neigh_t *n1 = p1;
|
|
|
|
const zebra_neigh_t *n2 = p2;
|
|
|
|
|
|
|
|
return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr));
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Callback to allocate neighbor hash entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_neigh_alloc(void *p)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_neigh_t *tmp_n = p;
|
|
|
|
zebra_neigh_t *n;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
|
|
|
|
*n = *tmp_n;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return ((void *)n);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Add neighbor entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-06 00:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
|
|
|
|
struct ethaddr *mac)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t tmp_n;
|
|
|
|
zebra_neigh_t *n = NULL;
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_n, 0, sizeof(zebra_neigh_t));
|
|
|
|
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
|
|
|
|
n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc);
|
|
|
|
assert(n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
memcpy(&n->emac, mac, ETH_ALEN);
|
|
|
|
n->state = ZEBRA_NEIGH_INACTIVE;
|
2019-03-15 17:13:42 +01:00
|
|
|
n->zvni = zvni;
|
2019-03-16 03:09:25 +01:00
|
|
|
n->dad_ip_auto_recovery_timer = NULL;
|
2017-07-06 00:03:14 +02:00
|
|
|
|
|
|
|
/* Associate the neigh to mac */
|
|
|
|
zmac = zvni_mac_lookup(zvni, mac);
|
|
|
|
if (zmac)
|
|
|
|
listnode_add_sort(zmac->neigh_list, n);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return n;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Delete neighbor entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *tmp_n;
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac = NULL;
|
|
|
|
|
|
|
|
zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (zmac)
|
|
|
|
listnode_delete(zmac->neigh_list, n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2019-03-16 03:09:25 +01:00
|
|
|
/* Cancel auto recovery */
|
|
|
|
THREAD_OFF(n->dad_ip_auto_recovery_timer);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
|
|
|
tmp_n = hash_release(zvni->neigh_table, n);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_NEIGH, tmp_n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Free neighbor hash entry (callback)
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_neigh_del_hash_entry(struct hash_bucket *bucket, void *arg)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx *wctx = arg;
|
2019-02-19 16:46:52 +01:00
|
|
|
zebra_neigh_t *n = bucket->data;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL))
|
|
|
|
|| ((wctx->flags & DEL_REMOTE_NEIGH)
|
|
|
|
&& (n->flags & ZEBRA_NEIGH_REMOTE))
|
|
|
|
|| ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP)
|
|
|
|
&& (n->flags & ZEBRA_NEIGH_REMOTE)
|
|
|
|
&& IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
|
|
|
|
if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
|
2019-01-15 00:19:48 +01:00
|
|
|
&n->emac, 0, n->state);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (wctx->uninstall)
|
|
|
|
zvni_neigh_uninstall(wctx->zvni, n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
zvni_neigh_del(wctx->zvni, n);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Delete all neighbor entries from specific VTEP for a particular VNI.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->neigh_table)
|
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.flags = DEL_REMOTE_NEIGH_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = *r_vtep_ip;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_neigh_del_hash_entry, &wctx);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Delete all neighbor entries for this VNI.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->neigh_table)
|
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.upd_client = upd_client;
|
|
|
|
wctx.flags = flags;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_neigh_del_hash_entry, &wctx);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Look up neighbor hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t tmp;
|
|
|
|
zebra_neigh_t *n;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
|
|
|
|
n = hash_lookup(zvni->neigh_table, &tmp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return n;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/*
|
|
|
|
* Process all neighbors associated with a MAC upon the MAC being learnt
|
|
|
|
* locally or undergoing any other change (such as sequence number).
|
|
|
|
*/
|
|
|
|
static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
|
|
|
|
zebra_mac_t *zmac,
|
|
|
|
bool seq_change)
|
2017-07-06 00:03:14 +02:00
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
2018-11-04 17:20:11 +01:00
|
|
|
struct zebra_vrf *zvrf = NULL;
|
2017-07-06 00:03:14 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
2018-11-04 17:20:11 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
|
|
|
|
prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
|
|
|
|
seq_change ? "CHANGE" : "ADD", zvni->vni);
|
|
|
|
|
|
|
|
/* Walk all neighbors and mark any inactive local neighbors as
|
|
|
|
* active and/or update sequence number upon a move, and inform BGP.
|
|
|
|
* The action for remote neighbors is TBD.
|
|
|
|
* NOTE: We can't simply uninstall remote neighbors as the kernel may
|
|
|
|
* accidentally end up deleting a just-learnt local neighbor.
|
|
|
|
*/
|
2017-07-06 00:03:14 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change) {
|
2017-07-06 00:03:14 +02:00
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->loc_seq = zmac->loc_seq;
|
2018-11-04 17:20:11 +01:00
|
|
|
if (!(zvrf->dup_addr_detect &&
|
|
|
|
zvrf->dad_freeze && !!CHECK_FLAG(n->flags,
|
|
|
|
ZEBRA_NEIGH_DUPLICATE)))
|
|
|
|
zvni_neigh_send_add_to_client(
|
|
|
|
zvni->vni, &n->ip, &n->emac,
|
|
|
|
n->flags, n->loc_seq);
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/*
|
|
|
|
* Process all neighbors associated with a local MAC upon the MAC being
|
|
|
|
* deleted.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Processing neighbors on local MAC %s DEL, VNI %u",
|
|
|
|
prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
/* Walk all local neighbors and mark as inactive and inform
|
|
|
|
* BGP, if needed.
|
|
|
|
* TBD: There is currently no handling for remote neighbors. We
|
|
|
|
* don't expect them to exist, if they do, do we install the MAC
|
|
|
|
* as a remote MAC and the neighbor as remote?
|
|
|
|
*/
|
2017-07-06 00:03:14 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->loc_seq = 0;
|
2018-03-06 20:02:52 +01:00
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
|
2019-01-15 00:19:48 +01:00
|
|
|
&n->emac, 0, ZEBRA_NEIGH_ACTIVE);
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/*
|
|
|
|
* Process all neighbors associated with a MAC upon the MAC being remotely
|
|
|
|
* learnt.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Processing neighbors on remote MAC %s ADD, VNI %u",
|
|
|
|
prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
/* Walk all local neighbors and mark as inactive and inform
|
|
|
|
* BGP, if needed.
|
|
|
|
*/
|
2017-07-06 00:03:14 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->loc_seq = 0;
|
2018-03-06 20:02:52 +01:00
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
|
2019-01-15 00:19:48 +01:00
|
|
|
&n->emac, 0, ZEBRA_NEIGH_ACTIVE);
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/*
|
|
|
|
* Process all neighbors associated with a remote MAC upon the MAC being
|
|
|
|
* deleted.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* NOTE: Currently a NO-OP. */
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
|
zebra: probe local inactive neigh
In extended-mobility case ({IP1, MAC} binding),
when a MAC moves from local to remote, binding
changes to {IP2, MAC}, local neigh (IP1) marked
as inactive in frr.
The evpn draft recommends to probe the entry once
local binding changes from local to remote.
Once the probe is set for the local neigh entry,
kernel will attempt refresh the entry via sending
unicast address resolution message, if host does not
reply, it will mark FAILED state.
For FAILED entry, kernel triggers delete neigh
request, which result in frr to remove inactive entry.
In absence of probing and aging out entry,
if MAC moves back to local with {IP3, MAC},
frr will mark both IP1 and IP3 as active and sends
type-2 update for both.
The IP1 may not be active host and still frr advertises
the route.
Ticket:CM-22864
Testing Done:
Validate the MAC mobilty in extended mobility scenario,
where local inactive entry gets removed once MAC moves
to remote state.
Once probe is set to the local entry, kernel triggers
reachability of the neigh/arp entry, since MAC moved remote,
ARP request goes to remote VTEP where host is not residing,
thus local neigh entry goes to failed state.
Frr receives neighbor delete faster and removes the entry.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-01-29 00:37:03 +01:00
|
|
|
static void zvni_probe_neigh_on_mac_add(zebra_vni_t *zvni, zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *nbr = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, nbr)) {
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) &&
|
|
|
|
IS_ZEBRA_NEIGH_INACTIVE(nbr))
|
|
|
|
zvni_neigh_probe(zvni, nbr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP about local neighbor addition.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
|
2017-11-13 12:19:52 +01:00
|
|
|
struct ethaddr *macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint8_t neigh_flags,
|
|
|
|
uint32_t seq)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t flags = 0;
|
2017-11-13 12:19:52 +01:00
|
|
|
|
|
|
|
if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
2018-07-07 06:46:46 +02:00
|
|
|
/* Set router flag (R-bit) based on local neigh entry add */
|
|
|
|
if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG))
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
|
2019-08-09 03:58:03 +02:00
|
|
|
if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP))
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP);
|
2017-11-13 12:19:52 +01:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
|
2019-01-15 00:19:48 +01:00
|
|
|
seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP about local neighbor deletion.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
|
2019-01-15 00:19:48 +01:00
|
|
|
struct ethaddr *macaddr, uint8_t flags,
|
|
|
|
int state)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
|
2019-01-15 00:19:48 +01:00
|
|
|
0, state, ZEBRA_MACIP_DEL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install remote neighbor into the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct interface *vlan_if;
|
2019-08-23 19:59:10 +02:00
|
|
|
int flags;
|
2018-07-07 06:46:46 +02:00
|
|
|
int ret = 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return -1;
|
2019-08-23 19:59:10 +02:00
|
|
|
|
|
|
|
flags = DPLANE_NTF_EXT_LEARNED;
|
2018-07-07 06:46:46 +02:00
|
|
|
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
|
2019-08-23 19:59:10 +02:00
|
|
|
flags |= DPLANE_NTF_ROUTER;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
2019-08-23 19:59:10 +02:00
|
|
|
|
|
|
|
dplane_neigh_add(vlan_if, &n->ip, &n->emac, flags);
|
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
return ret;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Uninstall remote neighbor from the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct interface *vlan_if;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
2019-09-05 17:05:03 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
|
|
|
|
zvni->vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return -1;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
|
|
|
n->loc_seq = 0;
|
2019-08-23 19:59:10 +02:00
|
|
|
|
|
|
|
dplane_neigh_delete(vlan_if, &n->ip);
|
|
|
|
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
zebra: probe local inactive neigh
In extended-mobility case ({IP1, MAC} binding),
when a MAC moves from local to remote, binding
changes to {IP2, MAC}, local neigh (IP1) marked
as inactive in frr.
The evpn draft recommends to probe the entry once
local binding changes from local to remote.
Once the probe is set for the local neigh entry,
kernel will attempt refresh the entry via sending
unicast address resolution message, if host does not
reply, it will mark FAILED state.
For FAILED entry, kernel triggers delete neigh
request, which result in frr to remove inactive entry.
In absence of probing and aging out entry,
if MAC moves back to local with {IP3, MAC},
frr will mark both IP1 and IP3 as active and sends
type-2 update for both.
The IP1 may not be active host and still frr advertises
the route.
Ticket:CM-22864
Testing Done:
Validate the MAC mobilty in extended mobility scenario,
where local inactive entry gets removed once MAC moves
to remote state.
Once probe is set to the local entry, kernel triggers
reachability of the neigh/arp entry, since MAC moved remote,
ARP request goes to remote VTEP where host is not residing,
thus local neigh entry goes to failed state.
Frr receives neighbor delete faster and removes the entry.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-01-29 00:37:03 +01:00
|
|
|
/*
|
|
|
|
* Probe neighbor from the kernel.
|
|
|
|
*/
|
|
|
|
static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n)
|
|
|
|
{
|
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct interface *vlan_if;
|
|
|
|
|
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
|
|
|
return -1;
|
|
|
|
|
2019-08-23 19:59:10 +02:00
|
|
|
dplane_neigh_update(vlan_if, &n->ip, &n->emac);
|
|
|
|
|
zebra: probe local inactive neigh
In extended-mobility case ({IP1, MAC} binding),
when a MAC moves from local to remote, binding
changes to {IP2, MAC}, local neigh (IP1) marked
as inactive in frr.
The evpn draft recommends to probe the entry once
local binding changes from local to remote.
Once the probe is set for the local neigh entry,
kernel will attempt refresh the entry via sending
unicast address resolution message, if host does not
reply, it will mark FAILED state.
For FAILED entry, kernel triggers delete neigh
request, which result in frr to remove inactive entry.
In absence of probing and aging out entry,
if MAC moves back to local with {IP3, MAC},
frr will mark both IP1 and IP3 as active and sends
type-2 update for both.
The IP1 may not be active host and still frr advertises
the route.
Ticket:CM-22864
Testing Done:
Validate the MAC mobilty in extended mobility scenario,
where local inactive entry gets removed once MAC moves
to remote state.
Once probe is set to the local entry, kernel triggers
reachability of the neigh/arp entry, since MAC moved remote,
ARP request goes to remote VTEP where host is not residing,
thus local neigh entry goes to failed state.
Frr receives neighbor delete faster and removes the entry.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-01-29 00:37:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Install neighbor hash entry - called upon access VLAN change.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_install_neigh_hash(struct hash_bucket *bucket, void *ctxt)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n;
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
n = (zebra_neigh_t *)bucket->data;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
|
|
|
|
zvni_neigh_install(wctx->zvni, n);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Get the VRR interface for SVI if any */
|
|
|
|
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
|
|
|
struct interface *tmp_if = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(ifp->vrf_id);
|
2017-06-28 10:51:10 +02:00
|
|
|
assert(zvrf);
|
|
|
|
|
2017-10-06 20:25:58 +02:00
|
|
|
FOR_ALL_INTERFACES (zvrf->vrf, tmp_if) {
|
2017-06-28 10:51:10 +02:00
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!IS_ZEBRA_IF_MACVLAN(tmp_if))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (zif->link == ifp)
|
|
|
|
return tmp_if;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct listnode *cnode = NULL, *cnnode = NULL;
|
|
|
|
struct connected *c = NULL;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
|
|
|
|
struct ipaddr ip;
|
|
|
|
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c->address->family == AF_INET) {
|
|
|
|
ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (c->address->family == AF_INET6) {
|
|
|
|
ip.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_gw_macip_del(ifp, zvni, &ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct listnode *cnode = NULL, *cnnode = NULL;
|
|
|
|
struct connected *c = NULL;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
|
|
|
|
struct ipaddr ip;
|
|
|
|
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c->address->family == AF_INET) {
|
|
|
|
ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (c->address->family == AF_INET6) {
|
|
|
|
ip.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
|
|
|
|
}
|
2017-11-20 06:47:04 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_advertise_subnet(zebra_vni_t *zvni, struct interface *ifp,
|
2017-11-20 06:47:04 +01:00
|
|
|
int advertise)
|
|
|
|
{
|
|
|
|
struct listnode *cnode = NULL, *cnnode = NULL;
|
|
|
|
struct connected *c = NULL;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
|
|
|
|
struct prefix p;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-11-20 06:47:04 +01:00
|
|
|
memcpy(&p, c->address, sizeof(struct prefix));
|
|
|
|
|
|
|
|
/* skip link local address */
|
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
apply_mask(&p);
|
|
|
|
if (advertise)
|
2019-06-24 01:46:39 +02:00
|
|
|
ip_prefix_send_to_client(ifp->vrf_id, &p,
|
2018-03-06 20:02:52 +01:00
|
|
|
ZEBRA_IP_PREFIX_ROUTE_ADD);
|
2017-11-20 06:47:04 +01:00
|
|
|
else
|
2019-06-24 01:46:39 +02:00
|
|
|
ip_prefix_send_to_client(ifp->vrf_id, &p,
|
2017-11-20 06:47:04 +01:00
|
|
|
ZEBRA_IP_PREFIX_ROUTE_DEL);
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* zvni_gw_macip_add_to_client
|
|
|
|
*/
|
|
|
|
static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
|
|
|
|
struct ethaddr *macaddr, struct ipaddr *ip)
|
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
zebra_mac_t *mac = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac) {
|
|
|
|
mac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!mac) {
|
2018-09-13 21:21:05 +02:00
|
|
|
flog_err(EC_ZEBRA_MAC_ADD_FAILED,
|
2018-09-13 21:38:57 +02:00
|
|
|
"Failed to add MAC %s intf %s(%u) VID %u",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vxl->access_vlan);
|
2017-06-28 10:51:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
2017-11-13 12:19:52 +01:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
|
2017-06-28 10:51:10 +02:00
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
|
|
|
mac->fwd_info.local.ifindex = ifp->ifindex;
|
|
|
|
mac->fwd_info.local.vid = vxl->access_vlan;
|
|
|
|
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n) {
|
2017-07-06 00:03:14 +02:00
|
|
|
n = zvni_neigh_add(zvni, ip, macaddr);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!n) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_MAC_ADD_FAILED,
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-08-25 02:43:29 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
2017-06-28 10:51:10 +02:00
|
|
|
ifp->name, ifp->ifindex, zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
2018-08-20 22:00:50 +02:00
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
2017-06-28 10:51:10 +02:00
|
|
|
memcpy(&n->emac, macaddr, ETH_ALEN);
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
|
2017-11-13 12:19:52 +01:00
|
|
|
/* Only advertise in BGP if the knob is enabled */
|
2019-08-08 19:43:49 +02:00
|
|
|
if (advertise_gw_macip_enabled(zvni)) {
|
2017-11-13 12:19:52 +01:00
|
|
|
|
2019-08-08 19:43:49 +02:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
|
|
|
|
/* Set Router flag (R-bit) */
|
|
|
|
if (ip->ipa_type == IPADDR_V6)
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2018-07-07 06:46:46 +02:00
|
|
|
"SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x",
|
2017-09-18 23:45:34 +02:00
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
2017-08-25 14:07:58 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
2018-07-07 06:46:46 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2019-08-08 19:43:49 +02:00
|
|
|
zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
|
|
|
|
n->flags, n->loc_seq);
|
|
|
|
} else if (advertise_svi_macip_enabled(zvni)) {
|
|
|
|
|
2019-08-09 03:58:03 +02:00
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP);
|
2019-08-08 19:43:49 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
|
|
|
|
|
|
|
|
zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
|
|
|
|
n->flags, n->loc_seq);
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* zvni_gw_macip_del_from_client
|
|
|
|
*/
|
|
|
|
static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
|
|
|
|
struct ipaddr *ip)
|
|
|
|
{
|
2017-08-25 02:43:29 +02:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2017-06-28 10:51:10 +02:00
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
zebra_mac_t *mac = NULL;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/* If the neigh entry is not present nothing to do*/
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* mac entry should be present */
|
|
|
|
mac = zvni_mac_lookup(zvni, &n->emac);
|
2017-08-25 02:43:29 +02:00
|
|
|
if (!mac) {
|
2019-09-05 17:05:03 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u",
|
|
|
|
prefix_mac2str(&n->emac,
|
|
|
|
buf1, sizeof(buf1)),
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
|
|
|
zvni->vni);
|
2017-08-25 02:43:29 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* If the entry is not local nothing to do*/
|
|
|
|
if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
|
|
|
|
return -1;
|
|
|
|
|
2017-11-13 12:19:52 +01:00
|
|
|
/* only need to delete the entry from bgp if we sent it before */
|
2017-12-13 21:18:11 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
|
2019-06-24 01:46:39 +02:00
|
|
|
ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
|
2018-06-08 19:18:49 +02:00
|
|
|
prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
|
2018-03-06 20:02:52 +01:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)));
|
2017-12-13 21:18:11 +01:00
|
|
|
|
|
|
|
/* Remove neighbor from BGP. */
|
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
|
2019-01-15 00:19:48 +01:00
|
|
|
ZEBRA_MACIP_TYPE_GW, ZEBRA_NEIGH_ACTIVE);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* Delete this neighbor entry. */
|
|
|
|
zvni_neigh_del(zvni, n);
|
|
|
|
|
|
|
|
/* see if the mac needs to be deleted as well*/
|
2017-08-25 14:07:58 +02:00
|
|
|
if (mac)
|
2018-08-29 02:22:04 +02:00
|
|
|
zvni_deref_ip2mac(zvni, mac);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket,
|
2017-09-18 23:45:34 +02:00
|
|
|
void *ctxt)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* Add primary SVI MAC*/
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/* Global (Zvrf) advertise-default-gw is disabled,
|
|
|
|
* but zvni advertise-default-gw is enabled
|
|
|
|
*/
|
|
|
|
if (zvni->advertise_gw_macip) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip",
|
|
|
|
zvni->vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
return;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
vlan_if =
|
|
|
|
zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Del primary MAC-IP */
|
|
|
|
zvni_del_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Del VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_del_macip_for_intf(vrr_if, zvni);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_gw_macip_add_for_vni_hash(struct hash_bucket *bucket,
|
2017-09-18 23:45:34 +02:00
|
|
|
void *ctxt)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
vlan_if =
|
|
|
|
zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Add primary SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
2019-02-05 17:38:35 +01:00
|
|
|
if (advertise_gw_macip_enabled(zvni)) {
|
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_add_macip_for_intf(vrr_if, zvni);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket,
|
2019-02-05 17:38:35 +01:00
|
|
|
void *ctxt)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *ifp;
|
|
|
|
|
|
|
|
/* Add primary SVI MAC*/
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2019-02-05 17:38:35 +01:00
|
|
|
if (!zvni)
|
|
|
|
return;
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/* Global(vrf) advertise-svi-ip disabled, but zvni advertise-svi-ip
|
|
|
|
* enabled
|
|
|
|
*/
|
|
|
|
if (zvni->advertise_svi_macip) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip",
|
|
|
|
zvni->vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-05 17:38:35 +01:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
|
|
|
vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Del primary MAC-IP */
|
|
|
|
zvni_del_macip_for_intf(vlan_if, zvni);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-03 00:28:33 +01:00
|
|
|
static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
|
|
|
struct interface *ifp,
|
|
|
|
struct ipaddr *ip,
|
2018-07-07 06:46:46 +02:00
|
|
|
struct ethaddr *macaddr,
|
2018-09-10 19:13:20 +02:00
|
|
|
bool is_router)
|
2018-03-03 00:28:33 +01:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2018-11-02 16:30:41 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
2018-03-03 00:28:33 +01:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
zebra_mac_t *zmac = NULL, *old_zmac = NULL;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint32_t old_mac_seq = 0, mac_new_seq = 0;
|
|
|
|
bool upd_mac_seq = false;
|
|
|
|
bool neigh_mac_change = false;
|
2018-11-02 16:30:41 +01:00
|
|
|
bool neigh_on_hold = false;
|
|
|
|
bool neigh_was_remote = false;
|
2018-11-17 05:38:39 +01:00
|
|
|
bool do_dad = false;
|
2018-11-02 16:30:41 +01:00
|
|
|
struct in_addr vtep_ip = {.s_addr = 0};
|
2018-03-03 00:28:33 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Check if the MAC exists. */
|
2018-03-03 00:28:33 +01:00
|
|
|
zmac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!zmac) {
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* create a dummy MAC if the MAC is not already present */
|
2018-03-03 00:28:33 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"AUTO MAC %s created for neigh %s on VNI %u",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
|
|
|
|
|
|
|
|
zmac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!zmac) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("Failed to add MAC %s VNI %u",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
2018-03-03 00:28:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
|
|
|
|
memset(&zmac->flags, 0, sizeof(uint32_t));
|
|
|
|
SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
} else {
|
|
|
|
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
/*
|
|
|
|
* We don't change the MAC to local upon a neighbor
|
|
|
|
* learn event, we wait for the explicit local MAC
|
|
|
|
* learn. However, we have to compute its sequence
|
|
|
|
* number in preparation for when it actually turns
|
|
|
|
* local.
|
|
|
|
*/
|
|
|
|
upd_mac_seq = true;
|
|
|
|
}
|
2018-03-03 00:28:33 +01:00
|
|
|
}
|
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
2019-03-08 16:46:55 +01:00
|
|
|
if (!zvrf) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-06-24 01:46:39 +02:00
|
|
|
zlog_debug("\tUnable to find vrf for: %d",
|
|
|
|
zvni->vxlan_if->vrf_id);
|
2018-11-02 16:30:41 +01:00
|
|
|
return -1;
|
2019-03-08 16:46:55 +01:00
|
|
|
}
|
2018-11-02 16:30:41 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Check if the neighbor exists. */
|
2018-03-03 00:28:33 +01:00
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (!n) {
|
|
|
|
/* New neighbor - create */
|
|
|
|
n = zvni_neigh_add(zvni, ip, macaddr);
|
|
|
|
if (!n) {
|
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_MAC_ADD_FAILED,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
"Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
} else {
|
2018-03-03 00:28:33 +01:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
2018-09-10 19:19:41 +02:00
|
|
|
bool mac_different;
|
|
|
|
bool cur_is_router;
|
|
|
|
|
|
|
|
/* Note any changes and see if of interest to BGP. */
|
|
|
|
mac_different = (memcmp(n->emac.octet,
|
|
|
|
macaddr->octet, ETH_ALEN) != 0) ? 1 : 0;
|
|
|
|
cur_is_router = !!CHECK_FLAG(n->flags,
|
|
|
|
ZEBRA_NEIGH_ROUTER_FLAG);
|
|
|
|
if (!mac_different && is_router == cur_is_router) {
|
2019-03-08 16:46:55 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"\tIgnoring entry mac is the same and is_router == cur_is_router");
|
2018-03-03 00:28:33 +01:00
|
|
|
n->ifindex = ifp->ifindex;
|
2018-09-10 19:19:41 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2018-03-03 00:28:33 +01:00
|
|
|
|
2018-09-10 19:19:41 +02:00
|
|
|
if (!mac_different) {
|
2018-11-02 16:30:41 +01:00
|
|
|
bool is_neigh_freezed = false;
|
|
|
|
|
2018-09-10 19:19:41 +02:00
|
|
|
/* Only the router flag has changed. */
|
|
|
|
if (is_router)
|
|
|
|
SET_FLAG(n->flags,
|
|
|
|
ZEBRA_NEIGH_ROUTER_FLAG);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(n->flags,
|
|
|
|
ZEBRA_NEIGH_ROUTER_FLAG);
|
2018-03-03 00:28:33 +01:00
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Neigh is in freeze state and freeze action
|
|
|
|
* is enabled, do not send update to client.
|
|
|
|
*/
|
|
|
|
is_neigh_freezed = (zvrf->dup_addr_detect &&
|
|
|
|
zvrf->dad_freeze &&
|
|
|
|
CHECK_FLAG(n->flags,
|
|
|
|
ZEBRA_NEIGH_DUPLICATE));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n) &&
|
|
|
|
!is_neigh_freezed)
|
2018-09-10 19:19:41 +02:00
|
|
|
return zvni_neigh_send_add_to_client(
|
|
|
|
zvni->vni, ip, macaddr,
|
|
|
|
n->flags, n->loc_seq);
|
2019-03-08 16:46:55 +01:00
|
|
|
else {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"\tNeighbor active and frozen");
|
|
|
|
}
|
2018-09-10 19:19:41 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The MAC has changed, need to issue a delete
|
|
|
|
* first as this means a different MACIP route.
|
|
|
|
* Also, need to do some unlinking/relinking.
|
|
|
|
* We also need to update the MAC's sequence number
|
|
|
|
* in different situations.
|
|
|
|
*/
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n))
|
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
|
2019-01-15 00:19:48 +01:00
|
|
|
&n->emac, 0, n->state);
|
2018-09-10 19:19:41 +02:00
|
|
|
old_zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (old_zmac) {
|
|
|
|
old_mac_seq = CHECK_FLAG(old_zmac->flags,
|
|
|
|
ZEBRA_MAC_REMOTE) ?
|
|
|
|
old_zmac->rem_seq : old_zmac->loc_seq;
|
|
|
|
neigh_mac_change = upd_mac_seq = true;
|
|
|
|
listnode_delete(old_zmac->neigh_list, n);
|
|
|
|
zvni_deref_ip2mac(zvni, old_zmac);
|
zebra: check router_flag change for neigh update
Neigh update can have router_flag change, from unset to set and
viceversa. This is the case where MAC, IP and VLAN are same but
entry's flag moved from R to not R bit and reverse case.
Router flag change needs to trigger bgpd to inform all evpn peers
to remove from the evpn route.
Testing Done:
Send GARP with and without R bit from host and validate neigh entry
and evpn neigh and mac-ip route entry in zebra and bgpd.
Check Peer VTEP evpn route entry where router flag is (un)set.
With R-bit
Route [2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
VNI 1001
Imported from
27.0.0.16:5:[2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
4435 5551
27.0.0.16 from MSP1(uplink-1) (27.0.0.9)
Origin IGP, valid, external, bestpath-from-AS 4435, best
Extended Community: RT:5551:1001 ET:8 ND:Router
Flag
AddPath ID: RX 0, TX 1261
Last update: Wed Aug 15 20:52:14 2018
Without R-bit
Route [2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
VNI 1001
Imported from
27.0.0.16:5:[2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
4435 5551
27.0.0.16 from MSP2(uplink-2) (27.0.0.10)
Origin IGP, valid, external, bestpath-from-AS 4435, best
Extended Community: RT:5551:1001 ET:8
AddPath ID: RX 0, TX 1263
Last update: Wed Aug 15 20:53:10 2018
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2018-08-15 22:32:03 +02:00
|
|
|
}
|
2018-03-03 00:28:33 +01:00
|
|
|
|
2018-09-10 19:19:41 +02:00
|
|
|
/* Update the forwarding info. */
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
memcpy(&n->emac, macaddr, ETH_ALEN);
|
|
|
|
|
|
|
|
/* Link to new MAC */
|
|
|
|
listnode_add_sort(zmac->neigh_list, n);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
/*
|
|
|
|
* Neighbor has moved from remote to local. Its
|
|
|
|
* MAC could have also changed as part of the move.
|
|
|
|
*/
|
2018-03-03 00:28:33 +01:00
|
|
|
if (memcmp(n->emac.octet, macaddr->octet,
|
|
|
|
ETH_ALEN) != 0) {
|
|
|
|
old_zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (old_zmac) {
|
2018-08-20 23:31:30 +02:00
|
|
|
old_mac_seq = CHECK_FLAG(
|
|
|
|
old_zmac->flags,
|
|
|
|
ZEBRA_MAC_REMOTE) ?
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
old_zmac->rem_seq :
|
|
|
|
old_zmac->loc_seq;
|
|
|
|
neigh_mac_change = upd_mac_seq = true;
|
2018-04-12 15:20:20 +02:00
|
|
|
listnode_delete(old_zmac->neigh_list,
|
|
|
|
n);
|
2018-08-29 02:22:04 +02:00
|
|
|
zvni_deref_ip2mac(zvni, old_zmac);
|
2018-03-03 00:28:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Link to new MAC */
|
|
|
|
memcpy(&n->emac, macaddr, ETH_ALEN);
|
|
|
|
listnode_add_sort(zmac->neigh_list, n);
|
|
|
|
}
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Based on Mobility event Scenario-B from the
|
|
|
|
* draft, neigh's previous state was remote treat this
|
|
|
|
* event for DAD.
|
|
|
|
*/
|
|
|
|
neigh_was_remote = true;
|
|
|
|
vtep_ip = n->r_vtep_ip;
|
2018-03-03 00:28:33 +01:00
|
|
|
/* Mark appropriately */
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
|
|
|
n->r_vtep_ip.s_addr = 0;
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
}
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If MAC was previously remote, or the neighbor had a different
|
|
|
|
* MAC earlier, recompute the sequence number.
|
|
|
|
*/
|
|
|
|
if (upd_mac_seq) {
|
|
|
|
uint32_t seq1, seq2;
|
|
|
|
|
|
|
|
seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) ?
|
|
|
|
zmac->rem_seq + 1 : zmac->loc_seq;
|
|
|
|
seq2 = neigh_mac_change ? old_mac_seq + 1 : 0;
|
|
|
|
mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ?
|
|
|
|
MAX(seq1, seq2) : zmac->loc_seq;
|
2018-03-03 00:28:33 +01:00
|
|
|
}
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Mark Router flag (R-bit) */
|
2018-09-10 19:13:20 +02:00
|
|
|
if (is_router)
|
2018-08-14 02:07:22 +02:00
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Check old and/or new MAC detected as duplicate mark
|
|
|
|
* the neigh as duplicate
|
|
|
|
*/
|
|
|
|
if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) {
|
|
|
|
flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
|
|
|
"VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC",
|
|
|
|
zvni->vni,
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
|
|
|
}
|
|
|
|
|
2018-11-17 05:38:39 +01:00
|
|
|
/* For IP Duplicate Address Detection (DAD) is trigger,
|
|
|
|
* when the event is extended mobility based on scenario-B
|
|
|
|
* from the draft, IP/Neigh's MAC binding changed and
|
|
|
|
* neigh's previous state was remote.
|
2018-11-02 16:30:41 +01:00
|
|
|
*/
|
2018-11-17 05:38:39 +01:00
|
|
|
if (neigh_mac_change && neigh_was_remote)
|
|
|
|
do_dad = true;
|
2018-11-02 16:30:41 +01:00
|
|
|
|
2018-11-17 05:38:39 +01:00
|
|
|
zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n, vtep_ip, do_dad,
|
|
|
|
&neigh_on_hold, true);
|
2018-11-04 17:20:11 +01:00
|
|
|
|
2018-03-03 00:28:33 +01:00
|
|
|
/* Before we program this in BGP, we need to check if MAC is locally
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
* learnt. If not, force neighbor to be inactive and reset its seq.
|
2018-03-03 00:28:33 +01:00
|
|
|
*/
|
|
|
|
if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
|
2018-08-20 20:21:21 +02:00
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->loc_seq = 0;
|
|
|
|
zmac->loc_seq = mac_new_seq;
|
2018-03-03 00:28:33 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* If the MAC's sequence number has changed, inform the MAC and all
|
|
|
|
* neighbors associated with the MAC to BGP, else just inform this
|
|
|
|
* neighbor.
|
|
|
|
*/
|
|
|
|
if (upd_mac_seq && zmac->loc_seq != mac_new_seq) {
|
zebra: check router_flag change for neigh update
Neigh update can have router_flag change, from unset to set and
viceversa. This is the case where MAC, IP and VLAN are same but
entry's flag moved from R to not R bit and reverse case.
Router flag change needs to trigger bgpd to inform all evpn peers
to remove from the evpn route.
Testing Done:
Send GARP with and without R bit from host and validate neigh entry
and evpn neigh and mac-ip route entry in zebra and bgpd.
Check Peer VTEP evpn route entry where router flag is (un)set.
With R-bit
Route [2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
VNI 1001
Imported from
27.0.0.16:5:[2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
4435 5551
27.0.0.16 from MSP1(uplink-1) (27.0.0.9)
Origin IGP, valid, external, bestpath-from-AS 4435, best
Extended Community: RT:5551:1001 ET:8 ND:Router
Flag
AddPath ID: RX 0, TX 1261
Last update: Wed Aug 15 20:52:14 2018
Without R-bit
Route [2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
VNI 1001
Imported from
27.0.0.16:5:[2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
4435 5551
27.0.0.16 from MSP2(uplink-2) (27.0.0.10)
Origin IGP, valid, external, bestpath-from-AS 4435, best
Extended Community: RT:5551:1001 ET:8
AddPath ID: RX 0, TX 1263
Last update: Wed Aug 15 20:53:10 2018
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2018-08-15 22:32:03 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
zlog_debug("Seq changed for MAC %s VNI %u - old %u new %u",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni, zmac->loc_seq, mac_new_seq);
|
|
|
|
zmac->loc_seq = mac_new_seq;
|
|
|
|
if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
|
|
|
|
zmac->flags, zmac->loc_seq))
|
|
|
|
return -1;
|
|
|
|
zvni_process_neigh_on_local_mac_change(zvni, zmac, 1);
|
zebra: check router_flag change for neigh update
Neigh update can have router_flag change, from unset to set and
viceversa. This is the case where MAC, IP and VLAN are same but
entry's flag moved from R to not R bit and reverse case.
Router flag change needs to trigger bgpd to inform all evpn peers
to remove from the evpn route.
Testing Done:
Send GARP with and without R bit from host and validate neigh entry
and evpn neigh and mac-ip route entry in zebra and bgpd.
Check Peer VTEP evpn route entry where router flag is (un)set.
With R-bit
Route [2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
VNI 1001
Imported from
27.0.0.16:5:[2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
4435 5551
27.0.0.16 from MSP1(uplink-1) (27.0.0.9)
Origin IGP, valid, external, bestpath-from-AS 4435, best
Extended Community: RT:5551:1001 ET:8 ND:Router
Flag
AddPath ID: RX 0, TX 1261
Last update: Wed Aug 15 20:52:14 2018
Without R-bit
Route [2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
VNI 1001
Imported from
27.0.0.16:5:[2]:[0]:[0]:[48]:[00:1f:2f:db:45:a6]:[128]:[2006:33:33:2::10]
4435 5551
27.0.0.16 from MSP2(uplink-2) (27.0.0.10)
Origin IGP, valid, external, bestpath-from-AS 4435, best
Extended Community: RT:5551:1001 ET:8
AddPath ID: RX 0, TX 1263
Last update: Wed Aug 15 20:53:10 2018
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2018-08-15 22:32:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->loc_seq = zmac->loc_seq;
|
2018-03-03 00:28:33 +01:00
|
|
|
|
2019-03-22 18:02:07 +01:00
|
|
|
if (!neigh_on_hold) {
|
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n->flags, n->loc_seq);
|
2019-03-22 18:02:07 +01:00
|
|
|
} else {
|
2019-03-08 16:46:55 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("\tNeighbor on hold not sending");
|
|
|
|
}
|
2018-11-02 16:30:41 +01:00
|
|
|
return 0;
|
2018-03-03 00:28:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int zvni_remote_neigh_update(zebra_vni_t *zvni,
|
|
|
|
struct interface *ifp,
|
|
|
|
struct ipaddr *ip,
|
|
|
|
struct ethaddr *macaddr,
|
|
|
|
uint16_t state)
|
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
zebra_mac_t *zmac = NULL;
|
|
|
|
|
|
|
|
/* If the neighbor is unknown, there is no further action. */
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If a remote entry, see if it needs to be refreshed */
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
2018-02-26 23:10:50 +01:00
|
|
|
#ifdef GNU_LINUX
|
2018-03-03 00:28:33 +01:00
|
|
|
if (state & NUD_STALE)
|
|
|
|
zvni_neigh_install(zvni, n);
|
2018-02-26 23:10:50 +01:00
|
|
|
#endif
|
2018-03-03 00:28:33 +01:00
|
|
|
} else {
|
|
|
|
/* We got a "remote" neighbor notification for an entry
|
|
|
|
* we think is local. This can happen in a multihoming
|
|
|
|
* scenario - but only if the MAC is already "remote".
|
|
|
|
* Just mark our entry as "remote".
|
|
|
|
*/
|
|
|
|
zmac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2018-06-19 20:29:05 +02:00
|
|
|
"Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local",
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)),
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
2018-03-03 00:28:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
2018-10-16 17:23:22 +02:00
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
2018-03-03 00:28:33 +01:00
|
|
|
n->r_vtep_ip = zmac->fwd_info.r_vtep_ip;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Make hash key for MAC.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int mac_hash_keymake(const void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const zebra_mac_t *pmac = p;
|
2017-08-03 13:43:47 +02:00
|
|
|
const void *pnt = (void *)pmac->macaddr.octet;
|
|
|
|
|
2017-08-03 14:43:56 +02:00
|
|
|
return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Compare two MAC addresses.
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool mac_cmp(const void *p1, const void *p2)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_mac_t *pmac1 = p1;
|
|
|
|
const zebra_mac_t *pmac2 = p2;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (pmac1 == NULL && pmac2 == NULL)
|
2018-10-17 21:27:12 +02:00
|
|
|
return true;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (pmac1 == NULL || pmac2 == NULL)
|
2018-10-17 21:27:12 +02:00
|
|
|
return false;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
|
2017-07-17 14:03:14 +02:00
|
|
|
== 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate MAC hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_mac_alloc(void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_mac_t *tmp_mac = p;
|
|
|
|
zebra_mac_t *mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
|
|
|
|
*mac = *tmp_mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return ((void *)mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add MAC entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t tmp_mac;
|
|
|
|
zebra_mac_t *mac = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_mac, 0, sizeof(zebra_mac_t));
|
2017-08-03 14:43:56 +02:00
|
|
|
memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
|
|
|
|
assert(mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-03-16 03:09:25 +01:00
|
|
|
mac->zvni = zvni;
|
|
|
|
mac->dad_mac_auto_recovery_timer = NULL;
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
mac->neigh_list = list_new();
|
2018-10-17 21:31:09 +02:00
|
|
|
mac->neigh_list->cmp = neigh_list_cmp;
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete MAC entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *tmp_mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-03-16 03:09:25 +01:00
|
|
|
/* Cancel auto recovery */
|
|
|
|
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
|
|
|
|
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&mac->neigh_list);
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
|
|
|
tmp_mac = hash_release(zvni->mac_table, mac);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_MAC, tmp_mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2019-07-26 23:57:59 +02:00
|
|
|
static bool zvni_check_mac_del_from_db(struct mac_walk_ctx *wctx,
|
|
|
|
zebra_mac_t *mac)
|
|
|
|
{
|
|
|
|
if ((wctx->flags & DEL_LOCAL_MAC) &&
|
|
|
|
(mac->flags & ZEBRA_MAC_LOCAL))
|
|
|
|
return true;
|
|
|
|
else if ((wctx->flags & DEL_REMOTE_MAC) &&
|
|
|
|
(mac->flags & ZEBRA_MAC_REMOTE))
|
|
|
|
return true;
|
|
|
|
else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) &&
|
|
|
|
(mac->flags & ZEBRA_MAC_REMOTE) &&
|
|
|
|
IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
|
|
|
|
return true;
|
|
|
|
else if ((wctx->flags & DEL_LOCAL_MAC) &&
|
|
|
|
(mac->flags & ZEBRA_MAC_AUTO) &&
|
|
|
|
!listcount(mac->neigh_list)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN) {
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
|
|
|
|
zlog_debug("%s: Del MAC %s flags 0x%x",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&mac->macaddr,
|
|
|
|
buf, sizeof(buf)),
|
|
|
|
mac->flags);
|
|
|
|
}
|
|
|
|
wctx->uninstall = 0;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Free MAC hash entry (callback)
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx *wctx = arg;
|
2019-02-19 16:46:52 +01:00
|
|
|
zebra_mac_t *mac = bucket->data;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-07-26 23:57:59 +02:00
|
|
|
if (zvni_check_mac_del_from_db(wctx, mac)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
|
2018-03-06 20:02:52 +01:00
|
|
|
zvni_mac_send_del_to_client(wctx->zvni->vni,
|
2018-10-11 17:48:42 +02:00
|
|
|
&mac->macaddr);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
if (wctx->uninstall)
|
2018-08-29 02:02:40 +02:00
|
|
|
zvni_mac_uninstall(wctx->zvni, mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
zvni_mac_del(wctx->zvni, mac);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all MAC entries from specific VTEP for a particular VNI.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->mac_table)
|
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.flags = DEL_REMOTE_MAC_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = *r_vtep_ip;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_mac_del_hash_entry, &wctx);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all MAC entries for this VNI.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->mac_table)
|
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.upd_client = upd_client;
|
|
|
|
wctx.flags = flags;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-06-08 01:49:17 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_mac_del_hash_entry, &wctx);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up MAC hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t tmp;
|
|
|
|
zebra_mac_t *pmac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
2017-08-03 14:43:56 +02:00
|
|
|
memcpy(&tmp.macaddr, mac, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
pmac = hash_lookup(zvni->mac_table, &tmp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return pmac;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local MAC addition.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint8_t mac_flags, uint32_t seq)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t flags = 0;
|
2017-11-13 12:19:52 +01:00
|
|
|
|
|
|
|
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
|
|
|
|
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
|
|
|
|
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
|
2019-01-15 00:19:48 +01:00
|
|
|
seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local MAC deletion.
|
|
|
|
*/
|
2018-10-11 17:48:42 +02:00
|
|
|
static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2018-10-11 17:48:42 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
|
2019-01-15 00:19:48 +01:00
|
|
|
0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC
|
2017-09-18 23:45:34 +02:00
|
|
|
* notifications, to see if they are of interest.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
|
|
|
|
struct interface *br_if, vlanid_t vid)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_bridge *br;
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t bridge_vlan_aware;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2017-09-18 23:45:34 +02:00
|
|
|
int found = 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
br = &zif->l2info.br;
|
|
|
|
bridge_vlan_aware = br->vlan_aware;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
|
|
|
/* TODO: Optimize with a hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
|
|
|
if (!tmp_if)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
if (!if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zif->brslave_info.br_if != br_if)
|
|
|
|
continue;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
|
|
|
|
found = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!found)
|
2017-07-17 14:03:14 +02:00
|
|
|
return NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vxl->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map SVI and associated bridge to a VNI. This is invoked upon getting
|
|
|
|
* neighbor notifications, to see if they are of interest.
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
|
|
|
|
struct interface *br_if)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_bridge *br;
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t bridge_vlan_aware;
|
2017-07-17 14:03:14 +02:00
|
|
|
vlanid_t vid = 0;
|
|
|
|
zebra_vni_t *zvni;
|
2017-09-18 23:45:34 +02:00
|
|
|
int found = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-20 02:28:58 +02:00
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Make sure the linked interface is a bridge. */
|
|
|
|
if (!IS_ZEBRA_IF_BRIDGE(br_if))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
br = &zif->l2info.br;
|
|
|
|
bridge_vlan_aware = br->vlan_aware;
|
|
|
|
if (bridge_vlan_aware) {
|
|
|
|
struct zebra_l2info_vlan *vl;
|
|
|
|
|
|
|
|
if (!IS_ZEBRA_IF_VLAN(ifp))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vl = &zif->l2info.vl;
|
|
|
|
vid = vl->vid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
|
|
|
/* TODO: Optimize with a hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
|
|
|
if (!tmp_if)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
if (!if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
|
|
|
if (zif->brslave_info.br_if != br_if)
|
|
|
|
continue;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
|
|
|
|
found = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!found)
|
2017-07-17 14:03:14 +02:00
|
|
|
return NULL;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vxl->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
|
|
|
|
* of two cases:
|
|
|
|
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
|
|
|
|
* linked to the bridge
|
2019-08-02 08:33:24 +02:00
|
|
|
* (b) In the case of a VLAN-unaware bridge, the SVI is the bridge interface
|
2017-05-15 07:44:13 +02:00
|
|
|
* itself
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_bridge *br;
|
|
|
|
struct zebra_l2info_vlan *vl;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t bridge_vlan_aware;
|
2017-09-18 23:45:34 +02:00
|
|
|
int found = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
/* Defensive check, caller expected to invoke only with valid bridge. */
|
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
br = &zif->l2info.br;
|
|
|
|
bridge_vlan_aware = br->vlan_aware;
|
|
|
|
|
|
|
|
/* Check oper status of the SVI. */
|
|
|
|
if (!bridge_vlan_aware)
|
|
|
|
return if_is_operative(br_if) ? br_if : NULL;
|
|
|
|
|
|
|
|
/* Identify corresponding VLAN interface. */
|
|
|
|
/* TODO: Optimize with a hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Check oper status of the SVI. */
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!tmp_if || !if_is_operative(tmp_if))
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|
|
|
|
|| zif->link != br_if)
|
|
|
|
continue;
|
|
|
|
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (vl->vid == vid) {
|
|
|
|
found = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
return found ? tmp_if : NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
/* Map to MAC-VLAN interface corresponding to specified SVI interface.
|
|
|
|
*/
|
|
|
|
static struct interface *zvni_map_to_macvlan(struct interface *br_if,
|
|
|
|
struct interface *svi_if)
|
|
|
|
{
|
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
|
|
|
struct zebra_if *zif;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
/* Defensive check, caller expected to invoke only with valid bridge. */
|
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!svi_if) {
|
|
|
|
zlog_debug("svi_if is not passed.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
|
|
|
|
/* Identify corresponding VLAN interface. */
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
|
|
|
/* Check oper status of the SVI. */
|
|
|
|
if (!tmp_if || !if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
zif = tmp_if->info;
|
|
|
|
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (zif->link == svi_if) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return found ? tmp_if : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
2019-07-30 17:54:07 +02:00
|
|
|
* Install remote MAC into the forwarding plane.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct zebra_if *zif, *br_zif;
|
|
|
|
const struct zebra_l2info_vxlan *vxl;
|
2018-09-10 19:13:20 +02:00
|
|
|
bool sticky;
|
2019-07-30 17:54:07 +02:00
|
|
|
enum zebra_dplane_result res;
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct interface *br_ifp;
|
|
|
|
vlanid_t vid;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!(mac->flags & ZEBRA_MAC_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
2019-09-05 18:58:58 +02:00
|
|
|
|
|
|
|
br_ifp = zif->brslave_info.br_if;
|
|
|
|
if (br_ifp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-09-10 19:13:20 +02:00
|
|
|
sticky = !!CHECK_FLAG(mac->flags,
|
|
|
|
(ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
|
2017-05-15 23:42:57 +02:00
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_zif = (const struct zebra_if *)(br_ifp->info);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
|
|
|
|
vid = vxl->access_vlan;
|
|
|
|
else
|
|
|
|
vid = 0;
|
|
|
|
|
|
|
|
res = dplane_mac_add(zvni->vxlan_if, br_ifp, vid,
|
|
|
|
&mac->macaddr, mac->fwd_info.r_vtep_ip, sticky);
|
2019-07-30 17:54:07 +02:00
|
|
|
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-07-30 17:54:07 +02:00
|
|
|
* Uninstall remote MAC from the forwarding plane.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2018-08-29 02:02:40 +02:00
|
|
|
static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct zebra_if *zif, *br_zif;
|
|
|
|
const struct zebra_l2info_vxlan *vxl;
|
2018-09-17 18:13:15 +02:00
|
|
|
struct in_addr vtep_ip;
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct interface *ifp, *br_ifp;
|
|
|
|
vlanid_t vid;
|
2019-07-30 17:54:07 +02:00
|
|
|
enum zebra_dplane_result res;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-08-29 02:02:40 +02:00
|
|
|
if (!(mac->flags & ZEBRA_MAC_REMOTE))
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
2019-09-05 17:05:03 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
|
|
|
|
zvni->vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
2019-09-05 18:58:58 +02:00
|
|
|
|
|
|
|
br_ifp = zif->brslave_info.br_if;
|
|
|
|
if (br_ifp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_zif = (const struct zebra_if *)br_ifp->info;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
|
|
|
|
vid = vxl->access_vlan;
|
|
|
|
else
|
|
|
|
vid = 0;
|
|
|
|
|
2018-08-29 02:02:40 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
vtep_ip = mac->fwd_info.r_vtep_ip;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
res = dplane_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
|
2019-07-30 17:54:07 +02:00
|
|
|
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install MAC hash entry - called upon access VLAN change.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *mac;
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
mac = (zebra_mac_t *)bucket->data;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
zvni_mac_install(wctx->zvni, mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 02:22:04 +02:00
|
|
|
/*
|
|
|
|
* Count of remote neighbors referencing this MAC.
|
|
|
|
*/
|
|
|
|
static int remote_neigh_count(zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Decrement neighbor refcount of MAC; uninstall and free it if
|
|
|
|
* appropriate.
|
|
|
|
*/
|
2018-08-29 02:22:04 +02:00
|
|
|
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2018-08-29 02:22:04 +02:00
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-08-29 02:22:04 +02:00
|
|
|
/* If all remote neighbors referencing a remote MAC go away,
|
|
|
|
* we need to uninstall the MAC.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
|
|
|
|
remote_neigh_count(mac) == 0) {
|
2018-08-29 02:02:40 +02:00
|
|
|
zvni_mac_uninstall(zvni, mac);
|
2018-08-29 02:22:04 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-08-29 02:22:04 +02:00
|
|
|
/* If no neighbors, delete the MAC. */
|
|
|
|
if (list_isempty(mac->neigh_list))
|
|
|
|
zvni_mac_del(zvni, mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read and populate local MACs and neighbors corresponding to this VNI.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct interface *vlan_if;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
2017-06-28 10:51:10 +02:00
|
|
|
struct interface *vrr_if;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zif->brslave_info.bridge_ifindex);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if);
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (vlan_if) {
|
|
|
|
|
2017-11-13 12:19:52 +01:00
|
|
|
/* Add SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-11-13 12:19:52 +01:00
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_add_macip_for_intf(vrr_if, zvni);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
neigh_read_for_vlan(zns, vlan_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Hash function for VNI.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int vni_hash_keymake(const void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_vni_t *zvni = p;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (jhash_1word(zvni->vni, 0));
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare 2 VNI hash entries.
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool vni_hash_cmp(const void *p1, const void *p2)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_vni_t *zvni1 = p1;
|
|
|
|
const zebra_vni_t *zvni2 = p2;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (zvni1->vni == zvni2->vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2018-10-17 21:31:09 +02:00
|
|
|
static int vni_list_cmp(void *p1, void *p2)
|
|
|
|
{
|
|
|
|
const zebra_vni_t *zvni1 = p1;
|
|
|
|
const zebra_vni_t *zvni2 = p2;
|
|
|
|
|
|
|
|
if (zvni1->vni == zvni2->vni)
|
|
|
|
return 0;
|
|
|
|
return (zvni1->vni < zvni2->vni) ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Callback to allocate VNI hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_alloc(void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_vni_t *tmp_vni = p;
|
|
|
|
zebra_vni_t *zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = XCALLOC(MTYPE_ZVNI, sizeof(zebra_vni_t));
|
|
|
|
zvni->vni = tmp_vni->vni;
|
|
|
|
return ((void *)zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up VNI hash entry.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static zebra_vni_t *zvni_lookup(vni_t vni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t tmp_vni;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-03-06 19:15:10 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2017-09-18 23:45:34 +02:00
|
|
|
assert(zvrf);
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_vni, 0, sizeof(zebra_vni_t));
|
|
|
|
tmp_vni.vni = vni;
|
|
|
|
zvni = hash_lookup(zvrf->vni_table, &tmp_vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add VNI hash entry.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static zebra_vni_t *zvni_add(vni_t vni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t tmp_zvni;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-03-06 19:15:10 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2017-09-18 23:45:34 +02:00
|
|
|
assert(zvrf);
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_zvni, 0, sizeof(zebra_vni_t));
|
|
|
|
tmp_zvni.vni = vni;
|
|
|
|
zvni = hash_get(zvrf->vni_table, &tmp_zvni, zvni_alloc);
|
|
|
|
assert(zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Create hash table for MAC */
|
|
|
|
zvni->mac_table =
|
|
|
|
hash_create(mac_hash_keymake, mac_cmp, "Zebra VNI MAC Table");
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Create hash table for neighbors */
|
|
|
|
zvni->neigh_table = hash_create(neigh_hash_keymake, neigh_cmp,
|
|
|
|
"Zebra VNI Neighbor Table");
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete VNI hash entry.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_del(zebra_vni_t *zvni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *tmp_zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-03-06 19:15:10 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2017-09-18 23:45:34 +02:00
|
|
|
assert(zvrf);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni->vxlan_if = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-03-19 21:26:22 +01:00
|
|
|
/* Remove references to the BUM mcast grp */
|
|
|
|
zebra_vxlan_sg_deref(zvni->local_vtep_ip, zvni->mcast_grp);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the neighbor hash table. */
|
|
|
|
hash_free(zvni->neigh_table);
|
|
|
|
zvni->neigh_table = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the MAC hash table. */
|
|
|
|
hash_free(zvni->mac_table);
|
|
|
|
zvni->mac_table = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
|
|
|
tmp_zvni = hash_release(zvrf->vni_table, zvni);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_ZVNI, tmp_zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local VNI addition.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_send_add_to_client(zebra_vni_t *zvni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zserv *client;
|
|
|
|
struct stream *s;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-02-19 21:45:38 +01:00
|
|
|
zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id());
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_putl(s, zvni->vni);
|
|
|
|
stream_put_in_addr(s, &zvni->local_vtep_ip);
|
2017-10-08 03:49:27 +02:00
|
|
|
stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
|
2019-03-19 17:10:47 +01:00
|
|
|
stream_put_in_addr(s, &zvni->mcast_grp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Send VNI_ADD %u %s tenant vrf %s to %s", zvni->vni,
|
|
|
|
inet_ntoa(zvni->local_vtep_ip),
|
2017-10-08 03:49:27 +02:00
|
|
|
vrf_id_to_name(zvni->vrf_id),
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
client->vniadd_cnt++;
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local VNI deletion.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_send_del_to_client(vni_t vni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zserv *client;
|
|
|
|
struct stream *s;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_reset(s);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-02-19 21:45:38 +01:00
|
|
|
zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id());
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_putl(s, vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Send VNI_DEL %u to %s", vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
client->vnidel_cnt++;
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the VNI hash table by going over the VxLAN interfaces. This
|
|
|
|
* is called when EVPN (advertise-all-vni) is enabled.
|
|
|
|
*/
|
2019-01-24 10:12:36 +01:00
|
|
|
static void zvni_build_hash_table(void)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct interface *ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Walk VxLAN interfaces and create VNI hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
2017-10-08 03:49:27 +02:00
|
|
|
vni_t vni;
|
2018-01-25 00:25:03 +01:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
ifp = (struct interface *)rn->info;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
vxl = &zif->l2info.vxl;
|
2017-07-17 14:03:14 +02:00
|
|
|
vni = vxl->vni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2018-01-25 00:25:03 +01:00
|
|
|
/* L3-VNI and L2-VNI are handled seperately */
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug(
|
|
|
|
"create L3-VNI hash for Intf %s(%u) L3-VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* associate with vxlan_if */
|
2017-10-31 00:58:15 +01:00
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vxlan_if = ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-12-27 20:47:10 +01:00
|
|
|
/*
|
|
|
|
* we need to associate with SVI.
|
2017-10-08 03:49:27 +02:00
|
|
|
* we can associate with svi-if only after association
|
2017-12-27 20:47:10 +01:00
|
|
|
* with vxlan-intf is complete
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
/* Associate l3vni to mac-vlan and extract VRR MAC */
|
|
|
|
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s",
|
|
|
|
vni, zl3vni->svi_if ? zl3vni->svi_if->name
|
|
|
|
: "NIL",
|
|
|
|
zl3vni->mac_vlan_if ?
|
|
|
|
zl3vni->mac_vlan_if->name : "NIL");
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %s",
|
|
|
|
ifp->name, ifp->ifindex, vni,
|
|
|
|
inet_ntoa(vxl->vtep_ip));
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/* VNI hash entry is expected to exist, if the BGP process is killed */
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (zvni) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-10-08 03:49:27 +02:00
|
|
|
"VNI hash already present for IF %s(%u) L2-VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP if intf is up and mapped to
|
|
|
|
* bridge.
|
|
|
|
*/
|
|
|
|
if (if_is_operative(ifp) &&
|
|
|
|
zif->brslave_info.br_if)
|
|
|
|
zvni_send_add_to_client(zvni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/* Send Local MAC-entries to client */
|
|
|
|
zvni_send_mac_to_client(zvni);
|
|
|
|
|
|
|
|
/* Send Loval Neighbor entries to client */
|
|
|
|
zvni_send_neigh_to_client(zvni);
|
|
|
|
} else {
|
|
|
|
zvni = zvni_add(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
zlog_debug(
|
|
|
|
"Failed to add VNI hash, IF %s(%u) L2-VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
if (zvni->local_vtep_ip.s_addr !=
|
|
|
|
vxl->vtep_ip.s_addr ||
|
|
|
|
zvni->mcast_grp.s_addr !=
|
|
|
|
vxl->mcast_grp.s_addr) {
|
|
|
|
zebra_vxlan_sg_deref(
|
|
|
|
zvni->local_vtep_ip,
|
|
|
|
zvni->mcast_grp);
|
|
|
|
zebra_vxlan_sg_ref(vxl->vtep_ip,
|
|
|
|
vxl->mcast_grp);
|
|
|
|
zvni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zvni->mcast_grp = vxl->mcast_grp;
|
|
|
|
}
|
|
|
|
zvni->vxlan_if = ifp;
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (vlan_if) {
|
|
|
|
zvni->vrf_id = vlan_if->vrf_id;
|
|
|
|
zl3vni = zl3vni_from_vrf(
|
|
|
|
vlan_if->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_add_sort(
|
|
|
|
zl3vni->l2vnis, zvni);
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP if intf is up and mapped to
|
|
|
|
* bridge.
|
|
|
|
*/
|
|
|
|
if (if_is_operative(ifp) &&
|
|
|
|
zif->brslave_info.br_if)
|
|
|
|
zvni_send_add_to_client(zvni);
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if remote VTEP matches with prefix.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip));
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locate remote VTEP in VNI hash table.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vtep_t *zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
|
|
|
if (zvni_vtep_match(vtep_ip, zvtep))
|
|
|
|
break;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add remote VTEP to VNI hash table.
|
|
|
|
*/
|
2019-03-19 18:37:22 +01:00
|
|
|
static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip,
|
|
|
|
int flood_control)
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vtep_t *zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep->vtep_ip = *vtep_ip;
|
2019-03-19 18:37:22 +01:00
|
|
|
zvtep->flood_control = flood_control;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvni->vteps)
|
|
|
|
zvni->vteps->prev = zvtep;
|
|
|
|
zvtep->next = zvni->vteps;
|
|
|
|
zvni->vteps = zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove remote VTEP from VNI hash table.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvtep->next)
|
|
|
|
zvtep->next->prev = zvtep->prev;
|
|
|
|
if (zvtep->prev)
|
|
|
|
zvtep->prev->next = zvtep->next;
|
|
|
|
else
|
|
|
|
zvni->vteps = zvtep->next;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep->prev = zvtep->next = NULL;
|
|
|
|
XFREE(MTYPE_ZVNI_VTEP, zvtep);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all remote VTEPs for this VNI (upon VNI delete). Also
|
|
|
|
* uninstall from kernel if asked to.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vtep_t *zvtep, *zvtep_next;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return -1;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
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);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-03-19 18:37:22 +01:00
|
|
|
* Install remote VTEP into the kernel if the remote VTEP has asked
|
|
|
|
* for head-end-replication.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2019-03-19 18:37:22 +01:00
|
|
|
static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2019-03-19 18:37:22 +01:00
|
|
|
if (is_vxlan_flooding_head_end() &&
|
2019-08-26 21:44:54 +02:00
|
|
|
(zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) {
|
|
|
|
if (ZEBRA_DPLANE_REQUEST_FAILURE ==
|
|
|
|
dplane_vtep_add(zvni->vxlan_if,
|
|
|
|
&zvtep->vtep_ip, zvni->vni))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-10-05 00:42:57 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall remote VTEP from the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
|
|
|
|
zvni->vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-08-26 21:44:54 +02:00
|
|
|
if (ZEBRA_DPLANE_REQUEST_FAILURE ==
|
|
|
|
dplane_vtep_delete(zvni->vxlan_if, vtep_ip, zvni->vni))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2018-10-05 00:42:57 +02:00
|
|
|
/*
|
|
|
|
* Install or uninstall flood entries in the kernel corresponding to
|
|
|
|
* remote VTEPs. This is invoked upon change to BUM handling.
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_handle_flooding_remote_vteps(struct hash_bucket *bucket,
|
2018-10-05 00:42:57 +02:00
|
|
|
void *zvrf)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2018-10-05 00:42:57 +02:00
|
|
|
if (!zvni)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
|
|
|
if (is_vxlan_flooding_head_end())
|
2019-03-19 18:37:22 +01:00
|
|
|
zvni_vtep_install(zvni, zvtep);
|
2018-10-05 00:42:57 +02:00
|
|
|
else
|
|
|
|
zvni_vtep_uninstall(zvni, &zvtep->vtep_ip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Cleanup VNI/VTEP and update kernel
|
|
|
|
*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_cleanup_all(struct hash_bucket *bucket, void *arg)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
struct zebra_vrf *zvrf = (struct zebra_vrf *)arg;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* remove from l3-vni list */
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (zl3vni)
|
|
|
|
listnode_delete(zl3vni->l2vnis, zvni);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all neighbors and MACs, if any. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 1);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Delete the hash entry. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_del(zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-11-14 08:12:15 +01:00
|
|
|
/* cleanup L3VNI */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args)
|
2017-11-14 08:12:15 +01:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zl3vni = (zebra_l3vni_t *)bucket->data;
|
2017-11-14 08:12:15 +01:00
|
|
|
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
}
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe,
|
2018-05-17 14:10:41 +02:00
|
|
|
struct prefix *host)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
struct host_rb_entry lookup;
|
|
|
|
struct host_rb_entry *hle;
|
|
|
|
|
|
|
|
memset(&lookup, 0, sizeof(lookup));
|
|
|
|
memcpy(&lookup.p, host, sizeof(*host));
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
|
2018-05-17 01:24:22 +02:00
|
|
|
if (hle)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry));
|
|
|
|
memcpy(hle, &lookup, sizeof(lookup));
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_INSERT(host_rb_tree_entry, hrbe, hle);
|
2018-05-17 01:24:22 +02:00
|
|
|
}
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
struct host_rb_entry lookup;
|
|
|
|
struct host_rb_entry *hle;
|
|
|
|
|
|
|
|
memset(&lookup, 0, sizeof(lookup));
|
|
|
|
memcpy(&lookup.p, host, sizeof(*host));
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
|
2018-06-04 19:31:34 +02:00
|
|
|
if (hle) {
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_REMOVE(host_rb_tree_entry, hrbe, hle);
|
2018-06-04 19:31:34 +02:00
|
|
|
XFREE(MTYPE_HOST_PREFIX, hle);
|
|
|
|
}
|
2018-05-17 01:24:22 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Look up MAC hash entry.
|
|
|
|
*/
|
2017-10-13 10:13:48 +02:00
|
|
|
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
|
2017-10-08 03:49:27 +02:00
|
|
|
struct ethaddr *rmac)
|
|
|
|
{
|
|
|
|
zebra_mac_t tmp;
|
|
|
|
zebra_mac_t *pmac;
|
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
memcpy(&tmp.macaddr, rmac, ETH_ALEN);
|
|
|
|
pmac = hash_lookup(zl3vni->rmac_table, &tmp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return pmac;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Callback to allocate RMAC hash entry.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2017-10-13 10:13:48 +02:00
|
|
|
static void *zl3vni_rmac_alloc(void *p)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2017-10-08 03:49:27 +02:00
|
|
|
const zebra_mac_t *tmp_rmac = p;
|
|
|
|
zebra_mac_t *zrmac;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zrmac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
|
|
|
|
*zrmac = *tmp_rmac;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return ((void *)zrmac);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Add RMAC entry to l3-vni
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_mac_t tmp_rmac;
|
|
|
|
zebra_mac_t *zrmac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
memset(&tmp_rmac, 0, sizeof(zebra_mac_t));
|
|
|
|
memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN);
|
|
|
|
zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc);
|
|
|
|
assert(zrmac);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_INIT(host_rb_tree_entry, &zrmac->host_rb);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return zrmac;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Delete MAC entry.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_mac_t *tmp_rmac;
|
2018-05-17 01:24:22 +02:00
|
|
|
struct host_rb_entry *hle;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
while (!RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) {
|
|
|
|
hle = RB_ROOT(host_rb_tree_entry, &zrmac->host_rb);
|
2018-05-17 01:24:22 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_REMOVE(host_rb_tree_entry, &zrmac->host_rb, hle);
|
2018-05-17 01:24:22 +02:00
|
|
|
XFREE(MTYPE_HOST_PREFIX, hle);
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_MAC, tmp_rmac);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
|
|
|
/*
|
2019-07-30 17:54:07 +02:00
|
|
|
* Install remote RMAC into the forwarding plane.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct zebra_if *zif = NULL, *br_zif = NULL;
|
|
|
|
const struct zebra_l2info_vxlan *vxl = NULL;
|
|
|
|
const struct interface *br_ifp;
|
2019-07-30 17:54:07 +02:00
|
|
|
enum zebra_dplane_result res;
|
2019-09-05 18:58:58 +02:00
|
|
|
vlanid_t vid;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
|| !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_ifp = zif->brslave_info.br_if;
|
|
|
|
if (br_ifp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_zif = (const struct zebra_if *)br_ifp->info;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
|
|
|
|
vid = vxl->access_vlan;
|
|
|
|
else
|
|
|
|
vid = 0;
|
|
|
|
|
|
|
|
res = dplane_mac_add(zl3vni->vxlan_if, br_ifp, vid,
|
2019-07-30 17:54:07 +02:00
|
|
|
&zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0);
|
|
|
|
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
2019-07-30 17:54:07 +02:00
|
|
|
* Uninstall remote RMAC from the forwarding plane.
|
2017-10-08 03:49:27 +02:00
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct zebra_if *zif = NULL, *br_zif;
|
|
|
|
const struct zebra_l2info_vxlan *vxl = NULL;
|
|
|
|
const struct interface *br_ifp;
|
|
|
|
vlanid_t vid;
|
2019-07-30 17:54:07 +02:00
|
|
|
enum zebra_dplane_result res;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
|| !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!zl3vni->vxlan_if) {
|
2019-09-05 17:05:03 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if",
|
|
|
|
prefix_mac2str(&zrmac->macaddr,
|
|
|
|
buf, sizeof(buf)),
|
|
|
|
zl3vni->vni, zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_ifp = zif->brslave_info.br_if;
|
|
|
|
if (br_ifp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_zif = (const struct zebra_if *)br_ifp->info;
|
|
|
|
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
|
|
|
|
vid = vxl->access_vlan;
|
|
|
|
else
|
|
|
|
vid = 0;
|
|
|
|
|
|
|
|
res = dplane_mac_del(zl3vni->vxlan_if, br_ifp, vid,
|
2019-07-30 17:54:07 +02:00
|
|
|
&zrmac->macaddr, zrmac->fwd_info.r_vtep_ip);
|
|
|
|
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* handle rmac add */
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
|
2017-10-16 23:57:42 +02:00
|
|
|
struct ipaddr *vtep_ip,
|
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2019-10-28 21:47:05 +01:00
|
|
|
char buf2[PREFIX_STRLEN];
|
2017-10-13 10:13:48 +02:00
|
|
|
zebra_mac_t *zrmac = NULL;
|
|
|
|
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
|
|
|
|
if (!zrmac) {
|
|
|
|
|
2019-10-28 21:47:05 +01:00
|
|
|
/* Create the RMAC entry, or update its vtep, if necessary. */
|
2017-10-13 10:13:48 +02:00
|
|
|
zrmac = zl3vni_rmac_add(zl3vni, rmac);
|
|
|
|
if (!zrmac) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2019-10-28 21:47:05 +01:00
|
|
|
"Failed to add RMAC %s L3VNI %u Remote VTEP %s, prefix %s",
|
2018-03-06 20:02:52 +01:00
|
|
|
prefix_mac2str(rmac, buf, sizeof(buf)),
|
|
|
|
zl3vni->vni,
|
2019-10-28 21:47:05 +01:00
|
|
|
ipaddr2str(vtep_ip, buf1, sizeof(buf1)),
|
|
|
|
prefix2str(host_prefix, buf2, sizeof(buf2)));
|
2017-10-13 10:13:48 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info));
|
|
|
|
zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
|
|
|
|
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
/* Send RMAC for FPM processing */
|
|
|
|
hook_call(zebra_rmac_update, zrmac, zl3vni, false,
|
|
|
|
"new RMAC added");
|
|
|
|
|
2019-10-28 21:47:05 +01:00
|
|
|
/* install rmac in kernel */
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
} else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip,
|
|
|
|
&vtep_ip->ipaddr_v4)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"L3VNI %u Remote VTEP change(%s -> %s) for RMAC %s, prefix %s",
|
|
|
|
zl3vni->vni,
|
|
|
|
inet_ntoa(zrmac->fwd_info.r_vtep_ip),
|
|
|
|
ipaddr2str(vtep_ip, buf1, sizeof(buf1)),
|
|
|
|
prefix_mac2str(rmac, buf, sizeof(buf)),
|
|
|
|
prefix2str(host_prefix, buf2, sizeof(buf2)));
|
|
|
|
|
|
|
|
zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* install rmac in kernel */
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
}
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2018-05-17 14:10:41 +02:00
|
|
|
rb_find_or_add_host(&zrmac->host_rb, host_prefix);
|
2018-05-17 01:24:22 +02:00
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* handle rmac delete */
|
2017-11-29 08:40:30 +01:00
|
|
|
static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac,
|
2017-10-16 23:57:42 +02:00
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2018-05-17 14:10:41 +02:00
|
|
|
rb_delete_host(&zrmac->host_rb, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
if (RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) {
|
2017-10-13 10:13:48 +02:00
|
|
|
/* uninstall from kernel */
|
|
|
|
zl3vni_rmac_uninstall(zl3vni, zrmac);
|
|
|
|
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
/* Send RMAC for FPM processing */
|
|
|
|
hook_call(zebra_rmac_update, zrmac, zl3vni, true,
|
|
|
|
"RMAC deleted");
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* del the rmac entry */
|
|
|
|
zl3vni_rmac_del(zl3vni, zrmac);
|
|
|
|
}
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up nh hash entry on a l3-vni.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, struct ipaddr *ip)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_neigh_t tmp;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
|
|
|
|
n = hash_lookup(zl3vni->nh_table, &tmp);
|
|
|
|
|
|
|
|
return n;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate NH hash entry on L3-VNI.
|
|
|
|
*/
|
2017-10-13 10:13:48 +02:00
|
|
|
static void *zl3vni_nh_alloc(void *p)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
const zebra_neigh_t *tmp_n = p;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
|
|
|
|
n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
|
|
|
|
*n = *tmp_n;
|
|
|
|
|
|
|
|
return ((void *)n);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add neighbor entry.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
|
2017-10-08 03:49:27 +02:00
|
|
|
struct ethaddr *mac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t tmp_n;
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
|
|
|
|
memset(&tmp_n, 0, sizeof(zebra_neigh_t));
|
|
|
|
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
|
|
|
|
n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
|
|
|
|
assert(n);
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_INIT(host_rb_tree_entry, &n->host_rb);
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
memcpy(&n->emac, mac, ETH_ALEN);
|
2017-10-13 10:13:48 +02:00
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE_NH);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return n;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete neighbor entry.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_neigh_t *tmp_n;
|
2018-05-17 14:18:23 +02:00
|
|
|
struct host_rb_entry *hle;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
while (!RB_EMPTY(host_rb_tree_entry, &n->host_rb)) {
|
|
|
|
hle = RB_ROOT(host_rb_tree_entry, &n->host_rb);
|
2018-05-17 14:18:23 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_REMOVE(host_rb_tree_entry, &n->host_rb, hle);
|
2018-05-17 14:18:23 +02:00
|
|
|
XFREE(MTYPE_HOST_PREFIX, hle);
|
|
|
|
}
|
2017-10-17 02:41:04 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
tmp_n = hash_release(zl3vni->nh_table, n);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_NEIGH, tmp_n);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return 0;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Install remote nh as neigh into the kernel.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-07-07 06:46:46 +02:00
|
|
|
uint8_t flags;
|
|
|
|
int ret = 0;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!is_l3vni_oper_up(zl3vni))
|
|
|
|
return -1;
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
|
|
|
|
|| !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
2019-08-23 19:59:10 +02:00
|
|
|
|
|
|
|
flags = DPLANE_NTF_EXT_LEARNED;
|
2018-07-07 06:46:46 +02:00
|
|
|
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
|
2019-08-23 19:59:10 +02:00
|
|
|
flags |= DPLANE_NTF_ROUTER;
|
|
|
|
|
|
|
|
dplane_neigh_add(zl3vni->svi_if, &n->ip, &n->emac, flags);
|
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
return ret;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall remote nh from the kernel.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-03-06 20:02:52 +01:00
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
|
|
|
|
|| !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-12-02 08:31:22 +01:00
|
|
|
if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
|
|
|
|
return 0;
|
|
|
|
|
2019-08-23 19:59:10 +02:00
|
|
|
dplane_neigh_delete(zl3vni->svi_if, &n->ip);
|
|
|
|
|
|
|
|
return 0;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add remote vtep as a neigh entry */
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
|
2017-10-16 23:57:42 +02:00
|
|
|
struct ethaddr *rmac,
|
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2019-10-28 21:47:05 +01:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
char buf3[PREFIX_STRLEN];
|
2017-10-13 10:13:48 +02:00
|
|
|
zebra_neigh_t *nh = NULL;
|
|
|
|
|
2019-10-28 21:47:05 +01:00
|
|
|
/* Create the next hop entry, or update its mac, if necessary. */
|
2017-10-13 10:13:48 +02:00
|
|
|
nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
|
|
|
|
if (!nh) {
|
|
|
|
nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac);
|
|
|
|
if (!nh) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2019-10-28 21:47:05 +01:00
|
|
|
"Failed to add NH %s as Neigh (RMAC %s L3-VNI %u prefix %s)",
|
|
|
|
ipaddr2str(vtep_ip, buf1, sizeof(buf2)),
|
2018-03-06 20:02:52 +01:00
|
|
|
prefix_mac2str(rmac, buf, sizeof(buf)),
|
2019-10-28 21:47:05 +01:00
|
|
|
zl3vni->vni,
|
|
|
|
prefix2str(host_prefix, buf2, sizeof(buf2)));
|
2017-10-13 10:13:48 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* install the nh neigh in kernel */
|
|
|
|
zl3vni_nh_install(zl3vni, nh);
|
2019-10-28 21:47:05 +01:00
|
|
|
} else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("L3VNI %u RMAC change(%s --> %s) for nexthop %s, prefix %s",
|
|
|
|
zl3vni->vni,
|
|
|
|
prefix_mac2str(&nh->emac, buf, sizeof(buf)),
|
|
|
|
prefix_mac2str(rmac, buf1, sizeof(buf1)),
|
|
|
|
ipaddr2str(vtep_ip, buf2, sizeof(buf2)),
|
|
|
|
prefix2str(host_prefix, buf3, sizeof(buf3)));
|
|
|
|
|
|
|
|
memcpy(&nh->emac, rmac, ETH_ALEN);
|
|
|
|
/* install (update) the nh neigh in kernel */
|
|
|
|
zl3vni_nh_install(zl3vni, nh);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2018-05-17 14:18:23 +02:00
|
|
|
rb_find_or_add_host(&nh->host_rb, host_prefix);
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle nh neigh delete */
|
2017-11-29 08:40:30 +01:00
|
|
|
static void zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *nh,
|
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2018-05-17 14:18:23 +02:00
|
|
|
rb_delete_host(&nh->host_rb, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
if (RB_EMPTY(host_rb_tree_entry, &nh->host_rb)) {
|
2017-10-13 10:13:48 +02:00
|
|
|
/* uninstall from kernel */
|
|
|
|
zl3vni_nh_uninstall(zl3vni, nh);
|
|
|
|
|
|
|
|
/* delete the nh entry */
|
|
|
|
zl3vni_nh_del(zl3vni, nh);
|
|
|
|
}
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-11-09 18:13:28 +01:00
|
|
|
/* handle neigh update from kernel - the only thing of interest is to
|
|
|
|
* readd stale entries.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_local_nh_add_update(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t state)
|
2017-11-09 18:13:28 +01:00
|
|
|
{
|
2017-12-14 00:04:44 +01:00
|
|
|
#ifdef GNU_LINUX
|
2017-11-09 18:13:28 +01:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
|
|
|
|
n = zl3vni_nh_lookup(zl3vni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* all next hop neigh are remote and installed by frr.
|
|
|
|
* If the kernel has aged this entry, re-install.
|
|
|
|
*/
|
|
|
|
if (state & NUD_STALE)
|
|
|
|
zl3vni_nh_install(zl3vni, n);
|
2017-12-14 00:04:44 +01:00
|
|
|
#endif
|
2017-11-09 18:13:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-22 10:16:54 +02:00
|
|
|
/* handle neigh delete from kernel */
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zl3vni_local_nh_del(zebra_l3vni_t *zl3vni, struct ipaddr *ip)
|
2017-10-22 10:16:54 +02:00
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
|
|
|
|
n = zl3vni_nh_lookup(zl3vni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* all next hop neigh are remote and installed by frr.
|
|
|
|
* If we get an age out notification for these neigh entries, we have to
|
2017-12-27 20:47:10 +01:00
|
|
|
* install it back
|
|
|
|
*/
|
2017-10-22 10:16:54 +02:00
|
|
|
zl3vni_nh_install(zl3vni, n);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Hash function for L3 VNI.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int l3vni_hash_keymake(const void *p)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
const zebra_l3vni_t *zl3vni = p;
|
|
|
|
|
|
|
|
return jhash_1word(zl3vni->vni, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare 2 L3 VNI hash entries.
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool l3vni_hash_cmp(const void *p1, const void *p2)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
const zebra_l3vni_t *zl3vni1 = p1;
|
|
|
|
const zebra_l3vni_t *zl3vni2 = p2;
|
|
|
|
|
|
|
|
return (zl3vni1->vni == zl3vni2->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate L3 VNI hash entry.
|
|
|
|
*/
|
|
|
|
static void *zl3vni_alloc(void *p)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
const zebra_l3vni_t *tmp_l3vni = p;
|
|
|
|
|
|
|
|
zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(zebra_l3vni_t));
|
|
|
|
zl3vni->vni = tmp_l3vni->vni;
|
|
|
|
return ((void *)zl3vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up L3 VNI hash entry.
|
|
|
|
*/
|
|
|
|
static zebra_l3vni_t *zl3vni_lookup(vni_t vni)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t tmp_l3vni;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
memset(&tmp_l3vni, 0, sizeof(zebra_l3vni_t));
|
|
|
|
tmp_l3vni.vni = vni;
|
2018-08-27 16:43:37 +02:00
|
|
|
zl3vni = hash_lookup(zrouter.l3vni_table, &tmp_l3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return zl3vni;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add L3 VNI hash entry.
|
|
|
|
*/
|
|
|
|
static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t tmp_zl3vni;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
memset(&tmp_zl3vni, 0, sizeof(zebra_l3vni_t));
|
|
|
|
tmp_zl3vni.vni = vni;
|
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
zl3vni = hash_get(zrouter.l3vni_table, &tmp_zl3vni, zl3vni_alloc);
|
2017-10-08 03:49:27 +02:00
|
|
|
assert(zl3vni);
|
|
|
|
|
|
|
|
zl3vni->vrf_id = vrf_id;
|
|
|
|
zl3vni->svi_if = NULL;
|
|
|
|
zl3vni->vxlan_if = NULL;
|
|
|
|
zl3vni->l2vnis = list_new();
|
2018-10-17 21:31:09 +02:00
|
|
|
zl3vni->l2vnis->cmp = vni_list_cmp;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Create hash table for remote RMAC */
|
2018-03-06 20:02:52 +01:00
|
|
|
zl3vni->rmac_table = hash_create(mac_hash_keymake, mac_cmp,
|
|
|
|
"Zebra L3-VNI RMAC-Table");
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Create hash table for neighbors */
|
|
|
|
zl3vni->nh_table = hash_create(neigh_hash_keymake, neigh_cmp,
|
2018-03-06 20:02:52 +01:00
|
|
|
"Zebra L3-VNI next-hop table");
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return zl3vni;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete L3 VNI hash entry.
|
|
|
|
*/
|
|
|
|
static int zl3vni_del(zebra_l3vni_t *zl3vni)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t *tmp_zl3vni;
|
|
|
|
|
|
|
|
/* free the list of l2vnis */
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&zl3vni->l2vnis);
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->l2vnis = NULL;
|
|
|
|
|
|
|
|
/* Free the rmac table */
|
|
|
|
hash_free(zl3vni->rmac_table);
|
|
|
|
zl3vni->rmac_table = NULL;
|
|
|
|
|
|
|
|
/* Free the nh table */
|
|
|
|
hash_free(zl3vni->nh_table);
|
|
|
|
zl3vni->nh_table = NULL;
|
|
|
|
|
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
2018-08-27 16:43:37 +02:00
|
|
|
tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct zebra_ns *zns = NULL;
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
|
|
|
|
/* loop through all vxlan-interface */
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
|
|
|
|
|
|
|
ifp = (struct interface *)rn->info;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-10-31 00:58:15 +01:00
|
|
|
if (vxl->vni == zl3vni->vni) {
|
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
2017-10-08 03:49:27 +02:00
|
|
|
return ifp;
|
2017-10-31 00:58:15 +01:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-03-06 20:02:52 +01:00
|
|
|
struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */
|
|
|
|
|
2018-02-05 22:51:45 +01:00
|
|
|
if (!zl3vni)
|
|
|
|
return NULL;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!zl3vni->vxlan_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
|
|
|
return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
|
|
|
}
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni)
|
|
|
|
{
|
|
|
|
struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
|
|
|
|
|
|
|
|
if (!zl3vni)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!zl3vni->vxlan_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return zvni_map_to_macvlan(zif->brslave_info.br_if, zl3vni->svi_if);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-17 03:38:03 +02:00
|
|
|
zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
|
|
|
|
|
|
|
zvrf = zebra_vrf_lookup_by_id(vrf_id);
|
|
|
|
if (!zvrf)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return zl3vni_lookup(zvrf->l3vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map SVI and associated bridge to a VNI. This is invoked upon getting
|
|
|
|
* neighbor notifications, to see if they are of interest.
|
|
|
|
*/
|
|
|
|
static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp,
|
|
|
|
struct interface *br_if)
|
|
|
|
{
|
|
|
|
int found = 0;
|
|
|
|
vlanid_t vid = 0;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t bridge_vlan_aware = 0;
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
struct zebra_ns *zns = NULL;
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct interface *tmp_if = NULL;
|
|
|
|
struct zebra_l2info_bridge *br = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
|
|
|
|
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Make sure the linked interface is a bridge. */
|
|
|
|
if (!IS_ZEBRA_IF_BRIDGE(br_if))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
br = &zif->l2info.br;
|
|
|
|
bridge_vlan_aware = br->vlan_aware;
|
|
|
|
if (bridge_vlan_aware) {
|
|
|
|
struct zebra_l2info_vlan *vl;
|
|
|
|
|
|
|
|
if (!IS_ZEBRA_IF_VLAN(ifp))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vl = &zif->l2info.vl;
|
|
|
|
vid = vl->vid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
|
|
|
/* TODO: Optimize with a hash. */
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
|
|
|
if (!tmp_if)
|
|
|
|
continue;
|
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
if (!if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
|
|
|
if (zif->brslave_info.br_if != br_if)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(vxl->vni);
|
|
|
|
return zl3vni;
|
|
|
|
}
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
static inline void zl3vni_get_vrr_rmac(zebra_l3vni_t *zl3vni,
|
|
|
|
struct ethaddr *rmac)
|
|
|
|
{
|
|
|
|
if (!zl3vni)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!is_l3vni_oper_up(zl3vni))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (zl3vni->mac_vlan_if && if_is_operative(zl3vni->mac_vlan_if))
|
|
|
|
memcpy(rmac->octet, zl3vni->mac_vlan_if->hw_addr, ETH_ALEN);
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP about l3-vni.
|
|
|
|
*/
|
|
|
|
static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni)
|
|
|
|
{
|
|
|
|
struct stream *s = NULL;
|
|
|
|
struct zserv *client = NULL;
|
2019-08-02 08:33:24 +02:00
|
|
|
struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} };
|
|
|
|
struct zebra_vrf *zvrf;
|
2017-10-08 03:49:27 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2019-08-02 08:33:24 +02:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
bool is_anycast_mac = true;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-10-08 03:49:27 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
zvrf = zebra_vrf_lookup_by_id(zl3vni->vrf_id);
|
|
|
|
assert(zvrf);
|
|
|
|
|
|
|
|
/* get the svi and vrr rmac values */
|
|
|
|
memset(&svi_rmac, 0, sizeof(struct ethaddr));
|
|
|
|
zl3vni_get_svi_rmac(zl3vni, &svi_rmac);
|
|
|
|
zl3vni_get_vrr_rmac(zl3vni, &vrr_rmac);
|
|
|
|
|
|
|
|
/* In absence of vrr mac use svi mac as anycast MAC value */
|
|
|
|
if (is_zero_mac(&vrr_rmac)) {
|
|
|
|
memcpy(&vrr_rmac, &svi_rmac, ETH_ALEN);
|
|
|
|
is_anycast_mac = false;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
/* The message is used for both vni add and/or update like
|
|
|
|
* vrr mac is added for l3vni SVI.
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
stream_putl(s, zl3vni->vni);
|
2019-08-02 08:33:24 +02:00
|
|
|
stream_put(s, &svi_rmac, sizeof(struct ethaddr));
|
2017-10-31 00:58:15 +01:00
|
|
|
stream_put_in_addr(s, &zl3vni->local_vtep_ip);
|
2018-02-06 23:28:22 +01:00
|
|
|
stream_put(s, &zl3vni->filter, sizeof(int));
|
2019-02-27 12:52:34 +01:00
|
|
|
stream_putl(s, zl3vni->svi_if->ifindex);
|
2019-08-02 08:33:24 +02:00
|
|
|
stream_put(s, &vrr_rmac, sizeof(struct ethaddr));
|
|
|
|
stream_putl(s, is_anycast_mac);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-02-06 23:28:22 +01:00
|
|
|
zlog_debug(
|
2019-08-02 08:33:24 +02:00
|
|
|
"Send L3_VNI_ADD %u VRF %s RMAC %s VRR %s local-ip %s filter %s to %s",
|
2018-03-06 20:02:52 +01:00
|
|
|
zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
|
2019-08-02 08:33:24 +02:00
|
|
|
prefix_mac2str(&svi_rmac, buf, sizeof(buf)),
|
|
|
|
prefix_mac2str(&vrr_rmac, buf1, sizeof(buf1)),
|
2018-03-06 20:02:52 +01:00
|
|
|
inet_ntoa(zl3vni->local_vtep_ip),
|
|
|
|
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
|
|
|
|
? "prefix-routes-only"
|
|
|
|
: "none",
|
|
|
|
zebra_route_string(client->proto));
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
client->l3vniadd_cnt++;
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local l3-VNI deletion.
|
|
|
|
*/
|
|
|
|
static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni)
|
|
|
|
{
|
|
|
|
struct stream *s = NULL;
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-10-08 03:49:27 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
stream_putl(s, zl3vni->vni);
|
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", zl3vni->vni,
|
2017-10-08 03:49:27 +02:00
|
|
|
vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
client->l3vnidel_cnt++;
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni)
|
|
|
|
{
|
2018-02-05 22:51:45 +01:00
|
|
|
if (!zl3vni)
|
|
|
|
return;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* send l3vni add to BGP */
|
|
|
|
zl3vni_send_add_to_client(zl3vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni)
|
|
|
|
{
|
2018-02-05 22:51:45 +01:00
|
|
|
if (!zl3vni)
|
|
|
|
return;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* send l3-vni del to BGP*/
|
|
|
|
zl3vni_send_del_to_client(zl3vni);
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2019-02-19 16:46:52 +01:00
|
|
|
zebra_vni_t *zvni = (zebra_vni_t *)bucket->data;
|
2018-03-06 20:02:52 +01:00
|
|
|
zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)ctxt;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (zvni->vrf_id == zl3vni_vrf_id(zl3vni))
|
|
|
|
listnode_add_sort(zl3vni->l2vnis, zvni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* handle transition of vni from l2 to l3 and vice versa
|
|
|
|
*/
|
2018-03-06 20:02:52 +01:00
|
|
|
static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
|
|
|
|
int add)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
|
|
|
|
/* There is a possibility that VNI notification was already received
|
|
|
|
* from kernel and we programmed it as L2-VNI
|
|
|
|
* In such a case we need to delete this L2-VNI first, so
|
|
|
|
* that it can be reprogrammed as L3-VNI in the system. It is also
|
|
|
|
* possible that the vrf-vni mapping is removed from FRR while the vxlan
|
|
|
|
* interface is still present in kernel. In this case to keep it
|
2017-12-27 20:47:10 +01:00
|
|
|
* symmetric, we will delete the l3-vni and reprogram it as l2-vni
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
if (add) {
|
|
|
|
/* Locate hash entry */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Del L2-VNI %u - transition to L3-VNI", vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Delete VNI from BGP. */
|
|
|
|
zvni_send_del_to_client(zvni->vni);
|
|
|
|
|
|
|
|
/* Free up all neighbors and MAC, if any. */
|
|
|
|
zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
|
|
|
|
|
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 0);
|
|
|
|
|
|
|
|
/* Delete the hash entry. */
|
|
|
|
if (zvni_del(zvni)) {
|
2018-09-13 21:21:05 +02:00
|
|
|
flog_err(EC_ZEBRA_VNI_DEL_FAILED,
|
2018-09-13 21:38:57 +02:00
|
|
|
"Failed to del VNI hash %p, VNI %u", zvni,
|
|
|
|
zvni->vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* TODO_MITESH: This needs to be thought through. We don't have
|
|
|
|
* enough information at this point to reprogram the vni as
|
|
|
|
* l2-vni. One way is to store the required info in l3-vni and
|
2017-12-27 20:47:10 +01:00
|
|
|
* used it solely for this purpose
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-18 10:46:40 +02:00
|
|
|
/* delete and uninstall rmac hash entry */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx)
|
2017-10-18 10:46:40 +02:00
|
|
|
{
|
|
|
|
zebra_mac_t *zrmac = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zrmac = (zebra_mac_t *)bucket->data;
|
2017-10-18 10:46:40 +02:00
|
|
|
zl3vni = (zebra_l3vni_t *)ctx;
|
|
|
|
zl3vni_rmac_uninstall(zl3vni, zrmac);
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
|
|
|
|
/* Send RMAC for FPM processing */
|
|
|
|
hook_call(zebra_rmac_update, zrmac, zl3vni, true, "RMAC deleted");
|
|
|
|
|
2017-10-18 10:46:40 +02:00
|
|
|
zl3vni_rmac_del(zl3vni, zrmac);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete and uninstall nh hash entry */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx)
|
2017-10-18 10:46:40 +02:00
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
n = (zebra_neigh_t *)bucket->data;
|
2017-10-18 10:46:40 +02:00
|
|
|
zl3vni = (zebra_l3vni_t *)ctx;
|
|
|
|
zl3vni_nh_uninstall(zl3vni, n);
|
|
|
|
zl3vni_nh_del(zl3vni, n);
|
|
|
|
}
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
|
|
|
|
uint16_t cmd)
|
2017-11-20 06:47:04 +01:00
|
|
|
{
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
struct stream *s = NULL;
|
|
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-11-20 06:47:04 +01:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2017-12-07 00:19:11 +01:00
|
|
|
zclient_create_header(s, cmd, vrf_id);
|
2017-11-20 06:47:04 +01:00
|
|
|
stream_put(s, p, sizeof(struct prefix));
|
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Send ip prefix %s %s on vrf %s",
|
2017-11-20 06:47:04 +01:00
|
|
|
prefix2str(p, buf, sizeof(buf)),
|
|
|
|
(cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
|
|
|
|
vrf_id_to_name(vrf_id));
|
|
|
|
|
|
|
|
if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD)
|
|
|
|
client->prefixadd_cnt++;
|
|
|
|
else
|
|
|
|
client->prefixdel_cnt++;
|
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-11-20 06:47:04 +01:00
|
|
|
}
|
|
|
|
|
2017-11-29 11:25:35 +01:00
|
|
|
/* re-add remote rmac if needed */
|
|
|
|
static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
|
2018-03-06 20:02:52 +01:00
|
|
|
struct ethaddr *rmac)
|
2017-11-29 11:25:35 +01:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
zebra_mac_t *zrmac = NULL;
|
|
|
|
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
|
|
|
|
if (!zrmac)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Del remote RMAC %s L3VNI %u - readd",
|
2018-03-06 20:02:52 +01:00
|
|
|
prefix_mac2str(rmac, buf, sizeof(buf)), zl3vni->vni);
|
2017-11-29 11:25:35 +01:00
|
|
|
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Process a remote MACIP add from BGP. */
|
|
|
|
static void process_remote_macip_add(vni_t vni,
|
|
|
|
struct ethaddr *macaddr,
|
2018-08-20 23:31:30 +02:00
|
|
|
uint16_t ipa_len,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
struct ipaddr *ipaddr,
|
2018-08-20 23:31:30 +02:00
|
|
|
uint8_t flags,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint32_t seq,
|
|
|
|
struct in_addr vtep_ip)
|
2018-02-06 23:28:22 +01:00
|
|
|
{
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
2018-11-02 16:30:41 +01:00
|
|
|
zebra_mac_t *mac = NULL, *old_mac = NULL;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
int update_mac = 0, update_neigh = 0;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
2018-11-02 16:30:41 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint32_t tmp_seq;
|
2018-09-10 19:13:20 +02:00
|
|
|
bool sticky;
|
|
|
|
bool remote_gw;
|
|
|
|
bool is_router;
|
2018-11-02 16:30:41 +01:00
|
|
|
bool do_dad = false;
|
|
|
|
bool is_dup_detect = false;
|
2018-02-06 23:28:22 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni);
|
|
|
|
return;
|
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (ifp)
|
|
|
|
zif = ifp->info;
|
|
|
|
if (!ifp ||
|
|
|
|
!if_is_operative(ifp) ||
|
|
|
|
!zif ||
|
|
|
|
!zif->brslave_info.br_if) {
|
|
|
|
zlog_warn("Ignoring remote MACIP ADD VNI %u, invalid interface state or info",
|
|
|
|
vni);
|
2017-10-13 10:13:48 +02:00
|
|
|
return;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* The remote VTEP specified should normally exist, but it is
|
|
|
|
* possible that when peering comes up, peer may advertise MACIP
|
|
|
|
* routes before advertising type-3 routes.
|
2018-04-09 06:04:11 +02:00
|
|
|
*/
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
zvtep = zvni_vtep_find(zvni, &vtep_ip);
|
|
|
|
if (!zvtep) {
|
2019-03-19 18:37:22 +01:00
|
|
|
zvtep = zvni_vtep_add(zvni, &vtep_ip, VXLAN_FLOOD_DISABLED);
|
|
|
|
if (!zvtep) {
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_VTEP_ADD_FAILED,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
"Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
|
|
|
|
vni, zvni);
|
|
|
|
return;
|
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2019-03-19 18:37:22 +01:00
|
|
|
zvni_vtep_install(zvni, zvtep);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
2018-04-09 06:04:11 +02:00
|
|
|
|
2018-09-10 19:13:20 +02:00
|
|
|
sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
|
|
|
|
remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
|
|
|
is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Ignore if the mac is already present as a gateway mac */
|
|
|
|
if (mac &&
|
|
|
|
CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
|
|
|
|
CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
|
|
|
|
vni,
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
|
2017-10-13 10:13:48 +02:00
|
|
|
return;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
2018-11-02 16:30:41 +01:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* check if the remote MAC is unknown or has a change.
|
|
|
|
* If so, that needs to be updated first. Note that client could
|
|
|
|
* install MAC and MACIP separately or just install the latter.
|
|
|
|
*/
|
|
|
|
if (!mac
|
|
|
|
|| !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|
2018-09-10 19:13:20 +02:00
|
|
|
|| sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
|
|
|
|
|| remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|| !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
|
|
|
|
|| seq != mac->rem_seq)
|
|
|
|
update_mac = 1;
|
|
|
|
|
|
|
|
if (update_mac) {
|
|
|
|
if (!mac) {
|
|
|
|
mac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!mac) {
|
|
|
|
zlog_warn(
|
|
|
|
"Failed to add MAC %s VNI %u Remote VTEP %s",
|
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
vni, inet_ntoa(vtep_ip));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is this MAC created for a MACIP? */
|
|
|
|
if (ipa_len)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
} else {
|
|
|
|
/* When host moves but changes its (MAC,IP)
|
|
|
|
* binding, BGP may install a MACIP entry that
|
|
|
|
* corresponds to "older" location of the host
|
|
|
|
* in transient situations (because {IP1,M1}
|
|
|
|
* is a different route from {IP1,M2}). Check
|
|
|
|
* the sequence number and ignore this update
|
|
|
|
* if appropriate.
|
|
|
|
*/
|
2019-07-04 02:03:15 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
tmp_seq = mac->loc_seq;
|
2019-07-04 02:03:15 +02:00
|
|
|
else
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
tmp_seq = mac->rem_seq;
|
2019-07-04 02:03:15 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (seq < tmp_seq) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-07-04 02:03:15 +02:00
|
|
|
zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x",
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
vni,
|
|
|
|
prefix_mac2str(macaddr,
|
|
|
|
buf, sizeof(buf)),
|
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(ipaddr,
|
|
|
|
buf1, sizeof(buf1)) : "",
|
2019-07-04 02:03:15 +02:00
|
|
|
tmp_seq, mac->flags);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Check MAC's curent state is local (this is the case
|
|
|
|
* where MAC has moved from L->R) and check previous
|
|
|
|
* detection started via local learning.
|
|
|
|
* RFC-7432: A PE/VTEP that detects a MAC mobility
|
|
|
|
* event via local learning starts an M-second timer.
|
|
|
|
*
|
2019-01-24 21:19:53 +01:00
|
|
|
* VTEP-IP or seq. change alone is not considered
|
2018-11-02 16:30:41 +01:00
|
|
|
* for dup. detection.
|
2019-01-24 21:19:53 +01:00
|
|
|
*
|
|
|
|
* MAC is already marked duplicate set dad, then
|
|
|
|
* is_dup_detect will be set to not install the entry.
|
2018-11-02 16:30:41 +01:00
|
|
|
*/
|
2019-01-24 21:19:53 +01:00
|
|
|
if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
|
|
|
|
mac->dad_count) ||
|
|
|
|
CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
2018-11-02 16:30:41 +01:00
|
|
|
do_dad = true;
|
|
|
|
|
2018-10-11 17:48:42 +02:00
|
|
|
/* Remove local MAC from BGP. */
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
zvni_mac_send_del_to_client(zvni->vni, macaddr);
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Set "auto" and "remote" forwarding info. */
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
mac->fwd_info.r_vtep_ip = vtep_ip;
|
|
|
|
|
|
|
|
if (sticky)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
|
|
|
|
if (remote_gw)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
|
|
|
|
|
2018-11-18 01:03:19 +01:00
|
|
|
zebra_vxlan_dup_addr_detect_for_mac(zvrf, mac,
|
|
|
|
mac->fwd_info.r_vtep_ip,
|
|
|
|
do_dad, &is_dup_detect,
|
|
|
|
false);
|
2018-11-02 16:30:41 +01:00
|
|
|
|
2018-12-17 23:36:27 +01:00
|
|
|
if (!is_dup_detect) {
|
|
|
|
zvni_process_neigh_on_remote_mac_add(zvni, mac);
|
|
|
|
/* Install the entry. */
|
2018-11-02 16:30:41 +01:00
|
|
|
zvni_mac_install(zvni, mac);
|
2018-12-17 23:36:27 +01:00
|
|
|
}
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update seq number. */
|
|
|
|
mac->rem_seq = seq;
|
|
|
|
|
|
|
|
/* If there is no IP, return after clearing AUTO flag of MAC. */
|
|
|
|
if (!ipa_len) {
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Reset flag */
|
|
|
|
do_dad = false;
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Check if the remote neighbor itself is unknown or has a
|
|
|
|
* change. If so, create or update and then install the entry.
|
|
|
|
*/
|
|
|
|
n = zvni_neigh_lookup(zvni, ipaddr);
|
|
|
|
if (!n
|
|
|
|
|| !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
|
2018-09-10 19:13:20 +02:00
|
|
|
|| is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|| (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0)
|
|
|
|
|| !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)
|
|
|
|
|| seq != n->rem_seq)
|
|
|
|
update_neigh = 1;
|
|
|
|
|
|
|
|
if (update_neigh) {
|
|
|
|
if (!n) {
|
|
|
|
n = zvni_neigh_add(zvni, ipaddr, macaddr);
|
|
|
|
if (!n) {
|
|
|
|
zlog_warn(
|
|
|
|
"Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
|
|
|
|
ipaddr2str(ipaddr, buf1,
|
|
|
|
sizeof(buf1)),
|
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
vni, inet_ntoa(vtep_ip));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
const char *n_type;
|
|
|
|
|
|
|
|
/* When host moves but changes its (MAC,IP)
|
|
|
|
* binding, BGP may install a MACIP entry that
|
|
|
|
* corresponds to "older" location of the host
|
|
|
|
* in transient situations (because {IP1,M1}
|
|
|
|
* is a different route from {IP1,M2}). Check
|
|
|
|
* the sequence number and ignore this update
|
|
|
|
* if appropriate.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
tmp_seq = n->loc_seq;
|
|
|
|
n_type = "local";
|
|
|
|
} else {
|
|
|
|
tmp_seq = n->rem_seq;
|
|
|
|
n_type = "remote";
|
|
|
|
}
|
|
|
|
if (seq < tmp_seq) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u",
|
|
|
|
vni,
|
|
|
|
prefix_mac2str(macaddr,
|
|
|
|
buf, sizeof(buf)),
|
2018-09-26 17:50:33 +02:00
|
|
|
" IP ",
|
|
|
|
ipaddr2str(ipaddr, buf1, sizeof(buf1)),
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
n_type,
|
|
|
|
tmp_seq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) {
|
|
|
|
/* MAC change, send a delete for old
|
|
|
|
* neigh if learnt locally.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) &&
|
|
|
|
IS_ZEBRA_NEIGH_ACTIVE(n))
|
|
|
|
zvni_neigh_send_del_to_client(
|
|
|
|
zvni->vni, &n->ip,
|
2019-01-15 00:19:48 +01:00
|
|
|
&n->emac, 0, n->state);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
|
|
|
/* update neigh list for macs */
|
|
|
|
old_mac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (old_mac) {
|
|
|
|
listnode_delete(old_mac->neigh_list, n);
|
2018-08-29 02:22:04 +02:00
|
|
|
zvni_deref_ip2mac(zvni, old_mac);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
|
|
|
listnode_add_sort(mac->neigh_list, n);
|
|
|
|
memcpy(&n->emac, macaddr, ETH_ALEN);
|
2018-11-02 16:30:41 +01:00
|
|
|
|
|
|
|
/* Check Neigh's curent state is local
|
|
|
|
* (this is the case where neigh/host has moved
|
|
|
|
* from L->R) and check previous detction
|
|
|
|
* started via local learning.
|
|
|
|
*
|
|
|
|
* RFC-7432: A PE/VTEP that detects a MAC
|
|
|
|
* mobilit event via local learning starts
|
|
|
|
* an M-second timer.
|
|
|
|
* VTEP-IP or seq. change along is not
|
|
|
|
* considered for dup. detection.
|
|
|
|
*
|
|
|
|
* Mobilty event scenario-B IP-MAC binding
|
|
|
|
* changed.
|
|
|
|
*/
|
|
|
|
if ((!CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
|
|
|
|
&& n->dad_count)
|
|
|
|
do_dad = true;
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "remote" forwarding info. */
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
n->r_vtep_ip = vtep_ip;
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
|
|
|
|
|
|
|
/* Set router flag (R-bit) to this Neighbor entry */
|
|
|
|
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
2018-08-28 00:13:30 +02:00
|
|
|
else
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
2018-11-02 16:30:41 +01:00
|
|
|
/* Check old or new MAC detected as duplicate,
|
|
|
|
* inherit duplicate flag to this neigh.
|
|
|
|
*/
|
|
|
|
if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_mac,
|
|
|
|
mac, n)) {
|
|
|
|
flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
|
|
|
"VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC",
|
|
|
|
zvni->vni,
|
|
|
|
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&n->ip, buf1, sizeof(buf1)));
|
|
|
|
}
|
|
|
|
|
2018-11-17 05:38:39 +01:00
|
|
|
/* Check duplicate address detection for IP */
|
|
|
|
zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n,
|
|
|
|
n->r_vtep_ip,
|
|
|
|
do_dad,
|
|
|
|
&is_dup_detect,
|
|
|
|
false);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Install the entry. */
|
2018-11-02 16:30:41 +01:00
|
|
|
if (!is_dup_detect)
|
|
|
|
zvni_neigh_install(zvni, n);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
|
|
|
|
zebra: probe local inactive neigh
In extended-mobility case ({IP1, MAC} binding),
when a MAC moves from local to remote, binding
changes to {IP2, MAC}, local neigh (IP1) marked
as inactive in frr.
The evpn draft recommends to probe the entry once
local binding changes from local to remote.
Once the probe is set for the local neigh entry,
kernel will attempt refresh the entry via sending
unicast address resolution message, if host does not
reply, it will mark FAILED state.
For FAILED entry, kernel triggers delete neigh
request, which result in frr to remove inactive entry.
In absence of probing and aging out entry,
if MAC moves back to local with {IP3, MAC},
frr will mark both IP1 and IP3 as active and sends
type-2 update for both.
The IP1 may not be active host and still frr advertises
the route.
Ticket:CM-22864
Testing Done:
Validate the MAC mobilty in extended mobility scenario,
where local inactive entry gets removed once MAC moves
to remote state.
Once probe is set to the local entry, kernel triggers
reachability of the neigh/arp entry, since MAC moved remote,
ARP request goes to remote VTEP where host is not residing,
thus local neigh entry goes to failed state.
Frr receives neighbor delete faster and removes the entry.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-01-29 00:37:03 +01:00
|
|
|
zvni_probe_neigh_on_mac_add(zvni, mac);
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Update seq number. */
|
|
|
|
n->rem_seq = seq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process a remote MACIP delete from BGP. */
|
|
|
|
static void process_remote_macip_del(vni_t vni,
|
|
|
|
struct ethaddr *macaddr,
|
2018-08-20 23:31:30 +02:00
|
|
|
uint16_t ipa_len,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
struct ipaddr *ipaddr,
|
|
|
|
struct in_addr vtep_ip)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac = NULL;
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
2018-12-11 06:33:16 +01:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct zebra_vrf *zvrf;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (ifp)
|
|
|
|
zif = ifp->info;
|
|
|
|
if (!ifp ||
|
|
|
|
!if_is_operative(ifp) ||
|
|
|
|
!zif ||
|
|
|
|
!zif->brslave_info.br_if) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Ignoring remote MACIP DEL VNI %u, invalid interface state or info",
|
|
|
|
vni);
|
|
|
|
return;
|
|
|
|
}
|
2018-12-11 06:33:16 +01:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
vxl = &zif->l2info.vxl;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
|
|
|
/* The remote VTEP specified is normally expected to exist, but
|
|
|
|
* it is possible that the peer may delete the VTEP before deleting
|
|
|
|
* any MACs referring to the VTEP, in which case the handler (see
|
|
|
|
* remote_vtep_del) would have already deleted the MACs.
|
|
|
|
*/
|
|
|
|
if (!zvni_vtep_find(zvni, &vtep_ip))
|
|
|
|
return;
|
|
|
|
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (ipa_len)
|
|
|
|
n = zvni_neigh_lookup(zvni, ipaddr);
|
|
|
|
|
|
|
|
if (n && !mac) {
|
|
|
|
zlog_warn("Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the remote mac or neighbor doesn't exist there is nothing
|
|
|
|
* more to do. Otherwise, uninstall the entry and then remove it.
|
|
|
|
*/
|
|
|
|
if (!mac && !n)
|
|
|
|
return;
|
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
2018-12-11 06:33:16 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Ignore the delete if this mac is a gateway mac-ip */
|
2018-12-11 06:33:16 +01:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
&& CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
|
|
|
|
zlog_warn(
|
|
|
|
"Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
|
|
|
|
vni,
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Uninstall remote neighbor or MAC. */
|
|
|
|
if (n) {
|
2018-12-11 06:33:16 +01:00
|
|
|
if (zvrf->dad_freeze &&
|
|
|
|
CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) &&
|
|
|
|
CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) &&
|
|
|
|
(memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
|
|
|
|
struct interface *vlan_if;
|
|
|
|
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-10-29 01:52:40 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
ipaddr2str(ipaddr, buf1, sizeof(buf1)),
|
|
|
|
n->flags,
|
|
|
|
vlan_if ? vlan_if->name : "Unknown");
|
|
|
|
if (vlan_if)
|
|
|
|
neigh_read_specific_ip(ipaddr, vlan_if);
|
2018-12-11 06:33:16 +01:00
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* When the MAC changes for an IP, it is possible the
|
|
|
|
* client may update the new MAC before trying to delete the
|
|
|
|
* "old" neighbor (as these are two different MACIP routes).
|
|
|
|
* Do the delete only if the MAC matches.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
|
|
|
|
&& (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
|
|
|
|
zvni_neigh_uninstall(zvni, n);
|
|
|
|
zvni_neigh_del(zvni, n);
|
2018-08-29 02:22:04 +02:00
|
|
|
zvni_deref_ip2mac(zvni, mac);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-12-11 06:33:16 +01:00
|
|
|
/* DAD: when MAC is freeze state as remote learn event,
|
|
|
|
* remote mac-ip delete event is received will result in freeze
|
|
|
|
* entry removal, first fetch kernel for the same entry present
|
|
|
|
* as LOCAL and reachable, avoid deleting this entry instead
|
|
|
|
* use kerenel local entry to update during unfreeze time.
|
|
|
|
*/
|
|
|
|
if (zvrf->dad_freeze &&
|
|
|
|
CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) &&
|
|
|
|
CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: MAC %s (flags 0x%x) is remote and duplicate, read kernel for local entry",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
mac->flags);
|
|
|
|
macfdb_read_specific_mac(zns, zif->brslave_info.br_if,
|
|
|
|
macaddr, vxl->access_vlan);
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
zvni_process_neigh_on_remote_mac_del(zvni, mac);
|
2018-10-16 21:59:24 +02:00
|
|
|
/*
|
|
|
|
* the remote sequence number in the auto mac entry
|
|
|
|
* needs to be reset to 0 as the mac entry may have
|
|
|
|
* been removed on all VTEPs (including
|
|
|
|
* the originating one)
|
|
|
|
*/
|
|
|
|
mac->rem_seq = 0;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
2018-08-29 02:22:04 +02:00
|
|
|
/* If all remote neighbors referencing a remote MAC
|
|
|
|
* go away, we need to uninstall the MAC.
|
|
|
|
*/
|
|
|
|
if (remote_neigh_count(mac) == 0) {
|
2018-08-29 02:02:40 +02:00
|
|
|
zvni_mac_uninstall(zvni, mac);
|
2018-08-29 02:22:04 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
}
|
|
|
|
if (list_isempty(mac->neigh_list))
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
zvni_mac_del(zvni, mac);
|
2018-08-29 02:22:04 +02:00
|
|
|
else
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Public functions */
|
|
|
|
|
2018-02-06 23:28:22 +01:00
|
|
|
int is_l3vni_for_prefix_routes_only(vni_t vni)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (!zl3vni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* handle evpn route in vrf table */
|
2018-03-06 20:02:52 +01:00
|
|
|
void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
|
|
|
|
struct ipaddr *vtep_ip,
|
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2018-04-09 06:04:11 +02:00
|
|
|
struct ipaddr ipv4_vtep;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return;
|
|
|
|
|
2018-04-29 20:35:39 +02:00
|
|
|
/*
|
2018-04-09 06:04:11 +02:00
|
|
|
* add the next hop neighbor -
|
|
|
|
* neigh to be installed is the ipv6 nexthop neigh
|
|
|
|
*/
|
2018-04-29 20:35:39 +02:00
|
|
|
zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2018-04-09 06:04:11 +02:00
|
|
|
/*
|
|
|
|
* if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
|
|
|
|
* address. Rmac is programmed against the ipv4 vtep because we only
|
|
|
|
* support ipv4 tunnels in the h/w right now
|
|
|
|
*/
|
|
|
|
memset(&ipv4_vtep, 0, sizeof(struct ipaddr));
|
|
|
|
ipv4_vtep.ipa_type = IPADDR_V4;
|
|
|
|
if (vtep_ip->ipa_type == IPADDR_V6)
|
|
|
|
ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
|
|
|
|
&(ipv4_vtep.ipaddr_v4));
|
|
|
|
else
|
|
|
|
memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
|
2018-04-29 20:35:39 +02:00
|
|
|
/*
|
|
|
|
* add the rmac - remote rmac to be installed is against the ipv4
|
2018-04-09 06:04:11 +02:00
|
|
|
* nexthop address
|
|
|
|
*/
|
2018-04-29 20:35:39 +02:00
|
|
|
zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* handle evpn vrf route delete */
|
2017-11-29 08:40:30 +01:00
|
|
|
void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
|
2018-03-06 20:02:52 +01:00
|
|
|
struct ipaddr *vtep_ip,
|
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-11-29 08:40:30 +01:00
|
|
|
zebra_neigh_t *nh = NULL;
|
|
|
|
zebra_mac_t *zrmac = NULL;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
2017-10-18 10:46:40 +02:00
|
|
|
if (!zl3vni)
|
2017-10-13 10:13:48 +02:00
|
|
|
return;
|
|
|
|
|
2017-11-29 08:40:30 +01:00
|
|
|
/* find the next hop entry and rmac entry */
|
|
|
|
nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
|
|
|
|
if (!nh)
|
|
|
|
return;
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac);
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* delete the next hop entry */
|
2017-11-29 08:40:30 +01:00
|
|
|
zl3vni_remote_nh_del(zl3vni, nh, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
/* delete the rmac entry */
|
2017-11-29 08:40:30 +01:00
|
|
|
if (zrmac)
|
|
|
|
zl3vni_remote_rmac_del(zl3vni, zrmac, host_prefix);
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct ethaddr *rmac, bool use_json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
zebra_mac_t *zrmac = NULL;
|
2017-10-17 14:25:47 +02:00
|
|
|
json_object *json = NULL;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2017-10-17 14:25:47 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
2017-10-17 14:25:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
2017-10-17 01:51:32 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
2017-10-17 14:25:47 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
2018-10-25 20:06:59 +02:00
|
|
|
vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
|
|
|
|
if (!zrmac) {
|
2017-10-17 14:25:47 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty,
|
2018-10-25 20:06:59 +02:00
|
|
|
"%% Requested RMAC doesn't exist in L3-VNI %u",
|
2017-10-17 14:25:47 +02:00
|
|
|
l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 14:25:47 +02:00
|
|
|
zl3vni_print_rmac(zrmac, vty, json);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_rmacs;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct rmac_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_rmacs = hashcount(zl3vni->rmac_table);
|
|
|
|
if (!num_rmacs)
|
|
|
|
return;
|
|
|
|
|
2017-10-17 14:14:33 +02:00
|
|
|
if (use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
2017-10-17 14:14:33 +02:00
|
|
|
wctx.json = json;
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!use_json) {
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "Number of Remote RMACs known for this VNI: %u\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
num_rmacs);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numRmacs", num_rmacs);
|
|
|
|
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
2017-10-17 13:59:42 +02:00
|
|
|
void *args[2];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-17 13:59:42 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-10-17 13:59:42 +02:00
|
|
|
void *))zl3vni_print_rmac_hash_all_vni,
|
|
|
|
args);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct ipaddr *ip, bool use_json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
zebra_neigh_t *n = NULL;
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json = NULL;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2017-10-17 13:32:31 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
2017-10-17 13:32:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
2017-10-17 01:51:32 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
2017-10-17 13:32:31 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = zl3vni_nh_lookup(zl3vni, ip);
|
|
|
|
if (!n) {
|
2017-10-17 13:32:31 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested next-hop not present for L3-VNI %u",
|
|
|
|
l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 13:32:31 +02:00
|
|
|
zl3vni_print_nh(n, vty, json);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_nh;
|
2017-10-13 10:13:48 +02:00
|
|
|
struct nh_walk_ctx wctx;
|
2017-10-08 03:49:27 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_nh = hashcount(zl3vni->nh_table);
|
|
|
|
if (!num_nh)
|
|
|
|
return;
|
|
|
|
|
2017-10-17 13:12:51 +02:00
|
|
|
if (use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
wctx.vty = vty;
|
2017-10-17 13:12:51 +02:00
|
|
|
wctx.json = json;
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!use_json) {
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "Number of NH Neighbors known for this VNI: %u\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
num_nh);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json, "numNextHops", num_nh);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2017-10-13 10:13:48 +02:00
|
|
|
json_object *json = NULL;
|
2017-10-17 12:48:06 +02:00
|
|
|
void *args[2];
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-17 12:48:06 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-10-17 12:48:06 +02:00
|
|
|
void *))zl3vni_print_nh_hash_all_vni,
|
|
|
|
args);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display L3 VNI information (VTY command handler).
|
|
|
|
*/
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
void *args[2];
|
|
|
|
json_object *json = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
2017-10-17 12:14:14 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
2017-10-17 12:14:14 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-17 12:14:14 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_print(zl3vni, (void *)args);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
json_object *json_vrfs)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2017-11-15 10:01:00 +01:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (!zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
if (!json_vrfs) {
|
|
|
|
vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n",
|
2018-03-06 20:02:52 +01:00
|
|
|
zvrf_name(zvrf), zl3vni->vni,
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni_vxlan_if_name(zl3vni),
|
2018-03-06 20:02:52 +01:00
|
|
|
zl3vni_svi_if_name(zl3vni), zl3vni_state2str(zl3vni),
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object *json_vrf = NULL;
|
2018-08-20 23:31:30 +02:00
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
json_vrf = json_object_new_object();
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(json_vrf, "vrf", zvrf_name(zvrf));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json_vrf, "vni", zl3vni->vni);
|
|
|
|
json_object_string_add(json_vrf, "vxlanIntf",
|
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
|
|
|
json_object_string_add(json_vrf, "sviIntf",
|
|
|
|
zl3vni_svi_if_name(zl3vni));
|
|
|
|
json_object_string_add(json_vrf, "state",
|
|
|
|
zl3vni_state2str(zl3vni));
|
2018-03-06 20:02:52 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json_vrf, "routerMac",
|
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_array_add(json_vrfs, json_vrf);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display Neighbors for a VNI (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
vni_t vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_neigh;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
/* Since we have IPv6 addresses to deal with which can vary widely in
|
|
|
|
* size, we try to be a bit more elegant in display by first computing
|
|
|
|
* the maximum width.
|
|
|
|
*/
|
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
|
|
|
wctx.json = json;
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
|
|
|
|
|
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of ARPs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_neigh);
|
2019-06-21 07:37:02 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n", -wctx.addr_width,
|
|
|
|
"IP", "Type", "State", "MAC", "Remote VTEP", "Seq #'s");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numArpNd", num_neigh);
|
|
|
|
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display neighbors across all VNIs (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-11-04 19:17:29 +01:00
|
|
|
bool print_dup, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
2018-11-04 19:17:29 +01:00
|
|
|
void *args[3];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2018-11-04 19:17:29 +01:00
|
|
|
args[2] = (void *)(ptrdiff_t)print_dup;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
hash_iterate(zvrf->vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-10-08 03:49:27 +02:00
|
|
|
void *))zvni_print_neigh_hash_all_vni,
|
|
|
|
args);
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-22 10:56:52 +01:00
|
|
|
/*
|
|
|
|
* Display neighbors across all VNIs in detail(VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
bool print_dup, bool use_json)
|
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[3];
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
|
|
|
args[2] = (void *)(ptrdiff_t)print_dup;
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2018-11-22 10:56:52 +01:00
|
|
|
void *))zvni_print_neigh_hash_all_vni_detail,
|
|
|
|
args);
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Display specific neighbor for a VNI, if present (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf, vni_t vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct ipaddr *ip, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
if (use_json)
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!use_json)
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested neighbor does not exist in VNI %u\n",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
zvni_print_neigh(n, vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display neighbors for a VNI from specific VTEP (VTY command handler).
|
|
|
|
* By definition, these are remote neighbors.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
vni_t vni, struct in_addr vtep_ip,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_neigh;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
2018-07-07 06:46:46 +02:00
|
|
|
wctx.addr_width = 15;
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2018-07-07 06:46:46 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
/*
|
|
|
|
* Display Duplicate detected Neighbors for a VNI
|
|
|
|
* (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni,
|
|
|
|
bool use_json)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
uint32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
num_neigh = num_dup_detected_neighs(zvni);
|
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
/* Since we have IPv6 addresses to deal with which can vary widely in
|
|
|
|
* size, we try to be a bit more elegant in display by first computing
|
|
|
|
* the maximum width.
|
|
|
|
*/
|
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
|
|
|
wctx.json = json;
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
|
|
|
|
|
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of ARPs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_neigh);
|
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
|
|
|
|
-wctx.addr_width, "IP", "Type",
|
|
|
|
"State", "MAC", "Remote VTEP");
|
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numArpNd", num_neigh);
|
|
|
|
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash, &wctx);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display MACs for a VNI (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
vni_t vni, bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json_mac;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
2019-06-21 07:37:02 +02:00
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC", "Type",
|
|
|
|
"Intf/Remote VTEP", "VLAN", "Seq #'s");
|
2017-06-22 01:37:51 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display MACs for all VNIs (VTY command handler).
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-11-04 19:17:29 +01:00
|
|
|
bool print_dup, bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2018-11-04 19:17:29 +01:00
|
|
|
wctx.print_dup = print_dup;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 09:18:10 +01:00
|
|
|
/*
|
|
|
|
* Display MACs in detail for all VNIs (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
bool print_dup, bool use_json)
|
|
|
|
{
|
|
|
|
struct mac_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.json = json;
|
|
|
|
wctx.print_dup = print_dup;
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni_detail,
|
|
|
|
&wctx);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display MACs for all VNIs (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct in_addr vtep_ip, bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display specific MAC for a VNI, if present (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-10-26 22:57:23 +02:00
|
|
|
vni_t vni, struct ethaddr *macaddr,
|
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
2018-10-26 22:57:23 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2018-10-26 22:57:23 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2018-10-26 22:57:23 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac) {
|
2018-10-26 22:57:23 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested MAC does not exist in VNI %u\n",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2018-10-26 22:57:23 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
zvni_print_mac(mac, vty, json);
|
2018-11-22 09:18:10 +01:00
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
/* Print Duplicate MACs per VNI */
|
|
|
|
void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni, bool use_json)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct mac_walk_ctx wctx;
|
|
|
|
uint32_t num_macs;
|
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_macs = num_valid_macs(zvni);
|
|
|
|
if (!num_macs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
num_macs = num_dup_detected_macs(zvni);
|
|
|
|
if (!num_macs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.json = json_mac;
|
|
|
|
|
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
|
|
|
|
"Intf/Remote VTEP", "VLAN");
|
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
|
|
|
|
|
|
|
hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, &wctx);
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni, struct ethaddr *macaddr)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
zebra_neigh_t *nbr = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
2018-11-04 19:55:39 +01:00
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac) {
|
|
|
|
vty_out(vty, "%% Requested MAC does not exist in VNI %u\n",
|
|
|
|
vni);
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
|
|
|
vty_out(vty, "%% Requested MAC is not duplicate detected\n");
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove all IPs as duplicate associcated with this MAC */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
|
|
|
|
/* For local neigh mark inactive so MACIP update is generated
|
|
|
|
* to BGP. This is a scenario where MAC update received
|
|
|
|
* and detected as duplicate which marked neigh as duplicate.
|
|
|
|
* Later local neigh update did not get a chance to relay
|
|
|
|
* to BGP. Similarly remote macip update, neigh needs to be
|
|
|
|
* installed locally.
|
|
|
|
*/
|
2018-12-15 03:34:06 +01:00
|
|
|
if (zvrf->dad_freeze &&
|
|
|
|
CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
2018-11-04 19:55:39 +01:00
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(nbr);
|
|
|
|
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
|
|
|
|
zvni_neigh_install(zvni, nbr);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
|
|
|
mac->dad_count = 0;
|
|
|
|
mac->detect_start_time.tv_sec = 0;
|
|
|
|
mac->detect_start_time.tv_usec = 0;
|
|
|
|
mac->dad_dup_detect_time = 0;
|
|
|
|
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
|
|
|
|
|
2018-12-15 03:34:06 +01:00
|
|
|
/* warn-only action return */
|
|
|
|
if (!zvrf->dad_freeze)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
2018-11-04 19:55:39 +01:00
|
|
|
/* Local: Notify Peer VTEPs, Remote: Install the entry */
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
/* Inform to BGP */
|
|
|
|
if (zvni_mac_send_add_to_client(zvni->vni,
|
|
|
|
&mac->macaddr,
|
|
|
|
mac->flags,
|
|
|
|
mac->loc_seq))
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
/* Process all neighbors associated with this MAC. */
|
|
|
|
zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
|
|
|
|
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
zvni_process_neigh_on_remote_mac_add(zvni, mac);
|
|
|
|
|
|
|
|
/* Install the entry. */
|
|
|
|
zvni_mac_install(zvni, mac);
|
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni, struct ipaddr *ip)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_neigh_t *nbr;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
char buf2[ETHER_ADDR_STRLEN];
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
nbr = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!nbr) {
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested host IP does not exist in VNI %u\n",
|
|
|
|
vni);
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ipaddr2str(&nbr->ip, buf, sizeof(buf));
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
|
|
|
vty_out(vty,
|
2019-08-19 16:12:30 +02:00
|
|
|
"%% Requested host IP %s is not duplicate detected\n",
|
2018-11-04 19:55:39 +01:00
|
|
|
buf);
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
mac = zvni_mac_lookup(zvni, &nbr->emac);
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested IP's associated MAC %s is still in duplicate state\n",
|
|
|
|
prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)));
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: clear neigh %s in dup state, flags 0x%x seq %u",
|
|
|
|
__PRETTY_FUNCTION__, buf, nbr->flags,
|
|
|
|
nbr->loc_seq);
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->detect_start_time.tv_usec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
|
|
|
|
|
|
|
|
if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
zvni_neigh_send_add_to_client(zvni->vni, ip,
|
|
|
|
&nbr->emac,
|
|
|
|
nbr->flags, nbr->loc_seq);
|
|
|
|
} else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
zvni_neigh_install(zvni, nbr);
|
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
zebra_neigh_t *nbr = NULL;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
mac = (zebra_mac_t *)bucket->data;
|
2018-11-04 19:55:39 +01:00
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvni = wctx->zvni;
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
|
|
|
mac->dad_count = 0;
|
|
|
|
mac->detect_start_time.tv_sec = 0;
|
|
|
|
mac->detect_start_time.tv_usec = 0;
|
|
|
|
mac->dad_dup_detect_time = 0;
|
|
|
|
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
|
|
|
|
|
|
|
|
/* Remove all IPs as duplicate associcated with this MAC */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)
|
|
|
|
&& nbr->dad_count)
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(nbr);
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Local: Notify Peer VTEPs, Remote: Install the entry */
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
/* Inform to BGP */
|
|
|
|
if (zvni_mac_send_add_to_client(zvni->vni,
|
|
|
|
&mac->macaddr,
|
|
|
|
mac->flags, mac->loc_seq))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Process all neighbors associated with this MAC. */
|
|
|
|
zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
|
|
|
|
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
zvni_process_neigh_on_remote_mac_add(zvni, mac);
|
|
|
|
|
|
|
|
/* Install the entry. */
|
|
|
|
zvni_mac_install(zvni, mac);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
|
|
|
zebra_neigh_t *nbr;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
nbr = (zebra_neigh_t *)bucket->data;
|
2018-11-04 19:55:39 +01:00
|
|
|
if (!nbr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvni = wctx->zvni;
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN) {
|
|
|
|
ipaddr2str(&nbr->ip, buf, sizeof(buf));
|
|
|
|
zlog_debug(
|
|
|
|
"%s: clear neigh %s dup state, flags 0x%x seq %u",
|
|
|
|
__PRETTY_FUNCTION__, buf,
|
|
|
|
nbr->flags, nbr->loc_seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->detect_start_time.tv_usec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
|
|
|
|
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip,
|
|
|
|
&nbr->emac,
|
|
|
|
nbr->flags, nbr->loc_seq);
|
|
|
|
} else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
zvni_neigh_install(zvni, nbr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
|
2018-11-04 19:55:39 +01:00
|
|
|
void **args)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
struct mac_walk_ctx m_wctx;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
2018-11-04 19:55:39 +01:00
|
|
|
if (!zvni)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
zvrf = (struct zebra_vrf *)args[1];
|
|
|
|
|
|
|
|
if (hashcount(zvni->neigh_table)) {
|
|
|
|
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
n_wctx.vty = vty;
|
|
|
|
n_wctx.zvni = zvni;
|
|
|
|
n_wctx.zvrf = zvrf;
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash,
|
|
|
|
&n_wctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_valid_macs(zvni)) {
|
|
|
|
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
m_wctx.zvni = zvni;
|
|
|
|
m_wctx.vty = vty;
|
|
|
|
m_wctx.zvrf = zvrf;
|
|
|
|
hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty,
|
2018-11-04 19:55:39 +01:00
|
|
|
struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
void *args[2];
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
args[0] = vty;
|
|
|
|
args[1] = zvrf;
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))
|
2018-11-04 19:55:39 +01:00
|
|
|
zvni_clear_dup_detect_hash_vni_all, args);
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni(struct vty *vty,
|
2018-11-04 19:55:39 +01:00
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct mac_walk_ctx m_wctx;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hashcount(zvni->neigh_table)) {
|
|
|
|
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
n_wctx.vty = vty;
|
|
|
|
n_wctx.zvni = zvni;
|
|
|
|
n_wctx.zvrf = zvrf;
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash,
|
|
|
|
&n_wctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_valid_macs(zvni)) {
|
|
|
|
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
m_wctx.zvni = zvni;
|
|
|
|
m_wctx.vty = vty;
|
|
|
|
m_wctx.zvrf = zvrf;
|
|
|
|
hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx);
|
|
|
|
}
|
|
|
|
|
2018-12-03 04:08:22 +01:00
|
|
|
return CMD_SUCCESS;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display MACs for a VNI from specific VTEP (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
vni_t vni, struct in_addr vtep_ip,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json_mac;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_int_add(json, "numMacs", wctx.count);
|
|
|
|
if (wctx.count)
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display VNI information (VTY command handler).
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
2018-02-10 01:57:37 +01:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2018-02-10 01:57:37 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni_print(zl3vni, (void *)args);
|
|
|
|
} else {
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_print(zvni, (void *)args);
|
|
|
|
}
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
/* Display all global details for EVPN */
|
2018-09-04 19:39:04 +02:00
|
|
|
void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-11-15 10:01:00 +01:00
|
|
|
int num_l2vnis = 0;
|
|
|
|
int num_l3vnis = 0;
|
2017-12-07 17:28:04 +01:00
|
|
|
int num_vnis = 0;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-11-15 10:01:00 +01:00
|
|
|
struct zebra_vrf *zvrf = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2019-03-06 19:15:10 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2017-11-15 10:01:00 +01:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
num_l3vnis = hashcount(zrouter.l3vni_table);
|
2017-11-15 10:01:00 +01:00
|
|
|
num_l2vnis = hashcount(zvrf->vni_table);
|
2017-12-07 17:28:04 +01:00
|
|
|
num_vnis = num_l2vnis + num_l3vnis;
|
2017-11-15 10:01:00 +01:00
|
|
|
|
|
|
|
if (uj) {
|
2017-06-22 01:37:51 +02:00
|
|
|
json = json_object_new_object();
|
2017-07-07 01:33:50 +02:00
|
|
|
json_object_string_add(json, "advertiseGatewayMacip",
|
|
|
|
zvrf->advertise_gw_macip ? "Yes" : "No");
|
2017-12-07 17:28:04 +01:00
|
|
|
json_object_int_add(json, "numVnis", num_vnis);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json, "numL2Vnis", num_l2vnis);
|
|
|
|
json_object_int_add(json, "numL3Vnis", num_l3vnis);
|
2018-11-17 02:51:11 +01:00
|
|
|
if (zvrf->dup_addr_detect)
|
|
|
|
json_object_boolean_true_add(json,
|
|
|
|
"isDuplicateAddrDetection");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json,
|
|
|
|
"isDuplicateAddrDetection");
|
|
|
|
json_object_int_add(json, "maxMoves", zvrf->dad_max_moves);
|
|
|
|
json_object_int_add(json, "detectionTime", zvrf->dad_time);
|
|
|
|
json_object_int_add(json, "detectionFreezeTime",
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "L2 VNIs: %u\n", num_l2vnis);
|
|
|
|
vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
|
2017-07-07 01:33:50 +02:00
|
|
|
vty_out(vty, "Advertise gateway mac-ip: %s\n",
|
|
|
|
zvrf->advertise_gw_macip ? "Yes" : "No");
|
2019-02-05 17:38:35 +01:00
|
|
|
vty_out(vty, "Advertise svi mac-ip: %s\n",
|
|
|
|
zvrf->advertise_svi_macip ? "Yes" : "No");
|
2018-11-17 02:51:11 +01:00
|
|
|
vty_out(vty, "Duplicate address detection: %s\n",
|
|
|
|
zvrf->dup_addr_detect ? "Enable" : "Disable");
|
|
|
|
vty_out(vty, " Detection max-moves %u, time %d\n",
|
|
|
|
zvrf->dad_max_moves, zvrf->dad_time);
|
|
|
|
if (zvrf->dad_freeze) {
|
|
|
|
if (zvrf->dad_freeze_time)
|
|
|
|
vty_out(vty, " Detection freeze %u\n",
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
else
|
|
|
|
vty_out(vty, " Detection freeze %s\n",
|
|
|
|
"permanent");
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-11-15 10:01:00 +01:00
|
|
|
|
|
|
|
if (uj) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display VNI hash table (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-11-15 10:01:00 +01:00
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
else
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n", "VNI",
|
|
|
|
"Type", "VxLAN IF", "# MACs", "# ARPs",
|
|
|
|
"# Remote VTEPs", "Tenant VRF");
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
/* Display all L2-VNIs */
|
2017-06-22 01:37:51 +02:00
|
|
|
hash_iterate(zvrf->vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))zvni_print_hash,
|
2017-06-22 01:37:51 +02:00
|
|
|
args);
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
/* Display all L3-VNIs */
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))zl3vni_print_hash,
|
2017-11-15 10:01:00 +01:00
|
|
|
args);
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-02 01:55:07 +01:00
|
|
|
void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int time = 0;
|
|
|
|
uint32_t max_moves = 0;
|
|
|
|
uint32_t freeze_time = 0;
|
|
|
|
bool dup_addr_detect = false;
|
|
|
|
bool freeze = false;
|
|
|
|
|
|
|
|
s = msg;
|
|
|
|
STREAM_GETL(s, dup_addr_detect);
|
|
|
|
STREAM_GETL(s, time);
|
|
|
|
STREAM_GETL(s, max_moves);
|
|
|
|
STREAM_GETL(s, freeze);
|
|
|
|
STREAM_GETL(s, freeze_time);
|
|
|
|
|
2018-11-04 19:55:39 +01:00
|
|
|
/* DAD previous state was enabled, and new state is disable,
|
|
|
|
* clear all duplicate detected addresses.
|
|
|
|
*/
|
|
|
|
if (zvrf->dup_addr_detect && !dup_addr_detect)
|
|
|
|
zebra_vxlan_clear_dup_detect_vni_all(NULL, zvrf);
|
|
|
|
|
2018-11-02 01:55:07 +01:00
|
|
|
zvrf->dup_addr_detect = dup_addr_detect;
|
|
|
|
zvrf->dad_time = time;
|
|
|
|
zvrf->dad_max_moves = max_moves;
|
|
|
|
zvrf->dad_freeze = freeze;
|
|
|
|
zvrf->dad_freeze_time = freeze_time;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2019-01-03 01:48:32 +01:00
|
|
|
"VRF %s duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
|
|
|
|
vrf_id_to_name(zvrf->vrf->vrf_id),
|
2018-11-02 01:55:07 +01:00
|
|
|
zvrf->dup_addr_detect ? "enable" : "disable",
|
|
|
|
zvrf->dad_max_moves,
|
|
|
|
zvrf->dad_time,
|
|
|
|
zvrf->dad_freeze ? "enable" : "disable",
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:33:43 +01:00
|
|
|
/*
|
|
|
|
* Display VNI hash table in detail(VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
bool use_json)
|
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
|
|
|
struct zebra_ns *zns = NULL;
|
|
|
|
struct zvni_evpn_show zes;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
if (!zns)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
zes.vty = vty;
|
|
|
|
zes.json = json;
|
|
|
|
zes.zvrf = zvrf;
|
|
|
|
|
|
|
|
/* Display all L2-VNIs */
|
2019-02-26 20:04:15 +01:00
|
|
|
hash_iterate(
|
|
|
|
zvrf->vni_table,
|
|
|
|
(void (*)(struct hash_bucket *, void *))zvni_print_hash_detail,
|
|
|
|
&zes);
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
/* Display all L3-VNIs */
|
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2018-11-15 18:33:43 +01:00
|
|
|
void *))zl3vni_print_hash_detail,
|
|
|
|
&zes);
|
|
|
|
|
|
|
|
if (use_json) {
|
2019-02-26 20:04:15 +01:00
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
2018-11-15 18:33:43 +01:00
|
|
|
json_object_free(json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
2018-03-03 00:28:33 +01:00
|
|
|
* Handle neighbor delete notification from the kernel (on a VLAN device
|
|
|
|
* / L3 interface). This may result in either the neighbor getting deleted
|
|
|
|
* from our database or being re-added to the kernel (if it is a valid
|
2017-05-15 07:44:13 +02:00
|
|
|
* remote neighbor).
|
|
|
|
*/
|
2018-03-03 00:28:33 +01:00
|
|
|
int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
|
|
|
|
struct interface *link_if,
|
|
|
|
struct ipaddr *ip)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
2017-07-06 00:03:14 +02:00
|
|
|
char buf2[ETHER_ADDR_STRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_mac_t *zmac = NULL;
|
2017-10-22 10:16:54 +02:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2018-12-27 00:05:15 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-10-22 10:16:54 +02:00
|
|
|
/* check if this is a remote neigh entry corresponding to remote
|
2017-12-27 20:47:10 +01:00
|
|
|
* next-hop
|
|
|
|
*/
|
2017-10-22 10:16:54 +02:00
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni)
|
|
|
|
return zl3vni_local_nh_del(zl3vni, ip);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* We are only interested in neighbors on an SVI that resides on top
|
|
|
|
* of a VxLAN bridge.
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni = zvni_from_svi(ifp, link_if);
|
2019-07-26 23:57:59 +02:00
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: Del neighbor %s VNI is not present for interface %s",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
ipaddr2str(ip, buf, sizeof(buf)), ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2019-07-26 23:57:59 +02:00
|
|
|
}
|
2017-10-22 10:16:54 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-07-17 14:03:14 +02:00
|
|
|
"VNI %u hash %p doesn't have intf upon local neighbor DEL",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-10-22 10:16:54 +02:00
|
|
|
zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u",
|
2018-03-06 20:02:52 +01:00
|
|
|
ipaddr2str(ip, buf, sizeof(buf)), ifp->name,
|
|
|
|
ifp->ifindex, zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (!zmac) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Trying to del a neigh %s without a mac %s on VNI %u",
|
|
|
|
ipaddr2str(ip, buf, sizeof(buf)),
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If it is a remote entry, the kernel has aged this out or someone has
|
|
|
|
* deleted it, it needs to be re-installed as Quagga is the owner.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
zvni_neigh_install(zvni, n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
2018-12-27 00:05:15 +01:00
|
|
|
if (!zvrf) {
|
|
|
|
zlog_debug("%s: VNI %u vrf lookup failed.",
|
|
|
|
__PRETTY_FUNCTION__, zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In case of feeze action, if local neigh is in duplicate state,
|
|
|
|
* Mark the Neigh as inactive before sending delete request to BGPd,
|
|
|
|
* If BGPd has remote entry, it will re-install
|
|
|
|
*/
|
|
|
|
if (zvrf->dad_freeze &&
|
|
|
|
CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Remove neighbor from BGP. */
|
2018-12-27 00:05:15 +01:00
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0, n->state);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* Delete this neighbor entry. */
|
|
|
|
zvni_neigh_del(zvni, n);
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* see if the AUTO mac needs to be deleted */
|
|
|
|
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
|
2017-08-19 02:40:52 +02:00
|
|
|
&& !listcount(zmac->neigh_list))
|
2017-07-06 00:03:14 +02:00
|
|
|
zvni_mac_del(zvni, zmac);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-03-03 00:28:33 +01:00
|
|
|
* Handle neighbor add or update notification from the kernel (on a VLAN
|
|
|
|
* device / L3 interface). This is typically for a local neighbor but can
|
|
|
|
* also be for a remote neighbor (e.g., ageout notification). It could
|
|
|
|
* also be a "move" scenario.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2018-03-03 00:28:33 +01:00
|
|
|
int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
|
|
|
|
struct interface *link_if,
|
|
|
|
struct ipaddr *ip,
|
|
|
|
struct ethaddr *macaddr,
|
|
|
|
uint16_t state,
|
2018-09-10 19:13:20 +02:00
|
|
|
bool is_ext,
|
|
|
|
bool is_router)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-11-09 18:13:28 +01:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
/* check if this is a remote neigh entry corresponding to remote
|
|
|
|
* next-hop
|
|
|
|
*/
|
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni)
|
|
|
|
return zl3vni_local_nh_add_update(zl3vni, ip, state);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* We are only interested in neighbors on an SVI that resides on top
|
|
|
|
* of a VxLAN bridge.
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni = zvni_from_svi(ifp, link_if);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2018-08-14 02:07:22 +02:00
|
|
|
"Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s %s-> L2-VNI %u",
|
2017-09-18 23:45:34 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
2018-09-10 19:13:20 +02:00
|
|
|
ifp->ifindex, state, is_ext ? "ext-learned " : "",
|
|
|
|
is_router ? "router " : "",
|
2017-10-22 10:16:54 +02:00
|
|
|
zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-03 00:28:33 +01:00
|
|
|
/* Is this about a local neighbor or a remote one? */
|
2018-09-10 19:13:20 +02:00
|
|
|
if (!is_ext)
|
2018-07-07 06:46:46 +02:00
|
|
|
return zvni_local_neigh_update(zvni, ifp, ip, macaddr,
|
2018-09-10 19:13:20 +02:00
|
|
|
is_router);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-03-03 00:28:33 +01:00
|
|
|
return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-08-14 06:52:04 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to delete a remote MACIP for a VNI.
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
vni_t vni;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct in_addr vtep_ip;
|
2018-08-20 23:31:30 +02:00
|
|
|
uint16_t l = 0, ipa_len;
|
2017-07-17 14:03:14 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
memset(&macaddr, 0, sizeof(struct ethaddr));
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
memset(&vtep_ip, 0, sizeof(struct in_addr));
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Obtain each remote MACIP and process. */
|
|
|
|
/* Message contains VNI, followed by MAC followed by IP (if any)
|
|
|
|
* followed by remote VTEP IP.
|
|
|
|
*/
|
|
|
|
memset(&ip, 0, sizeof(ip));
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
|
|
|
STREAM_GET(&macaddr.octet, s, ETH_ALEN);
|
|
|
|
STREAM_GETL(s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ipa_len) {
|
|
|
|
ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
|
|
|
|
: IPADDR_V6;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&ip.ip.addr, s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-08-03 14:43:56 +02:00
|
|
|
l += 4 + ETH_ALEN + 4 + ipa_len;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
"Recv MACIP DEL VNI %u MAC %s%s%s Remote VTEP %s from %s",
|
|
|
|
vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&macaddr, buf, sizeof(buf)),
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
|
2017-07-17 14:03:14 +02:00
|
|
|
inet_ntoa(vtep_ip),
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
process_remote_macip_del(vni, &macaddr, ipa_len, &ip, vtep_ip);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to add a remote MACIP for a VNI. This
|
|
|
|
* could be just the add of a MAC address or the add of a neighbor
|
|
|
|
* (IP+MAC).
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
vni_t vni;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct in_addr vtep_ip;
|
2018-08-20 23:31:30 +02:00
|
|
|
uint16_t l = 0, ipa_len;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint8_t flags = 0;
|
|
|
|
uint32_t seq;
|
2017-07-17 14:03:14 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
memset(&macaddr, 0, sizeof(struct ethaddr));
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
memset(&vtep_ip, 0, sizeof(struct in_addr));
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("EVPN not enabled, ignoring remote MACIP ADD");
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-10 14:51:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Obtain each remote MACIP and process. */
|
|
|
|
/* Message contains VNI, followed by MAC followed by IP (if any)
|
|
|
|
* followed by remote VTEP IP.
|
|
|
|
*/
|
|
|
|
memset(&ip, 0, sizeof(ip));
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
|
|
|
STREAM_GET(&macaddr.octet, s, ETH_ALEN);
|
|
|
|
STREAM_GETL(s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ipa_len) {
|
|
|
|
ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
|
|
|
|
: IPADDR_V6;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&ip.ip.addr, s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-08-03 14:43:56 +02:00
|
|
|
l += 4 + ETH_ALEN + 4 + ipa_len;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
2017-11-13 12:19:52 +01:00
|
|
|
/* Get flags - sticky mac and/or gateway mac */
|
2018-04-27 15:21:28 +02:00
|
|
|
STREAM_GETC(s, flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
l++;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
STREAM_GETL(s, seq);
|
|
|
|
l += 4;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
"Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s",
|
|
|
|
vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&macaddr, buf, sizeof(buf)),
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
|
|
|
|
flags, seq, inet_ntoa(vtep_ip),
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
process_remote_macip_add(vni, &macaddr, ipa_len, &ip,
|
|
|
|
flags, seq, vtep_ip);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle notification of MAC add/update over VxLAN. If the kernel is notifying
|
|
|
|
* us, this must involve a multihoming scenario. Treat this as implicit delete
|
|
|
|
* of any prior local MAC.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_check_del_local_mac(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Is it a local entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2019-05-09 21:25:44 +02:00
|
|
|
"Add/update remote MAC %s intf %s(%u) VNI %u flags 0x%x - del local",
|
2018-03-06 20:02:52 +01:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
2019-05-09 21:25:44 +02:00
|
|
|
ifp->ifindex, vni, mac->flags);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Remove MAC from BGP. */
|
2018-10-11 17:48:42 +02:00
|
|
|
zvni_mac_send_del_to_client(zvni->vni, macaddr);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/*
|
|
|
|
* If there are no neigh associated with the mac delete the mac
|
|
|
|
* else mark it as AUTO for forward reference
|
|
|
|
*/
|
|
|
|
if (!listcount(mac->neigh_list)) {
|
|
|
|
zvni_mac_del(zvni, mac);
|
|
|
|
} else {
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
2019-05-09 21:25:44 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
2017-07-06 00:03:14 +02:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle remote MAC delete by kernel; readd the remote MAC if we have it.
|
|
|
|
* This can happen because the remote MAC entries are also added as "dynamic",
|
|
|
|
* so the kernel can ageout the entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-11-29 11:25:35 +01:00
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
2017-11-29 11:25:35 +01:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
zebra_mac_t *mac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-11-29 11:25:35 +01:00
|
|
|
/* check if this is a remote RMAC and readd simillar to remote macs */
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni)
|
|
|
|
return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Is it a remote entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Del remote MAC %s intf %s(%u) VNI %u - readd",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
|
|
|
ifp->ifindex, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_mac_install(zvni, mac);
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle local MAC delete (on a port or VLAN corresponding to this VNI).
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* We are interested in MACs only on ports or (port, VLAN) that
|
|
|
|
* map to a VNI.
|
|
|
|
*/
|
|
|
|
zvni = zvni_map_vlan(ifp, br_if, vid);
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
if (!zvni->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
|
|
|
"VNI %u hash %p doesn't have intf upon local MAC DEL",
|
|
|
|
zvni->vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Is it a local entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2019-05-09 21:25:44 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-07-04 02:03:15 +02:00
|
|
|
zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u",
|
2019-05-09 21:25:44 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
2019-07-04 02:03:15 +02:00
|
|
|
ifp->ifindex, vid, zvni->vni, mac->loc_seq,
|
|
|
|
mac->flags, listcount(mac->neigh_list));
|
2019-05-09 21:25:44 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* Update all the neigh entries associated with this mac */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_process_neigh_on_local_mac_del(zvni, mac);
|
2017-07-06 00:03:14 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Remove MAC from BGP. */
|
2018-10-11 17:48:42 +02:00
|
|
|
zvni_mac_send_del_to_client(zvni->vni, macaddr);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/*
|
|
|
|
* If there are no neigh associated with the mac delete the mac
|
|
|
|
* else mark it as AUTO for forward reference
|
|
|
|
*/
|
|
|
|
if (!listcount(mac->neigh_list)) {
|
|
|
|
zvni_mac_del(zvni, mac);
|
|
|
|
} else {
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
2019-05-09 21:25:44 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
2017-07-06 00:03:14 +02:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle local MAC add (on a port or VLAN corresponding to this VNI).
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid,
|
2018-09-10 19:13:20 +02:00
|
|
|
bool sticky)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
2018-11-02 16:30:41 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
bool mac_sticky = false;
|
|
|
|
bool inform_client = false;
|
|
|
|
bool upd_neigh = false;
|
2018-12-17 23:36:27 +01:00
|
|
|
bool is_dup_detect = false;
|
2018-11-02 16:30:41 +01:00
|
|
|
struct in_addr vtep_ip = {.s_addr = 0};
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* We are interested in MACs only on ports or (port, VLAN) that
|
|
|
|
* map to a VNI.
|
|
|
|
*/
|
|
|
|
zvni = zvni_map_vlan(ifp, br_if, vid);
|
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2019-03-08 16:46:55 +01:00
|
|
|
"\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
|
2017-09-18 23:45:34 +02:00
|
|
|
sticky ? "sticky " : "",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zvni->vxlan_if) {
|
2019-03-08 16:46:55 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"\tVNI %u hash %p doesn't have intf upon local MAC ADD",
|
|
|
|
zvni->vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
2019-03-08 16:46:55 +01:00
|
|
|
if (!zvrf) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-06-24 01:46:39 +02:00
|
|
|
zlog_debug("\tNo Vrf found for vrf_id: %d",
|
|
|
|
zvni->vxlan_if->vrf_id);
|
2018-11-02 16:30:41 +01:00
|
|
|
return -1;
|
2019-03-08 16:46:55 +01:00
|
|
|
}
|
2018-11-02 16:30:41 +01:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Check if we need to create or update or it is a NO-OP. */
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (!mac) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"ADD %sMAC %s intf %s(%u) VID %u -> VNI %u",
|
|
|
|
sticky ? "sticky " : "",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid, zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
mac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!mac) {
|
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_MAC_ADD_FAILED,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
"Failed to add MAC %s intf %s(%u) VID %u VNI %u",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid, zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
mac->fwd_info.local.ifindex = ifp->ifindex;
|
|
|
|
mac->fwd_info.local.vid = vid;
|
|
|
|
if (sticky)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
inform_client = true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"UPD %sMAC %s intf %s(%u) VID %u -> VNI %u curFlags 0x%x",
|
|
|
|
sticky ? "sticky " : "",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid, zvni->vni,
|
|
|
|
mac->flags);
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
|
|
|
|
mac_sticky = true;
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-06-21 23:25:39 +02:00
|
|
|
/*
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
* Update any changes and if changes are relevant to
|
|
|
|
* BGP, note it.
|
2017-06-21 23:25:39 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
if (mac_sticky == sticky
|
|
|
|
&& mac->fwd_info.local.ifindex == ifp->ifindex
|
|
|
|
&& mac->fwd_info.local.vid == vid) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2019-03-08 16:46:55 +01:00
|
|
|
"\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
|
2017-07-17 14:03:14 +02:00
|
|
|
"entry exists and has not changed ",
|
|
|
|
sticky ? "sticky " : "",
|
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid,
|
|
|
|
zvni->vni);
|
|
|
|
return 0;
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (mac_sticky != sticky) {
|
|
|
|
if (sticky)
|
|
|
|
SET_FLAG(mac->flags,
|
|
|
|
ZEBRA_MAC_STICKY);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(mac->flags,
|
|
|
|
ZEBRA_MAC_STICKY);
|
|
|
|
inform_client = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
|
|
|
mac->fwd_info.local.ifindex = ifp->ifindex;
|
|
|
|
mac->fwd_info.local.vid = vid;
|
|
|
|
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
|
|
|
|
CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
|
2018-11-02 16:30:41 +01:00
|
|
|
bool do_dad = false;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
|
2017-06-21 21:55:29 +02:00
|
|
|
/*
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
* MAC has either moved or was "internally" created due
|
|
|
|
* to a neighbor learn and is now actually learnt. If
|
|
|
|
* it was learnt as a remote sticky MAC, this is an
|
|
|
|
* operator error.
|
2017-06-21 21:55:29 +02:00
|
|
|
*/
|
2017-06-27 02:55:55 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
|
2018-08-16 22:10:32 +02:00
|
|
|
flog_warn(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
|
2018-08-16 22:10:32 +02:00
|
|
|
"MAC %s already learnt as remote sticky MAC behind VTEP %s VNI %u",
|
2017-06-21 21:55:29 +02:00
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip),
|
|
|
|
zvni->vni);
|
2017-06-27 02:55:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* If an actual move, compute MAC's seq number */
|
2018-11-02 16:30:41 +01:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
mac->loc_seq = MAX(mac->rem_seq + 1,
|
|
|
|
mac->loc_seq);
|
2018-11-02 16:30:41 +01:00
|
|
|
vtep_ip = mac->fwd_info.r_vtep_ip;
|
|
|
|
/* Trigger DAD for remote MAC */
|
|
|
|
do_dad = true;
|
|
|
|
}
|
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
|
|
|
mac->fwd_info.local.ifindex = ifp->ifindex;
|
|
|
|
mac->fwd_info.local.vid = vid;
|
|
|
|
if (sticky)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
/*
|
|
|
|
* We have to inform BGP of this MAC as well as process
|
|
|
|
* all neighbors.
|
|
|
|
*/
|
|
|
|
inform_client = true;
|
|
|
|
upd_neigh = true;
|
2018-11-02 16:30:41 +01:00
|
|
|
|
2018-11-18 01:03:19 +01:00
|
|
|
zebra_vxlan_dup_addr_detect_for_mac(zvrf, mac, vtep_ip,
|
|
|
|
do_dad,
|
2018-12-17 23:36:27 +01:00
|
|
|
&is_dup_detect,
|
2018-11-18 01:03:19 +01:00
|
|
|
true);
|
2018-12-17 23:36:27 +01:00
|
|
|
if (is_dup_detect) {
|
|
|
|
inform_client = false;
|
|
|
|
upd_neigh = false;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Inform BGP if required. */
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
if (inform_client) {
|
|
|
|
if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
|
|
|
|
mac->flags, mac->loc_seq))
|
|
|
|
return -1;
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
/* Process all neighbors associated with this MAC, if required. */
|
|
|
|
if (upd_neigh)
|
|
|
|
zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to delete a remote VTEP for a VNI.
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
2018-03-27 21:13:34 +02:00
|
|
|
unsigned short l = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
|
|
|
struct in_addr vtep_ip;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2018-03-06 20:02:52 +01:00
|
|
|
"%s: EVPN is not enabled yet we have received a vtep del command",
|
|
|
|
__PRETTY_FUNCTION__);
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-10 14:51:34 +01:00
|
|
|
}
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_debug("Recv MACIP DEL for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2019-05-01 21:29:24 +02:00
|
|
|
int flood_control __attribute__((unused));
|
2019-05-01 03:29:03 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Obtain each remote VTEP and process. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += 4;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
2019-05-01 03:29:03 +02:00
|
|
|
/* Flood control is intentionally ignored right now */
|
|
|
|
STREAM_GETL(s, flood_control);
|
|
|
|
l += 4;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Recv VTEP_DEL %s VNI %u from %s",
|
|
|
|
inet_ntoa(vtep_ip), vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Failed to locate VNI hash upon remote VTEP DEL, "
|
2017-09-18 23:45:34 +02:00
|
|
|
"VNI %u",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-08-30 17:23:01 +02:00
|
|
|
"VNI %u hash %p doesn't have intf upon remote VTEP DEL",
|
|
|
|
zvni->vni, zvni);
|
2017-08-14 06:52:04 +02:00
|
|
|
continue;
|
2017-07-20 11:46:28 +02:00
|
|
|
}
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
continue;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* 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_neigh_del_from_vtep(zvni, 1, &vtep_ip);
|
|
|
|
zvni_mac_del_from_vtep(zvni, 1, &vtep_ip);
|
|
|
|
zvni_vtep_uninstall(zvni, &vtep_ip);
|
|
|
|
zvni_vtep_del(zvni, zvtep);
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to add a remote VTEP for a VNI.
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
2018-03-27 21:13:34 +02:00
|
|
|
unsigned short l = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
|
|
|
struct in_addr vtep_ip;
|
|
|
|
zebra_vni_t *zvni;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
2019-03-19 18:37:22 +01:00
|
|
|
int flood_control;
|
|
|
|
zebra_vtep_t *zvtep;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2018-03-06 20:02:52 +01:00
|
|
|
"%s: EVPN not enabled yet we received a vtep_add zapi call",
|
|
|
|
__PRETTY_FUNCTION__);
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-10 14:51:34 +01:00
|
|
|
}
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_debug("Recv MACIP ADD for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Obtain each remote VTEP and process. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += 4;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2019-03-19 18:37:22 +01:00
|
|
|
STREAM_GETL(s, flood_control);
|
2019-05-01 03:29:03 +02:00
|
|
|
l += IPV4_MAX_BYTELEN + 4;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-03-19 18:37:22 +01:00
|
|
|
zlog_debug("Recv VTEP_ADD %s VNI %u flood %d from %s",
|
|
|
|
inet_ntoa(vtep_ip), vni, flood_control,
|
|
|
|
zebra_route_string(client->proto));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_VTEP_ADD_FAILED,
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate VNI hash upon remote VTEP ADD, VNI %u",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
|
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_VTEP_ADD_FAILED,
|
2017-07-17 14:03:14 +02:00
|
|
|
"VNI %u hash %p doesn't have intf upon remote VTEP ADD",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
zif = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
|
2019-03-19 18:37:22 +01:00
|
|
|
zvtep = zvni_vtep_find(zvni, &vtep_ip);
|
|
|
|
if (zvtep) {
|
|
|
|
/* If the remote VTEP already exists check if
|
|
|
|
* the flood mode has changed
|
|
|
|
*/
|
|
|
|
if (zvtep->flood_control != flood_control) {
|
|
|
|
if (zvtep->flood_control
|
|
|
|
== VXLAN_FLOOD_DISABLED)
|
|
|
|
/* old mode was head-end-replication but
|
|
|
|
* is no longer; get rid of the HER fdb
|
|
|
|
* entry installed before
|
|
|
|
*/
|
|
|
|
zvni_vtep_uninstall(zvni, &vtep_ip);
|
|
|
|
zvtep->flood_control = flood_control;
|
|
|
|
zvni_vtep_install(zvni, zvtep);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
zvtep = zvni_vtep_add(zvni, &vtep_ip, flood_control);
|
|
|
|
if (zvtep)
|
|
|
|
zvni_vtep_install(zvni, zvtep);
|
|
|
|
else
|
|
|
|
flog_err(EC_ZEBRA_VTEP_ADD_FAILED,
|
|
|
|
"Failed to add remote VTEP, VNI %u zvni %p",
|
|
|
|
vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/*
|
|
|
|
* Add/Del gateway macip to evpn
|
|
|
|
* g/w can be:
|
|
|
|
* 1. SVI interface on a vlan aware bridge
|
|
|
|
* 2. SVI interface on a vlan unaware bridge
|
|
|
|
* 3. vrr interface (MACVLAN) associated to a SVI
|
|
|
|
* We advertise macip routes for an interface if it is associated to VxLan vlan
|
|
|
|
*/
|
|
|
|
int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
|
|
|
|
int add)
|
|
|
|
{
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
memset(&macaddr, 0, sizeof(struct ethaddr));
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-12 23:09:36 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
if (IS_ZEBRA_IF_MACVLAN(ifp)) {
|
|
|
|
struct interface *svi_if =
|
|
|
|
NULL; /* SVI corresponding to the MACVLAN */
|
|
|
|
struct zebra_if *ifp_zif =
|
|
|
|
NULL; /* Zebra daemon specific info for MACVLAN */
|
|
|
|
struct zebra_if *svi_if_zif =
|
|
|
|
NULL; /* Zebra daemon specific info for SVI*/
|
|
|
|
|
|
|
|
ifp_zif = ifp->info;
|
|
|
|
if (!ifp_zif)
|
|
|
|
return -1;
|
|
|
|
|
2017-08-20 02:28:58 +02:00
|
|
|
/*
|
|
|
|
* for a MACVLAN interface the link represents the svi_if
|
|
|
|
*/
|
|
|
|
svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
ifp_zif->link_ifindex);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!svi_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("MACVLAN %s(%u) without link information",
|
|
|
|
ifp->name, ifp->ifindex);
|
2017-06-28 10:51:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_IF_VLAN(svi_if)) {
|
2017-08-20 02:28:58 +02:00
|
|
|
/*
|
|
|
|
* If it is a vlan aware bridge then the link gives the
|
|
|
|
* bridge information
|
|
|
|
*/
|
|
|
|
struct interface *svi_if_link = NULL;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
svi_if_zif = svi_if->info;
|
2017-08-20 02:28:58 +02:00
|
|
|
if (svi_if_zif) {
|
|
|
|
svi_if_link = if_lookup_by_index_per_ns(
|
2017-08-30 17:23:01 +02:00
|
|
|
zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
svi_if_zif->link_ifindex);
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni = zvni_from_svi(svi_if, svi_if_link);
|
2017-08-20 02:28:58 +02:00
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
} else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
|
2017-08-20 02:28:58 +02:00
|
|
|
/*
|
|
|
|
* If it is a vlan unaware bridge then svi is the bridge
|
|
|
|
* itself
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni = zvni_from_svi(svi_if, svi_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
|
|
|
|
struct zebra_if *svi_if_zif =
|
2017-08-20 02:28:58 +02:00
|
|
|
NULL; /* Zebra daemon specific info for SVI */
|
|
|
|
struct interface *svi_if_link =
|
|
|
|
NULL; /* link info for the SVI = bridge info */
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
svi_if_zif = ifp->info;
|
2018-04-11 14:02:34 +02:00
|
|
|
if (svi_if_zif) {
|
|
|
|
svi_if_link = if_lookup_by_index_per_ns(
|
2018-04-11 17:25:32 +02:00
|
|
|
zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
svi_if_zif->link_ifindex);
|
2018-04-11 14:02:34 +02:00
|
|
|
if (svi_if_link)
|
|
|
|
zvni = zvni_from_svi(ifp, svi_if_link);
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
} else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni = zvni_from_svi(ifp, ifp);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!zvni->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("VNI %u hash %p doesn't have intf upon MACVLAN up",
|
|
|
|
zvni->vni, zvni);
|
2017-06-28 10:51:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
if (p->family == AF_INET) {
|
|
|
|
ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(ip.ipaddr_v4), &(p->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (p->family == AF_INET6) {
|
|
|
|
ip.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(ip.ipaddr_v6), &(p->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
|
|
|
|
else
|
|
|
|
zvni_gw_macip_del(ifp, zvni, &ip);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Handle SVI interface going down.
|
|
|
|
* SVI can be associated to either L3-VNI or L2-VNI.
|
|
|
|
* For L2-VNI: At this point, this is a NOP since
|
|
|
|
* the kernel deletes the neighbor entries on this SVI (if any).
|
|
|
|
* We only need to update the vrf corresponding to zvni.
|
|
|
|
* For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete
|
|
|
|
* from bgp
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni) {
|
|
|
|
|
|
|
|
/* process l3-vni down */
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
|
|
|
|
/* remove association with svi-if */
|
|
|
|
zl3vni->svi_if = NULL;
|
|
|
|
} else {
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
|
|
|
|
/* since we dont have svi corresponding to zvni, we associate it
|
|
|
|
* to default vrf. Note: the corresponding neigh entries on the
|
|
|
|
* SVI would have already been deleted */
|
|
|
|
zvni = zvni_from_svi(ifp, link_if);
|
|
|
|
if (zvni) {
|
|
|
|
zvni->vrf_id = VRF_DEFAULT;
|
|
|
|
|
|
|
|
/* update the tenant vrf in BGP */
|
|
|
|
zvni_send_add_to_client(zvni);
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Handle SVI interface coming up.
|
|
|
|
* SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni
|
|
|
|
* vxlan intf).
|
|
|
|
* For L2-VNI: we need to install any remote neighbors entried (used for
|
|
|
|
* apr-suppression)
|
|
|
|
* For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni) {
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* associate with svi */
|
|
|
|
zl3vni->svi_if = ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* process oper-up */
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* process SVI up for l2-vni */
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
|
|
|
zvni = zvni_from_svi(ifp, link_if);
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!zvni->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2018-06-19 20:29:05 +02:00
|
|
|
"VNI %u hash %p doesn't have intf upon SVI up",
|
|
|
|
zvni->vni, zvni);
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug(
|
|
|
|
"SVI %s(%u) VNI %u VRF %s is UP, installing neighbors",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
2019-06-24 01:46:39 +02:00
|
|
|
vrf_id_to_name(ifp->vrf_id));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* update the vrf information for l2-vni and inform bgp */
|
2019-06-24 01:46:39 +02:00
|
|
|
zvni->vrf_id = ifp->vrf_id;
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni_send_add_to_client(zvni);
|
|
|
|
|
|
|
|
/* Install any remote neighbors for this VNI. */
|
|
|
|
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
n_wctx.zvni = zvni;
|
2018-03-06 20:02:52 +01:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
|
2017-10-08 03:49:27 +02:00
|
|
|
&n_wctx);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Handle VxLAN interface down
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_down(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-01-25 00:25:03 +01:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
zebra_vni_t *zvni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-01-25 00:25:03 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-10-08 03:49:27 +02:00
|
|
|
/* process-if-down for l3-vni */
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name,
|
|
|
|
ifp->ifindex, vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
} else {
|
|
|
|
/* process if-down for l2-vni */
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name,
|
|
|
|
ifp->ifindex, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-10-08 03:49:27 +02:00
|
|
|
"Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
assert(zvni->vxlan_if == ifp);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Delete this VNI from BGP. */
|
|
|
|
zvni_send_del_to_client(zvni->vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Free up all neighbors and MACs, if any. */
|
|
|
|
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 1);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface up - update BGP if required.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_up(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-01-25 00:25:03 +01:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-01-25 00:25:03 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-10-08 03:49:27 +02:00
|
|
|
/* we need to associate with SVI, if any, we can associate with
|
2017-12-27 20:47:10 +01:00
|
|
|
* svi-if only after association with vxlan-intf is complete
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
2019-08-02 08:33:24 +02:00
|
|
|
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s"
|
|
|
|
, ifp->name, ifp->ifindex, vni,
|
|
|
|
zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
|
|
|
|
zl3vni->mac_vlan_if ?
|
|
|
|
zl3vni->mac_vlan_if->name : "NIL");
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
} else {
|
|
|
|
/* Handle L2-VNI add */
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name,
|
|
|
|
ifp->ifindex, vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Locate hash entry; it is expected to exist. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-10-08 03:49:27 +02:00
|
|
|
"Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(zvni->vxlan_if == ifp);
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (vlan_if) {
|
2019-06-24 01:46:39 +02:00
|
|
|
zvni->vrf_id = vlan_if->vrf_id;
|
|
|
|
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (zl3vni)
|
|
|
|
listnode_add_sort(zl3vni->l2vnis, zvni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If part of a bridge, inform BGP about this VNI. */
|
|
|
|
/* Also, read and populate local MACs and neighbors. */
|
|
|
|
if (zif->brslave_info.br_if) {
|
|
|
|
zvni_send_add_to_client(zvni);
|
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface delete. Locate and remove entry in hash table
|
|
|
|
* and update BGP, if required.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_del(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-01-25 00:25:03 +01:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-01-25 00:25:03 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name,
|
|
|
|
ifp->ifindex);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* process oper-down for l3-vni */
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* remove the association with vxlan_if */
|
2017-10-31 00:58:15 +01:00
|
|
|
memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr));
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vxlan_if = NULL;
|
|
|
|
} else {
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* process if-del for l2-vni*/
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name,
|
|
|
|
ifp->ifindex);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Locate hash entry; it is expected to exist. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-10-08 03:49:27 +02:00
|
|
|
"Failed to locate VNI hash at del, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove from l3-vni list */
|
|
|
|
zl3vni = zl3vni_from_vrf(zvni->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_delete(zl3vni->l2vnis, zvni);
|
|
|
|
|
|
|
|
/* Delete VNI from BGP. */
|
|
|
|
zvni_send_del_to_client(zvni->vni);
|
|
|
|
|
|
|
|
/* Free up all neighbors and MAC, if any. */
|
|
|
|
zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
|
|
|
|
|
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 0);
|
|
|
|
|
|
|
|
/* Delete the hash entry. */
|
|
|
|
if (zvni_del(zvni)) {
|
2018-09-13 21:21:05 +02:00
|
|
|
flog_err(EC_ZEBRA_VNI_DEL_FAILED,
|
2018-09-13 21:38:57 +02:00
|
|
|
"Failed to del VNI hash %p, IF %s(%u) VNI %u",
|
|
|
|
zvni, ifp->name, ifp->ifindex, zvni->vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface update - change to tunnel IP, master or VLAN.
|
|
|
|
*/
|
2018-03-27 21:13:34 +02:00
|
|
|
int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
vni_t vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-01-25 00:25:03 +01:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
|
|
|
|
2018-01-25 00:25:03 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-07-20 18:54:46 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Update L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x",
|
2018-03-06 20:02:52 +01:00
|
|
|
vni, ifp->name, ifp->ifindex, vxl->access_vlan,
|
|
|
|
inet_ntoa(vxl->vtep_ip),
|
2017-10-08 03:49:27 +02:00
|
|
|
zif->brslave_info.bridge_ifindex, chgflags);
|
|
|
|
|
|
|
|
/* Removed from bridge? Cleanup and return */
|
|
|
|
if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
|
|
|
|
&& (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* access-vlan change - process oper down, associate with new
|
2017-12-27 20:47:10 +01:00
|
|
|
* svi_if and then process oper up again
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
|
|
|
|
if (if_is_operative(ifp)) {
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
zl3vni->svi_if = NULL;
|
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
2019-08-02 08:33:24 +02:00
|
|
|
zl3vni->mac_vlan_if =
|
|
|
|
zl3vni_map_to_mac_vlan_if(zl3vni);
|
2018-01-23 03:12:13 +01:00
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
2017-10-08 03:49:27 +02:00
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(
|
2018-03-06 20:02:52 +01:00
|
|
|
zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-01-30 02:14:52 +01:00
|
|
|
/*
|
|
|
|
* local-ip change - process oper down, associate with new
|
|
|
|
* local-ip and then process oper up again
|
|
|
|
*/
|
|
|
|
if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) {
|
|
|
|
if (if_is_operative(ifp)) {
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(
|
2018-03-06 20:02:52 +01:00
|
|
|
zl3vni);
|
2018-01-30 02:14:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 03:12:13 +01:00
|
|
|
/* Update local tunnel IP. */
|
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
|
2018-01-30 02:14:52 +01:00
|
|
|
/* if we have a valid new master, process l3-vni oper up */
|
|
|
|
if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
|
|
|
|
if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni))
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
}
|
|
|
|
} else {
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Update VNI hash. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-10-08 03:49:27 +02:00
|
|
|
"Failed to find L2-VNI hash on update, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Update L2-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x",
|
2018-03-06 20:02:52 +01:00
|
|
|
vni, ifp->name, ifp->ifindex, vxl->access_vlan,
|
|
|
|
inet_ntoa(vxl->vtep_ip),
|
2017-10-08 03:49:27 +02:00
|
|
|
zif->brslave_info.bridge_ifindex, chgflags);
|
|
|
|
|
|
|
|
/* Removed from bridge? Cleanup and return */
|
|
|
|
if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
|
|
|
|
&& (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
|
|
|
|
/* Delete from client, remove all remote VTEPs */
|
|
|
|
/* Also, free up all MACs and neighbors. */
|
|
|
|
zvni_send_del_to_client(zvni->vni);
|
|
|
|
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
|
|
|
|
zvni_vtep_del_all(zvni, 1);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Handle other changes. */
|
|
|
|
if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
|
|
|
|
/* Remove all existing local neigh and MACs for this VNI
|
|
|
|
* (including from BGP)
|
|
|
|
*/
|
|
|
|
zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
|
|
|
|
zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-03-19 21:26:22 +01:00
|
|
|
if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
|
|
|
|
zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
|
|
|
|
zebra_vxlan_sg_deref(zvni->local_vtep_ip,
|
|
|
|
zvni->mcast_grp);
|
|
|
|
zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
|
|
|
|
zvni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zvni->mcast_grp = vxl->mcast_grp;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni->vxlan_if = ifp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* 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;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Inform BGP, if there is a change of interest. */
|
|
|
|
if (chgflags
|
2019-03-19 17:10:47 +01:00
|
|
|
& (ZEBRA_VXLIF_MASTER_CHANGE |
|
|
|
|
ZEBRA_VXLIF_LOCAL_IP_CHANGE |
|
|
|
|
ZEBRA_VXLIF_MCAST_GRP_CHANGE))
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni_send_add_to_client(zvni);
|
|
|
|
|
|
|
|
/* If there is a valid new master or a VLAN mapping change,
|
|
|
|
* read and populate local MACs and neighbors.
|
|
|
|
* Also, reinstall any remote MACs and neighbors
|
|
|
|
* for this VNI (based on new VLAN).
|
|
|
|
*/
|
|
|
|
if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
|
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
|
|
|
else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
|
|
|
|
struct mac_walk_ctx m_wctx;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
|
|
|
|
|
|
|
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
m_wctx.zvni = zvni;
|
2018-03-06 20:02:52 +01:00
|
|
|
hash_iterate(zvni->mac_table, zvni_install_mac_hash,
|
2017-10-08 03:49:27 +02:00
|
|
|
&m_wctx);
|
|
|
|
|
|
|
|
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
n_wctx.zvni = zvni;
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
|
|
|
|
&n_wctx);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface add.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_add(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
vni_t vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2018-01-25 00:25:03 +01:00
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-01-25 00:25:03 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* process if-add for l3-vni*/
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Add L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u",
|
2018-03-06 20:02:52 +01:00
|
|
|
vni, ifp->name, ifp->ifindex, vxl->access_vlan,
|
|
|
|
inet_ntoa(vxl->vtep_ip),
|
2017-10-08 03:49:27 +02:00
|
|
|
zif->brslave_info.bridge_ifindex);
|
|
|
|
|
|
|
|
/* associate with vxlan_if */
|
2017-10-31 00:58:15 +01:00
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vxlan_if = ifp;
|
|
|
|
|
|
|
|
/* Associate with SVI, if any. We can associate with svi-if only
|
|
|
|
* after association with vxlan_if is complete */
|
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* process if-add for l2-vni */
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
|
|
|
|
/* Create or update VNI hash. */
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni) {
|
|
|
|
zvni = zvni_add(vni);
|
|
|
|
if (!zvni) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 21:21:05 +02:00
|
|
|
EC_ZEBRA_VNI_ADD_FAILED,
|
2017-10-08 03:49:27 +02:00
|
|
|
"Failed to add VNI hash, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 21:26:22 +01:00
|
|
|
if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
|
|
|
|
zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
|
|
|
|
zebra_vxlan_sg_deref(zvni->local_vtep_ip,
|
|
|
|
zvni->mcast_grp);
|
|
|
|
zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
|
|
|
|
zvni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zvni->mcast_grp = vxl->mcast_grp;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
zvni->vxlan_if = ifp;
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (vlan_if) {
|
2019-06-24 01:46:39 +02:00
|
|
|
zvni->vrf_id = vlan_if->vrf_id;
|
|
|
|
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (zl3vni)
|
|
|
|
listnode_add_sort(zl3vni->l2vnis, zvni);
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:10:47 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN) {
|
|
|
|
char addr_buf1[INET_ADDRSTRLEN];
|
|
|
|
char addr_buf2[INET_ADDRSTRLEN];
|
|
|
|
|
|
|
|
inet_ntop(AF_INET, &vxl->vtep_ip,
|
|
|
|
addr_buf1, INET_ADDRSTRLEN);
|
|
|
|
inet_ntop(AF_INET, &vxl->mcast_grp,
|
|
|
|
addr_buf2, INET_ADDRSTRLEN);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zlog_debug(
|
2019-04-20 16:27:46 +02:00
|
|
|
"Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s mcast_grp %s master %u",
|
2017-10-08 03:49:27 +02:00
|
|
|
vni,
|
2019-06-24 01:46:39 +02:00
|
|
|
vlan_if ? vrf_id_to_name(vlan_if->vrf_id)
|
2018-12-17 18:56:36 +01:00
|
|
|
: VRF_DEFAULT_NAME,
|
2018-03-06 20:02:52 +01:00
|
|
|
ifp->name, ifp->ifindex, vxl->access_vlan,
|
2019-03-19 17:10:47 +01:00
|
|
|
addr_buf1, addr_buf2,
|
2017-10-08 03:49:27 +02:00
|
|
|
zif->brslave_info.bridge_ifindex);
|
2019-03-19 17:10:47 +01:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* 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(zvni);
|
|
|
|
|
|
|
|
/* Read and populate local MACs and neighbors */
|
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
|
|
|
|
char *err, int err_str_sz, int filter,
|
|
|
|
int add)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2019-03-06 19:10:02 +01:00
|
|
|
struct zebra_vrf *zvrf_evpn = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
zvrf_evpn = zebra_vrf_get_evpn();
|
|
|
|
if (!zvrf_evpn)
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("vrf %s vni %u %s", zvrf_name(zvrf), vni,
|
2017-10-08 03:49:27 +02:00
|
|
|
add ? "ADD" : "DEL");
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
|
|
|
|
zebra_vxlan_handle_vni_transition(zvrf, vni, add);
|
|
|
|
|
|
|
|
/* check if the vni is already present under zvrf */
|
|
|
|
if (zvrf->l3vni) {
|
2017-12-14 00:20:34 +01:00
|
|
|
snprintf(err, err_str_sz,
|
2017-10-08 03:49:27 +02:00
|
|
|
"VNI is already configured under the vrf");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if this VNI is already present in the system */
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-12-14 00:20:34 +01:00
|
|
|
snprintf(err, err_str_sz,
|
2017-10-08 03:49:27 +02:00
|
|
|
"VNI is already configured as L3-VNI");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add the L3-VNI to the global table */
|
|
|
|
zl3vni = zl3vni_add(vni, zvrf_id(zvrf));
|
|
|
|
if (!zl3vni) {
|
2018-03-06 20:02:52 +01:00
|
|
|
snprintf(err, err_str_sz, "Could not add L3-VNI");
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* associate the vrf with vni */
|
|
|
|
zvrf->l3vni = vni;
|
|
|
|
|
2018-02-06 23:28:22 +01:00
|
|
|
/* set the filter in l3vni to denote if we are using l3vni only
|
|
|
|
* for prefix routes
|
|
|
|
*/
|
|
|
|
if (filter)
|
|
|
|
SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* associate with vxlan-intf;
|
2017-12-27 20:47:10 +01:00
|
|
|
* we need to associate with the vxlan-intf first
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
|
|
|
|
|
|
|
|
/* associate with corresponding SVI interface, we can associate
|
|
|
|
* with svi-if only after vxlan interface association is
|
2017-12-27 20:47:10 +01:00
|
|
|
* complete
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: l3vni %u svi_if %s mac_vlan_if %s",
|
|
|
|
__PRETTY_FUNCTION__, vni,
|
|
|
|
zl3vni->svi_if ?
|
|
|
|
zl3vni->svi_if->name : "NIL",
|
|
|
|
zl3vni->mac_vlan_if ?
|
|
|
|
zl3vni->mac_vlan_if->name : "NIL");
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* formulate l2vni list */
|
2019-03-06 19:10:02 +01:00
|
|
|
hash_iterate(zvrf_evpn->vni_table, zvni_add_to_l3vni_list,
|
2018-03-06 20:02:52 +01:00
|
|
|
zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (!zl3vni) {
|
2017-12-14 00:20:34 +01:00
|
|
|
snprintf(err, err_str_sz, "VNI doesn't exist");
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-04-11 21:04:34 +02:00
|
|
|
if (zvrf->l3vni != vni) {
|
|
|
|
snprintf(err, err_str_sz,
|
|
|
|
"VNI %d doesn't exist in VRF: %s",
|
|
|
|
vni, zvrf->vrf->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-04-10 10:37:21 +02:00
|
|
|
if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) {
|
|
|
|
snprintf(err, ERR_STR_SZ,
|
|
|
|
"prefix-routes-only is not set for the vni");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
|
2017-10-18 10:46:40 +02:00
|
|
|
/* delete and uninstall all rmacs */
|
2018-03-06 20:02:52 +01:00
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry,
|
2017-10-18 10:46:40 +02:00
|
|
|
zl3vni);
|
|
|
|
|
|
|
|
/* delete and uninstall all next-hops */
|
2018-03-06 20:02:52 +01:00
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry,
|
2017-10-18 10:46:40 +02:00
|
|
|
zl3vni);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zvrf->l3vni = 0;
|
|
|
|
zl3vni_del(zl3vni);
|
|
|
|
|
|
|
|
zebra_vxlan_handle_vni_transition(zvrf, vni, add);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (!zl3vni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zl3vni->vrf_id = zvrf_id(zvrf);
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!zl3vni)
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
zl3vni->vrf_id = VRF_UNKNOWN;
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
vni_t vni;
|
|
|
|
|
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (!zl3vni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
vni = zl3vni->vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_del(zl3vni);
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
zebra_vxlan_handle_vni_transition(zvrf, vni, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2018-10-05 00:42:57 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to specify the flooding mechanism for
|
|
|
|
* BUM packets. The default is to do head-end (ingress) replication
|
|
|
|
* and the other supported option is to disable it. This applies to
|
|
|
|
* all BUM traffic and disabling it applies to both the transmit and
|
|
|
|
* receive direction.
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
enum vxlan_flood_control flood_ctrl;
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_err("EVPN flood control for non-EVPN VRF %u",
|
2018-10-05 00:42:57 +02:00
|
|
|
zvrf_id(zvrf));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = msg;
|
|
|
|
STREAM_GETC(s, flood_ctrl);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("EVPN flood control %u, currently %u",
|
|
|
|
flood_ctrl, zvrf->vxlan_flood_ctrl);
|
|
|
|
|
|
|
|
if (zvrf->vxlan_flood_ctrl == flood_ctrl)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvrf->vxlan_flood_ctrl = flood_ctrl;
|
|
|
|
|
|
|
|
/* Install or uninstall flood entries corresponding to
|
|
|
|
* remote VTEPs.
|
|
|
|
*/
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_handle_flooding_remote_vteps,
|
|
|
|
zvrf);
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-05 17:38:35 +01:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of svi macip
|
|
|
|
* routes
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-06-19 23:45:21 +02:00
|
|
|
zlog_debug("EVPN SVI-MACIP Adv for non-EVPN VRF %u",
|
2019-02-21 18:08:36 +01:00
|
|
|
zvrf_id(zvrf));
|
2019-02-05 17:38:35 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = msg;
|
|
|
|
STREAM_GETC(s, advertise);
|
|
|
|
STREAM_GETL(s, vni);
|
|
|
|
|
|
|
|
if (!vni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-06-19 23:45:21 +02:00
|
|
|
zlog_debug("EVPN SVI-MACIP Adv %s, currently %s",
|
2019-02-05 17:38:35 +01:00
|
|
|
advertise ? "enabled" : "disabled",
|
2019-08-08 19:43:49 +02:00
|
|
|
advertise_svi_macip_enabled(NULL)
|
2019-02-05 17:38:35 +01:00
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
|
|
|
if (zvrf->advertise_svi_macip == advertise)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (advertise) {
|
|
|
|
zvrf->advertise_svi_macip = advertise;
|
|
|
|
hash_iterate(zvrf->vni_table,
|
|
|
|
zvni_gw_macip_add_for_vni_hash, NULL);
|
|
|
|
} else {
|
|
|
|
hash_iterate(zvrf->vni_table,
|
|
|
|
zvni_svi_macip_del_for_vni_hash, NULL);
|
|
|
|
zvrf->advertise_svi_macip = advertise;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"EVPN SVI macip Adv %s on VNI %d , currently %s",
|
|
|
|
advertise ? "enabled" : "disabled", vni,
|
|
|
|
advertise_svi_macip_enabled(zvni)
|
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
|
|
|
if (zvni->advertise_svi_macip == advertise)
|
|
|
|
return;
|
|
|
|
|
2019-09-12 02:29:04 +02:00
|
|
|
/* Store flag even though SVI is not present.
|
|
|
|
* Once SVI comes up triggers self MAC-IP route add.
|
|
|
|
*/
|
|
|
|
zvni->advertise_svi_macip = advertise;
|
|
|
|
|
2019-02-05 17:38:35 +01:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (advertise) {
|
|
|
|
/* Add primary SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
|
|
|
} else {
|
2019-09-12 02:29:04 +02:00
|
|
|
/* Del primary SVI MAC-IP */
|
2019-02-05 17:38:35 +01:00
|
|
|
zvni_del_macip_for_intf(vlan_if, zvni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-20 06:47:04 +01:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of g/w macip
|
|
|
|
* routes
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
|
2017-11-20 06:47:04 +01:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2018-04-27 15:21:28 +02:00
|
|
|
STREAM_GETC(s, advertise);
|
2017-11-20 06:47:04 +01:00
|
|
|
vni = stream_get3(s);
|
|
|
|
|
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
if (zvni->advertise_subnet == advertise)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("EVPN subnet Adv %s on VNI %d , currently %s",
|
|
|
|
advertise ? "enabled" : "disabled", vni,
|
|
|
|
zvni->advertise_subnet ? "enabled" : "disabled");
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
|
|
|
|
zvni->advertise_subnet = advertise;
|
|
|
|
|
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
vlan_if =
|
|
|
|
zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
|
2017-11-20 06:47:04 +01:00
|
|
|
if (!vlan_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
if (zvni->advertise_subnet)
|
|
|
|
zvni_advertise_subnet(zvni, vlan_if, 1);
|
|
|
|
else
|
|
|
|
zvni_advertise_subnet(zvni, vlan_if, 0);
|
2018-04-27 15:21:28 +02:00
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of g/w macip
|
|
|
|
* routes
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
|
2018-08-16 22:10:32 +02:00
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, advertise);
|
2018-03-02 02:18:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
if (!vni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("EVPN gateway macip Adv %s, currently %s",
|
2017-06-28 10:51:10 +02:00
|
|
|
advertise ? "enabled" : "disabled",
|
2017-09-18 23:45:34 +02:00
|
|
|
advertise_gw_macip_enabled(NULL)
|
2017-06-28 10:51:10 +02:00
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
|
|
|
if (zvrf->advertise_gw_macip == advertise)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
zvrf->advertise_gw_macip = advertise;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (advertise_gw_macip_enabled(zvni))
|
2017-06-28 10:51:10 +02:00
|
|
|
hash_iterate(zvrf->vni_table,
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_gw_macip_add_for_vni_hash, NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
else
|
|
|
|
hash_iterate(zvrf->vni_table,
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_gw_macip_del_for_vni_hash, NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
|
|
|
|
2017-12-13 21:18:11 +01:00
|
|
|
zvni = zvni_lookup(vni);
|
|
|
|
if (!zvni)
|
2018-03-07 17:23:58 +01:00
|
|
|
return;
|
2017-12-13 21:18:11 +01:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"EVPN gateway macip Adv %s on VNI %d , currently %s",
|
2017-06-28 10:51:10 +02:00
|
|
|
advertise ? "enabled" : "disabled", vni,
|
2018-03-06 20:02:52 +01:00
|
|
|
advertise_gw_macip_enabled(zvni) ? "enabled"
|
|
|
|
: "disabled");
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
if (zvni->advertise_gw_macip == advertise)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
zvni->advertise_gw_macip = advertise;
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-07-20 11:46:28 +02:00
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-07-20 11:46:28 +02:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
|
2017-06-28 10:51:10 +02:00
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (advertise_gw_macip_enabled(zvni)) {
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Add primary SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_add_macip_for_intf(vrr_if, zvni);
|
|
|
|
} else {
|
|
|
|
/* Del primary MAC-IP */
|
|
|
|
zvni_del_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Del VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_del_macip_for_intf(vrr_if, zvni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
2018-10-05 00:42:57 +02:00
|
|
|
* This also informs the setting for BUM handling at the time this change
|
|
|
|
* occurs; it is relevant only when specifying "learn".
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-11-14 08:12:15 +01:00
|
|
|
struct stream *s = NULL;
|
|
|
|
int advertise = 0;
|
2018-10-05 00:42:57 +02:00
|
|
|
enum vxlan_flood_control flood_ctrl;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2019-03-22 11:18:31 +01:00
|
|
|
/* Mismatch between EVPN VRF and current VRF (should be prevented by
|
|
|
|
* bgpd's cli) */
|
2019-03-22 13:37:06 +01:00
|
|
|
if (is_evpn_enabled() && !EVPN_ENABLED(zvrf))
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, advertise);
|
2018-10-05 00:42:57 +02:00
|
|
|
STREAM_GETC(s, flood_ctrl);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-02-19 21:37:59 +01:00
|
|
|
zlog_debug("EVPN VRF %s(%u) VNI Adv %s, currently %s, flood control %u",
|
|
|
|
zvrf_name(zvrf), zvrf_id(zvrf),
|
2017-07-17 14:03:14 +02:00
|
|
|
advertise ? "enabled" : "disabled",
|
2018-10-05 00:42:57 +02:00
|
|
|
is_evpn_enabled() ? "enabled" : "disabled",
|
|
|
|
flood_ctrl);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvrf->advertise_all_vni == advertise)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvrf->advertise_all_vni = advertise;
|
2019-03-22 13:37:06 +01:00
|
|
|
if (EVPN_ENABLED(zvrf)) {
|
2019-03-27 02:16:27 +01:00
|
|
|
zrouter.evpn_vrf = zvrf;
|
2019-02-19 21:37:59 +01:00
|
|
|
|
2018-10-05 00:42:57 +02:00
|
|
|
/* Note BUM handling */
|
|
|
|
zvrf->vxlan_flood_ctrl = flood_ctrl;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Build VNI hash table and inform BGP. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_build_hash_table();
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Add all SVI (L3 GW) MACs to BGP*/
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash,
|
2017-09-18 23:45:34 +02:00
|
|
|
NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Read the MAC FDB */
|
|
|
|
macfdb_read(zvrf->zns);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Read neighbors */
|
|
|
|
neigh_read(zvrf->zns);
|
|
|
|
} else {
|
|
|
|
/* Cleanup VTEPs for all VNIs - uninstall from
|
|
|
|
* kernel and free entries.
|
|
|
|
*/
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
|
2017-11-14 08:12:15 +01:00
|
|
|
|
|
|
|
/* cleanup all l3vnis */
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL);
|
2019-02-19 21:37:59 +01:00
|
|
|
|
2019-03-27 02:16:27 +01:00
|
|
|
/* Mark as "no EVPN VRF" */
|
|
|
|
zrouter.evpn_vrf = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate VNI hash table for this VRF and do other initialization.
|
|
|
|
* NOTE: Currently supported only for default VRF.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp,
|
|
|
|
"Zebra VRF VNI Table");
|
2019-03-19 21:15:23 +01:00
|
|
|
zvrf->vxlan_sg_table = hash_create(zebra_vxlan_sg_hash_key_make,
|
|
|
|
zebra_vxlan_sg_hash_eq, "Zebra VxLAN SG Table");
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Cleanup VNI info, but don't free the table. */
|
|
|
|
void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
|
2019-03-19 21:26:22 +01:00
|
|
|
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/* Close all VNI handling */
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
|
2017-06-29 15:45:18 +02:00
|
|
|
hash_free(zvrf->vni_table);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* init the l3vni table */
|
2018-12-06 09:03:12 +01:00
|
|
|
void zebra_vxlan_init(void)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-08-27 16:43:37 +02:00
|
|
|
zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
|
|
|
|
"Zebra VRF L3 VNI table");
|
2019-03-27 02:16:27 +01:00
|
|
|
zrouter.evpn_vrf = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free l3vni table */
|
2018-12-06 09:03:12 +01:00
|
|
|
void zebra_vxlan_disable(void)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_free(zrouter.l3vni_table);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
/* get the l3vni svi ifindex */
|
|
|
|
ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return zl3vni->svi_if->ifindex;
|
|
|
|
}
|
2018-11-04 17:20:11 +01:00
|
|
|
|
|
|
|
static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
|
|
|
zebra_neigh_t *nbr = NULL;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
char buf2[ETHER_ADDR_STRLEN];
|
|
|
|
|
|
|
|
nbr = THREAD_ARG(t);
|
|
|
|
|
|
|
|
/* since this is asynchronous we need sanity checks*/
|
2019-02-23 01:19:18 +01:00
|
|
|
zvrf = vrf_info_lookup(nbr->zvni->vrf_id);
|
|
|
|
if (!zvrf)
|
2018-11-17 02:30:15 +01:00
|
|
|
return 0;
|
2018-11-04 17:20:11 +01:00
|
|
|
|
|
|
|
zvni = zvni_lookup(nbr->zvni->vni);
|
|
|
|
if (!zvni)
|
2018-11-17 02:30:15 +01:00
|
|
|
return 0;
|
2018-11-04 17:20:11 +01:00
|
|
|
|
2019-02-23 01:19:18 +01:00
|
|
|
nbr = zvni_neigh_lookup(zvni, &nbr->ip);
|
|
|
|
if (!nbr)
|
2018-11-17 02:30:15 +01:00
|
|
|
return 0;
|
2018-11-04 17:20:11 +01:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired",
|
|
|
|
__PRETTY_FUNCTION__,
|
2019-03-22 18:02:07 +01:00
|
|
|
prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)),
|
|
|
|
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
|
2018-11-04 17:20:11 +01:00
|
|
|
nbr->flags,
|
|
|
|
nbr->dad_count, zvni->vni);
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->detect_start_time.tv_usec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
nbr->dad_ip_auto_recovery_timer = NULL;
|
2019-03-22 18:02:07 +01:00
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(nbr);
|
2018-11-04 17:20:11 +01:00
|
|
|
|
|
|
|
/* Send to BGP */
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip, &nbr->emac,
|
|
|
|
nbr->flags, nbr->loc_seq);
|
|
|
|
} else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
zvni_neigh_install(zvni, nbr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
|
|
|
zebra_mac_t *mac = NULL;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
zebra_neigh_t *nbr = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
|
|
|
|
mac = THREAD_ARG(t);
|
|
|
|
|
|
|
|
/* since this is asynchronous we need sanity checks*/
|
2019-02-23 01:19:18 +01:00
|
|
|
zvrf = vrf_info_lookup(mac->zvni->vrf_id);
|
|
|
|
if (!zvrf)
|
2018-11-17 02:30:15 +01:00
|
|
|
return 0;
|
2018-11-04 17:20:11 +01:00
|
|
|
|
|
|
|
zvni = zvni_lookup(mac->zvni->vni);
|
|
|
|
if (!zvni)
|
2018-11-17 02:30:15 +01:00
|
|
|
return 0;
|
2018-11-04 17:20:11 +01:00
|
|
|
|
2019-02-23 01:19:18 +01:00
|
|
|
mac = zvni_mac_lookup(zvni, &mac->macaddr);
|
|
|
|
if (!mac)
|
2018-11-17 02:30:15 +01:00
|
|
|
return 0;
|
2018-11-04 17:20:11 +01:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
|
|
|
|
mac->flags,
|
|
|
|
mac->dad_count,
|
|
|
|
listcount(mac->neigh_list));
|
|
|
|
|
|
|
|
/* Remove all IPs as duplicate associcated with this MAC */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
|
2018-12-17 23:36:27 +01:00
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
2018-11-04 17:20:11 +01:00
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(nbr);
|
|
|
|
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
|
|
|
|
zvni_neigh_install(zvni, nbr);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
|
|
|
mac->dad_count = 0;
|
|
|
|
mac->detect_start_time.tv_sec = 0;
|
|
|
|
mac->detect_start_time.tv_usec = 0;
|
|
|
|
mac->dad_dup_detect_time = 0;
|
|
|
|
mac->dad_mac_auto_recovery_timer = NULL;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
/* Inform to BGP */
|
|
|
|
if (zvni_mac_send_add_to_client(zvni->vni, &mac->macaddr,
|
|
|
|
mac->flags, mac->loc_seq))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Process all neighbors associated with this MAC. */
|
|
|
|
zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
|
|
|
|
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
zvni_process_neigh_on_remote_mac_add(zvni, mac);
|
|
|
|
|
|
|
|
/* Install the entry. */
|
|
|
|
zvni_mac_install(zvni, mac);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-03-19 21:15:23 +01:00
|
|
|
|
|
|
|
/************************** vxlan SG cache management ************************/
|
2019-03-19 21:56:46 +01:00
|
|
|
/* Inform PIM about the mcast group */
|
2019-07-02 20:20:34 +02:00
|
|
|
static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg,
|
|
|
|
char *sg_str, uint16_t cmd)
|
2019-03-19 21:56:46 +01:00
|
|
|
{
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
struct stream *s = NULL;
|
|
|
|
|
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_PIM, 0);
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
if (!CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG))
|
|
|
|
return 0;
|
|
|
|
|
2019-03-19 21:56:46 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
|
|
|
|
|
|
|
zclient_create_header(s, cmd, VRF_DEFAULT);
|
|
|
|
stream_putl(s, IPV4_MAX_BYTELEN);
|
|
|
|
stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN);
|
|
|
|
stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN);
|
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Send %s %s to %s",
|
|
|
|
(cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", sg_str,
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
if (cmd == ZEBRA_VXLAN_SG_ADD)
|
|
|
|
client->vxlan_sg_add_cnt++;
|
|
|
|
else
|
|
|
|
client->vxlan_sg_del_cnt++;
|
|
|
|
|
|
|
|
return zserv_send_message(client, s);
|
|
|
|
}
|
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
2019-05-14 22:19:07 +02:00
|
|
|
const zebra_vxlan_sg_t *vxlan_sg = p;
|
2019-03-19 21:15:23 +01:00
|
|
|
|
|
|
|
return (jhash_2words(vxlan_sg->sg.src.s_addr,
|
|
|
|
vxlan_sg->sg.grp.s_addr, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
const zebra_vxlan_sg_t *sg1 = p1;
|
|
|
|
const zebra_vxlan_sg_t *sg2 = p2;
|
|
|
|
|
|
|
|
return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr)
|
|
|
|
&& (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
static zebra_vxlan_sg_t *zebra_vxlan_sg_new(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t *vxlan_sg;
|
|
|
|
|
|
|
|
vxlan_sg = XCALLOC(MTYPE_ZVXLAN_SG, sizeof(*vxlan_sg));
|
|
|
|
|
|
|
|
vxlan_sg->zvrf = zvrf;
|
|
|
|
vxlan_sg->sg = *sg;
|
|
|
|
prefix_sg2str(sg, vxlan_sg->sg_str);
|
|
|
|
|
|
|
|
vxlan_sg = hash_get(zvrf->vxlan_sg_table, vxlan_sg, hash_alloc_intern);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("vxlan SG %s created", vxlan_sg->sg_str);
|
|
|
|
|
|
|
|
return vxlan_sg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static zebra_vxlan_sg_t *zebra_vxlan_sg_find(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t lookup;
|
|
|
|
|
|
|
|
lookup.sg = *sg;
|
|
|
|
return hash_lookup(zvrf->vxlan_sg_table, &lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
static zebra_vxlan_sg_t *zebra_vxlan_sg_add(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t *vxlan_sg;
|
|
|
|
zebra_vxlan_sg_t *parent = NULL;
|
|
|
|
struct in_addr sip;
|
|
|
|
|
|
|
|
vxlan_sg = zebra_vxlan_sg_find(zvrf, sg);
|
|
|
|
if (vxlan_sg)
|
|
|
|
return vxlan_sg;
|
|
|
|
|
|
|
|
/* create a *G entry for every BUM group implicitly -
|
|
|
|
* 1. The SG entry is used by pimd to setup the vxlan-origination-mroute
|
|
|
|
* 2. the XG entry is used by pimd to setup the
|
|
|
|
* vxlan-termination-mroute
|
|
|
|
*/
|
|
|
|
if (sg->src.s_addr) {
|
|
|
|
memset(&sip, 0, sizeof(sip));
|
|
|
|
parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp);
|
|
|
|
if (!parent)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vxlan_sg = zebra_vxlan_sg_new(zvrf, sg);
|
|
|
|
if (!vxlan_sg) {
|
|
|
|
if (parent)
|
|
|
|
zebra_vxlan_sg_do_deref(zvrf, sip, sg->grp);
|
|
|
|
return vxlan_sg;
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
zebra_vxlan_sg_send(zvrf, sg, vxlan_sg->sg_str,
|
|
|
|
ZEBRA_VXLAN_SG_ADD);
|
2019-03-19 21:56:46 +01:00
|
|
|
|
2019-03-19 21:15:23 +01:00
|
|
|
return vxlan_sg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_sg_del(zebra_vxlan_sg_t *vxlan_sg)
|
|
|
|
{
|
|
|
|
struct in_addr sip;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* On SG entry deletion remove the reference to its parent XG
|
|
|
|
* entry
|
|
|
|
*/
|
|
|
|
if (vxlan_sg->sg.src.s_addr) {
|
|
|
|
memset(&sip, 0, sizeof(sip));
|
|
|
|
zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp);
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg,
|
|
|
|
vxlan_sg->sg_str, ZEBRA_VXLAN_SG_DEL);
|
2019-03-19 21:56:46 +01:00
|
|
|
|
2019-03-19 21:15:23 +01:00
|
|
|
hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VXLAN SG %s deleted", vxlan_sg->sg_str);
|
|
|
|
|
|
|
|
XFREE(MTYPE_ZVXLAN_SG, vxlan_sg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
|
|
|
|
struct in_addr sip, struct in_addr mcast_grp)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t *vxlan_sg;
|
|
|
|
struct prefix_sg sg;
|
|
|
|
|
|
|
|
sg.family = AF_INET;
|
|
|
|
sg.prefixlen = IPV4_MAX_BYTELEN;
|
|
|
|
sg.src = sip;
|
|
|
|
sg.grp = mcast_grp;
|
|
|
|
vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg);
|
|
|
|
if (!vxlan_sg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (vxlan_sg->ref_cnt)
|
|
|
|
--vxlan_sg->ref_cnt;
|
|
|
|
|
|
|
|
if (!vxlan_sg->ref_cnt)
|
|
|
|
zebra_vxlan_sg_del(vxlan_sg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf,
|
|
|
|
struct in_addr sip, struct in_addr mcast_grp)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t *vxlan_sg;
|
|
|
|
struct prefix_sg sg;
|
|
|
|
|
|
|
|
sg.family = AF_INET;
|
|
|
|
sg.prefixlen = IPV4_MAX_BYTELEN;
|
|
|
|
sg.src = sip;
|
|
|
|
sg.grp = mcast_grp;
|
|
|
|
vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg);
|
|
|
|
if (vxlan_sg)
|
|
|
|
++vxlan_sg->ref_cnt;
|
|
|
|
|
|
|
|
return vxlan_sg;
|
|
|
|
}
|
2019-03-19 21:26:22 +01:00
|
|
|
|
|
|
|
static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
|
|
|
|
struct in_addr mcast_grp)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
|
|
|
|
struct in_addr mcast_grp)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
|
|
|
|
|
|
|
|
zebra_vxlan_sg_del(vxlan_sg);
|
|
|
|
}
|
2019-06-19 23:45:21 +02:00
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
static void zebra_vxlan_sg_replay_send(struct hash_backet *backet, void *arg)
|
|
|
|
{
|
|
|
|
zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
|
|
|
|
|
|
|
|
zebra_vxlan_sg_send(vxlan_sg->zvrf, &vxlan_sg->sg,
|
|
|
|
vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle message from client to replay vxlan SG entries */
|
|
|
|
void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VxLAN SG updates to PIM, start");
|
|
|
|
|
|
|
|
SET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
|
|
|
|
|
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-07-17 02:17:05 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VxLAN SG replay request on unexpected vrf %d",
|
|
|
|
zvrf->vrf->vrf_id);
|
2019-07-02 20:20:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_replay_send, NULL);
|
|
|
|
}
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/************************** EVPN BGP config management ************************/
|
|
|
|
/* Notify Local MACs to the clienti, skips GW MAC */
|
|
|
|
static void zvni_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct mac_walk_ctx *wctx = arg;
|
|
|
|
zebra_mac_t *zmac = bucket->data;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
zvni_mac_send_add_to_client(wctx->zvni->vni, &zmac->macaddr,
|
|
|
|
zmac->flags, zmac->loc_seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterator to Notify Local MACs of a L2VNI */
|
|
|
|
static void zvni_send_mac_to_client(zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct mac_walk_ctx wctx;
|
|
|
|
|
|
|
|
if (!zvni->mac_table)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
|
|
|
|
hash_iterate(zvni->mac_table, zvni_send_mac_hash_entry_to_client,
|
|
|
|
&wctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify Neighbor entries to the Client, skips the GW entry */
|
|
|
|
static void zvni_send_neigh_hash_entry_to_client(struct hash_bucket *bucket,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct mac_walk_ctx *wctx = arg;
|
|
|
|
zebra_neigh_t *zn = bucket->data;
|
|
|
|
zebra_mac_t *zmac = NULL;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL) &&
|
|
|
|
IS_ZEBRA_NEIGH_ACTIVE(zn)) {
|
|
|
|
zmac = zvni_mac_lookup(wctx->zvni, &zn->emac);
|
|
|
|
if (!zmac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvni_neigh_send_add_to_client(wctx->zvni->vni, &zn->ip,
|
|
|
|
&zn->emac, zn->flags,
|
|
|
|
zn->loc_seq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterator of a specific L2VNI */
|
|
|
|
static void zvni_send_neigh_to_client(zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
|
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_send_neigh_hash_entry_to_client,
|
|
|
|
&wctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zvni_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
|
|
|
|
zvni = (zebra_vni_t *)bucket->data;
|
|
|
|
zvni->advertise_gw_macip = 0;
|
|
|
|
zvni->advertise_svi_macip = 0;
|
|
|
|
zvni->advertise_subnet = 0;
|
|
|
|
|
2019-06-28 19:42:08 +02:00
|
|
|
zvni_neigh_del_all(zvni, 1, 0,
|
2019-06-19 23:45:21 +02:00
|
|
|
DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP);
|
2019-06-28 19:42:08 +02:00
|
|
|
zvni_mac_del_all(zvni, 1, 0,
|
2019-06-19 23:45:21 +02:00
|
|
|
DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP);
|
2019-06-28 19:42:08 +02:00
|
|
|
zvni_vtep_del_all(zvni, 1);
|
2019-06-19 23:45:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup EVPN configuration of a specific VRF */
|
|
|
|
static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2019-06-28 19:42:08 +02:00
|
|
|
zebra_l3vni_t *zl3vni = NULL;
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
zvrf->advertise_all_vni = 0;
|
|
|
|
zvrf->advertise_gw_macip = 0;
|
|
|
|
zvrf->advertise_svi_macip = 0;
|
|
|
|
zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_evpn_cfg_cleanup, NULL);
|
2019-06-28 19:42:08 +02:00
|
|
|
|
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (zl3vni) {
|
|
|
|
/* delete and uninstall all rmacs */
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry,
|
|
|
|
zl3vni);
|
|
|
|
/* delete and uninstall all next-hops */
|
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry,
|
|
|
|
zl3vni);
|
|
|
|
}
|
2019-06-19 23:45:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup BGP EVPN configuration upon client disconnect */
|
2019-07-02 20:20:34 +02:00
|
|
|
static int zebra_evpn_bgp_cfg_clean_up(struct zserv *client)
|
2019-06-19 23:45:21 +02:00
|
|
|
{
|
|
|
|
struct vrf *vrf;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
|
|
|
|
zvrf = vrf->info;
|
|
|
|
if (zvrf)
|
|
|
|
zebra_evpn_vrf_cfg_cleanup(zvrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
static int zebra_evpn_pim_cfg_clean_up(struct zserv *client)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = zebra_vrf_get_evpn();
|
|
|
|
|
|
|
|
if (CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VxLAN SG updates to PIM, stop");
|
|
|
|
UNSET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_evpn_cfg_clean_up(struct zserv *client)
|
|
|
|
{
|
|
|
|
if (client->proto == ZEBRA_ROUTE_BGP)
|
|
|
|
return zebra_evpn_bgp_cfg_clean_up(client);
|
|
|
|
|
|
|
|
if (client->proto == ZEBRA_ROUTE_PIM)
|
|
|
|
return zebra_evpn_pim_cfg_clean_up(client);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-30 17:54:07 +02:00
|
|
|
/*
|
|
|
|
* Handle results for vxlan dataplane operations.
|
|
|
|
*/
|
|
|
|
extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx)
|
|
|
|
{
|
|
|
|
/* TODO -- anything other than freeing the context? */
|
|
|
|
dplane_ctx_fini(&ctx);
|
|
|
|
}
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/* Cleanup BGP EVPN configuration upon client disconnect */
|
|
|
|
extern void zebra_evpn_init(void)
|
|
|
|
{
|
|
|
|
hook_register(zserv_client_close, zebra_evpn_cfg_clean_up);
|
|
|
|
}
|