#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_vxlan_private.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint32_t seq, uint16_t cmd);
+ uint32_t seq, int state, uint16_t cmd);
static unsigned int neigh_hash_keymake(void *p);
static void *zvni_neigh_alloc(void *p);
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
uint8_t flags, uint32_t seq);
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr,
- uint8_t flags);
+ uint8_t flags, int state);
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);
+static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n);
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
struct interface *br_if);
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
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);
-static void zvni_build_hash_table();
+static void zvni_build_hash_table(void);
static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep);
static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip);
static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip);
struct ipaddr *ip);
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
+static int advertise_svi_macip_enabled(zebra_vni_t *zvni);
static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
zebra_mac_t *old_zmac,
zebra_mac_t *new_zmac,
return 0;
}
+static int advertise_svi_macip_enabled(zebra_vni_t *zvni)
+{
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (zvrf && zvrf->advertise_svi_macip)
+ return 1;
+
+ if (zvni && zvni->advertise_svi_macip)
+ return 1;
+
+ return 0;
+}
+
/* As part Duplicate Address Detection (DAD) for IP mobility
* MAC binding changes, ensure to inherit duplicate flag
* from MAC.
sizeof(buf)),
mac->flags, zvrf->dad_freeze_time);
- thread_add_timer(zebrad.master,
+ thread_add_timer(zrouter.master,
zebra_vxlan_dad_mac_auto_recovery_exp,
mac, zvrf->dad_freeze_time,
&mac->dad_mac_auto_recovery_timer);
if (zvrf->dad_freeze)
*is_dup_detect = true;
+
/* warn-only action, neigh will be installed.
* freeze action, it wil not be installed.
*/
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
nbr->flags, zvrf->dad_freeze_time);
- thread_add_timer(zebrad.master,
+ thread_add_timer(zrouter.master,
zebra_vxlan_dad_ip_auto_recovery_exp,
nbr, zvrf->dad_freeze_time,
&nbr->dad_ip_auto_recovery_timer);
struct zebra_vrf *zvrf = NULL;
struct timeval detect_start_time = {0, 0};
- zvrf = zebra_vrf_lookup_by_id(n->zvni->vrf_id);
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
if (!zvrf)
return;
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
ipaddr2str(&n->ip, buf2, sizeof(buf2));
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ?
struct zebra_vrf *zvrf;
struct timeval detect_start_time = {0, 0};
- zvrf = zebra_vrf_lookup_by_id(mac->zvni->vrf_id);
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
vty = (struct vty *)ctxt;
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
*/
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint32_t seq, uint16_t cmd)
+ uint32_t seq, int state, uint16_t cmd)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
if (cmd == ZEBRA_MACIP_ADD) {
stream_putc(s, flags); /* sticky mac/gateway mac */
stream_putl(s, seq); /* sequence number */
+ } else {
+ stream_putl(s, state); /* state - active/inactive */
}
&& IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, n->state);
if (wctx->uninstall)
zvni_neigh_uninstall(wctx->zvni, n);
struct zebra_vrf *zvrf = NULL;
char buf[ETHER_ADDR_STRLEN];
- zvrf = vrf_info_lookup(zvni->vrf_id);
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
}
}
}
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
}
}
}
/* NOTE: Currently a NO-OP. */
}
+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);
+ }
+}
+
/*
* Inform BGP about local neighbor addition.
*/
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- seq, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
}
/*
* Inform BGP about local neighbor deletion.
*/
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr, uint8_t flags)
+ struct ethaddr *macaddr, uint8_t flags,
+ int state)
{
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- 0, ZEBRA_MACIP_DEL);
+ 0, state, ZEBRA_MACIP_DEL);
}
/*
return kernel_del_neigh(vlan_if, &n->ip);
}
+/*
+ * 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;
+
+#ifdef GNU_LINUX
+ return kernel_upd_neigh(vlan_if, &n->ip, &n->emac,
+ 0, NUD_PROBE);
+#else
+ return 0;
+#endif
+}
+
/*
* Install neighbor hash entry - called upon access VLAN change.
*/
/* Remove neighbor from BGP. */
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
- ZEBRA_MACIP_TYPE_GW);
+ ZEBRA_MACIP_TYPE_GW, ZEBRA_NEIGH_ACTIVE);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
/* 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);
+ 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;
+}
+
+static void zvni_svi_macip_del_for_vni_hash(struct hash_backet *backet,
+ 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*/
+ zvni = (zebra_vni_t *)backet->data;
+ if (!zvni)
+ return;
+
+ 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);
return;
}
}
}
- zvrf = vrf_info_lookup(zvni->vrf_id);
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (!zvrf)
return -1;
*/
if (IS_ZEBRA_NEIGH_ACTIVE(n))
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, n->state);
old_zmac = zvni_mac_lookup(zvni, &n->emac);
if (old_zmac) {
old_mac_seq = CHECK_FLAG(old_zmac->flags,
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- seq, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
}
/*
static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
{
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
- 0 /* seq */, ZEBRA_MACIP_DEL);
+ 0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL);
}
/*
* Build the VNI hash table by going over the VxLAN interfaces. This
* is called when EVPN (advertise-all-vni) is enabled.
*/
-static void zvni_build_hash_table()
+static void zvni_build_hash_table(void)
{
struct zebra_ns *zns;
struct route_node *rn;
* RFC-7432: A PE/VTEP that detects a MAC mobility
* event via local learning starts an M-second timer.
*
- * VTEP-IP or seq. change along is not considered
+ * VTEP-IP or seq. change alone is not considered
* for dup. detection.
+ *
+ * MAC is already marked duplicate set dad, then
+ * is_dup_detect will be set to not install the entry.
*/
- if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) &&
- mac->dad_count)
+ if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
+ mac->dad_count) ||
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
do_dad = true;
/* Remove local MAC from BGP. */
IS_ZEBRA_NEIGH_ACTIVE(n))
zvni_neigh_send_del_to_client(
zvni->vni, &n->ip,
- &n->emac, 0);
+ &n->emac, 0, n->state);
/* update neigh list for macs */
old_mac = zvni_mac_lookup(zvni, &n->emac);
zvni_neigh_install(zvni, n);
}
+ zvni_probe_neigh_on_mac_add(zvni, mac);
+
/* Update seq number. */
n->rem_seq = seq;
}
zebra_neigh_t *n = NULL;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
+ struct zebra_ns *zns;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_vrf *zvrf;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
vni);
return;
}
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ vxl = &zif->l2info.vxl;
/* The remote VTEP specified is normally expected to exist, but
* it is possible that the peer may delete the VTEP before deleting
if (!mac && !n)
return;
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+
/* Ignore the delete if this mac is a gateway mac-ip */
- if (mac
- && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
&& CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
zlog_warn(
"Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
/* Uninstall remote neighbor or MAC. */
if (n) {
+ 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)
+ 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->name);
+ neigh_read_specific_ip(ipaddr, vlan_if);
+ }
+
/* 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).
zvni_deref_ip2mac(zvni, mac);
}
} else {
+ /* 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);
+ }
+
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zvni_process_neigh_on_remote_mac_del(zvni, mac);
/*
vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
vty_out(vty, "Advertise gateway mac-ip: %s\n",
zvrf->advertise_gw_macip ? "Yes" : "No");
+ vty_out(vty, "Advertise svi mac-ip: %s\n",
+ zvrf->advertise_svi_macip ? "Yes" : "No");
vty_out(vty, "Duplicate address detection: %s\n",
zvrf->dup_addr_detect ? "Enable" : "Disable");
vty_out(vty, " Detection max-moves %u, time %d\n",
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "%s: duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
- __PRETTY_FUNCTION__,
+ "VRF %s duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
+ vrf_id_to_name(zvrf->vrf->vrf_id),
zvrf->dup_addr_detect ? "enable" : "disable",
zvrf->dad_max_moves,
zvrf->dad_time,
zebra_vni_t *zvni = NULL;
zebra_mac_t *zmac = NULL;
zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_vrf *zvrf;
/* check if this is a remote neigh entry corresponding to remote
* next-hop
return 0;
}
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ 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);
+
/* Remove neighbor from BGP. */
- if (IS_ZEBRA_NEIGH_ACTIVE(n))
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0);
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0, n->state);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
return;
}
+/*
+ * 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;
+
+ if (zvrf_id(zvrf) != VRF_DEFAULT) {
+ zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u",
+ zvrf_id(zvrf));
+ return;
+ }
+
+ s = msg;
+ STREAM_GETC(s, advertise);
+ STREAM_GETL(s, vni);
+
+ if (!vni) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("EVPN gateway macip Adv %s, currently %s",
+ advertise ? "enabled" : "disabled",
+ advertise_gw_macip_enabled(NULL)
+ ? "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;
+
+ 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) {
+ zvni->advertise_svi_macip = advertise;
+ /* Add primary SVI MAC-IP */
+ zvni_add_macip_for_intf(vlan_if, zvni);
+ } else {
+ /* Del primary MAC-IP */
+ zvni_del_macip_for_intf(vlan_if, zvni);
+ zvni->advertise_svi_macip = advertise;
+ }
+ }
+
+stream_failure:
+ return;
+}
+
/*
* Handle message from client to enable/disable advertisement of g/w macip
* routes
nbr = THREAD_ARG(t);
/* since this is asynchronous we need sanity checks*/
- zvrf = vrf_info_lookup(nbr->zvni->vrf_id);
- if (!zvrf)
+ nbr = zvni_neigh_lookup(zvni, &nbr->ip);
+ if (!nbr)
return 0;
zvni = zvni_lookup(nbr->zvni->vni);
if (!zvni)
return 0;
- nbr = zvni_neigh_lookup(zvni, &nbr->ip);
- if (!nbr)
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
mac = THREAD_ARG(t);
/* since this is asynchronous we need sanity checks*/
- zvrf = vrf_info_lookup(mac->zvni->vrf_id);
- if (!zvrf)
+ mac = zvni_mac_lookup(zvni, &mac->macaddr);
+ if (!mac)
return 0;
zvni = zvni_lookup(mac->zvni->vni);
if (!zvni)
return 0;
- mac = zvni_mac_lookup(zvni, &mac->macaddr);
- if (!mac)
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)