zebra: Uninstall remote MACs from kernel appropriately

When a remote MAC goes away, but there are neighbors referring to it,
ensure that when the last remote neighbor goes away, the MAC is
uninstalled from the kernel and no longer considered as remote.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by:   Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Reviewed-by:   Chirag Shah <chirag@cumulusnetworks.com>

Ticket: CM-22130
Reviewed By: CCR-7777
Testing Done:
1. Replicated failed scenario and verified with fix.
2. evpn-min
This commit is contained in:
vivek 2018-08-28 17:22:04 -07:00 committed by Donald Sharp
parent d63c1b18b4
commit fe697c6be5

View file

@ -180,8 +180,8 @@ 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);
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
int uninstall);
static int remote_neigh_count(zebra_mac_t *zmac);
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac);
/* Private functions */
static int host_rb_entry_compare(const struct host_rb_entry *hle1,
@ -1876,7 +1876,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
/* see if the mac needs to be deleted as well*/
if (mac)
zvni_deref_ip2mac(zvni, mac, 0);
zvni_deref_ip2mac(zvni, mac);
return 0;
}
@ -2062,7 +2062,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
neigh_mac_change = upd_mac_seq = true;
listnode_delete(
old_zmac->neigh_list, n);
zvni_deref_ip2mac(zvni, old_zmac, 0);
zvni_deref_ip2mac(zvni, old_zmac);
}
/* Update the forwarding info. */
@ -2090,7 +2090,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
neigh_mac_change = upd_mac_seq = true;
listnode_delete(old_zmac->neigh_list,
n);
zvni_deref_ip2mac(zvni, old_zmac, 0);
zvni_deref_ip2mac(zvni, old_zmac);
}
/* Link to new MAC */
@ -2654,21 +2654,44 @@ static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt)
zvni_mac_install(wctx->zvni, mac);
}
/*
* 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;
}
/*
* Decrement neighbor refcount of MAC; uninstall and free it if
* appropriate.
*/
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
int uninstall)
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
{
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)
|| !list_isempty(mac->neigh_list))
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
return;
if (uninstall)
/* 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) {
zvni_mac_uninstall(zvni, mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
}
zvni_mac_del(zvni, mac);
/* If no neighbors, delete the MAC. */
if (list_isempty(mac->neigh_list))
zvni_mac_del(zvni, mac);
}
/*
@ -4261,7 +4284,7 @@ static void process_remote_macip_add(vni_t vni,
old_mac = zvni_mac_lookup(zvni, &n->emac);
if (old_mac) {
listnode_delete(old_mac->neigh_list, n);
zvni_deref_ip2mac(zvni, old_mac, 1);
zvni_deref_ip2mac(zvni, old_mac);
}
listnode_add_sort(mac->neigh_list, n);
memcpy(&n->emac, macaddr, ETH_ALEN);
@ -4373,16 +4396,22 @@ static void process_remote_macip_del(vni_t vni,
&& (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
zvni_neigh_uninstall(zvni, n);
zvni_neigh_del(zvni, n);
zvni_deref_ip2mac(zvni, mac, 1);
zvni_deref_ip2mac(zvni, mac);
}
} else {
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zvni_process_neigh_on_remote_mac_del(zvni, mac);
if (list_isempty(mac->neigh_list)) {
/* If all remote neighbors referencing a remote MAC
* go away, we need to uninstall the MAC.
*/
if (remote_neigh_count(mac) == 0) {
zvni_mac_uninstall(zvni, mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
}
if (list_isempty(mac->neigh_list))
zvni_mac_del(zvni, mac);
} else
else
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
}