zebra: support for slow-failover of local MACs on an ES

When a local ES flaps there are two modes in which the local
MACs are failed over -
1. Fast failover - A backup NHG (ES-peer group) is programmed in the
dataplane per-access port. When a local ES flaps the MAC entries
are left unaltered i.e. pointing to the down access port. And the
dataplane redirects traffic destined to the oper-down access port
via the backup NHG.
2. Slow failover - This mode needs to be turned on to allow dataplanes
not capable of re-directing traffic. In this mode local MAC entries
on a down local ES are re-programmed to point to the ES-peers'
NHG. And vice-versa i.e. when the ES comes up the MAC entries
are re-programmed with the access port as dest.

Fast failover is on by default. Slow failover can be enabled via the
following config -
evpn mh redirect-off

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
Anuradha Karuppiah 2020-05-08 18:47:52 -07:00 committed by Anuradha Karuppiah
parent 69711b3f83
commit 15400f95b7
8 changed files with 346 additions and 76 deletions

View File

@ -2956,8 +2956,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
}
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac,
vid);
return zebra_vxlan_dp_network_mac_add(
ifp, br_if, &mac, vid, nhg_id, sticky,
!!(ndm->ndm_flags & NTF_EXT_LEARNED));
return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
sticky, local_inactive, dp_static);
@ -2985,8 +2986,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
}
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac,
vid);
return zebra_vxlan_dp_network_mac_del(ifp, br_if, &mac, vid);
return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
}

View File

@ -108,9 +108,6 @@ int zebra_evpn_rem_mac_install(zebra_evpn_t *zevpn, zebra_mac_t *mac,
uint32_t nhg_id;
struct in_addr vtep_ip;
if (!(mac->flags & ZEBRA_MAC_REMOTE))
return 0;
zif = zevpn->vxlan_if->info;
if (!zif)
return -1;
@ -165,9 +162,6 @@ int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevpn, zebra_mac_t *mac,
vlanid_t vid;
enum zebra_dplane_result res;
if (!(mac->flags & ZEBRA_MAC_REMOTE))
return 0;
/* If the MAC was not installed there is no need to uninstall it */
if (!force && mac->es && !(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
return -1;
@ -1187,10 +1181,9 @@ struct hash *zebra_mac_db_create(const char *desc)
}
/* program sync mac flags in the dataplane */
void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
bool force_clear_static, const char *caller)
int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
bool force_clear_static, const char *caller)
{
char macbuf[ETHER_ADDR_STRLEN];
struct interface *ifp;
bool sticky;
bool set_static;
@ -1205,13 +1198,11 @@ void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
if (!ifp) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no access-port",
caller, zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf,
sizeof(macbuf)),
"%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no access-port",
caller, zevpn->vni, &mac->macaddr,
mac->es ? mac->es->esi_str : "-", mac->flags,
set_inactive ? "inactive " : "");
return;
return -1;
}
zif = ifp->info;
@ -1219,13 +1210,11 @@ void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
if (!br_ifp) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no br",
caller, zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf,
sizeof(macbuf)),
"%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no br",
caller, zevpn->vni, &mac->macaddr,
mac->es ? mac->es->esi_str : "-", mac->flags,
set_inactive ? "inactive " : "");
return;
return -1;
}
sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
@ -1234,17 +1223,42 @@ void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
else
set_static = zebra_evpn_mac_is_static(mac);
/* We can install a local mac that has been synced from the peer
* over the VxLAN-overlay/network-port if fast failover is not
* supported and if the local ES is oper-down.
*/
if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"dp-%s sync-nw-mac vni %u mac %pEA es %s 0x%x %s",
set_static ? "install" : "uninstall",
zevpn->vni, &mac->macaddr,
mac->es ? mac->es->esi_str : "-", mac->flags,
set_inactive ? "inactive " : "");
if (set_static)
/* XXX - old_static needs to be computed more
* accurately
*/
zebra_evpn_rem_mac_install(zevpn, mac,
true /* old_static */);
else
zebra_evpn_rem_mac_uninstall(zevpn, mac,
false /* force */);
return 0;
}
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"dp-install sync-mac vni %u mac %s es %s 0x%x %s%s",
zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
"dp-install sync-mac vni %u mac %pEA es %s 0x%x %s%s",
zevpn->vni, &mac->macaddr,
mac->es ? mac->es->esi_str : "-", mac->flags,
set_static ? "static " : "",
set_inactive ? "inactive " : "");
dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
set_static, set_inactive);
return 0;
}
void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready,

View File

@ -173,7 +173,6 @@ struct sync_mac_ip_ctx {
zebra_mac_t *mac;
};
/**************************** SYNC MAC handling *****************************/
/**************************** SYNC MAC handling *****************************/
/* if the mac has been added of a mac-route from the peer
* or if it is being referenced by a neigh added by the
@ -219,9 +218,8 @@ int zebra_evpn_macip_send_msg_to_client(uint32_t id, struct ethaddr *macaddr,
void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json);
void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt);
void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt);
void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
bool force_clear_static,
const char *caller);
int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
bool force_clear_static, const char *caller);
void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready,
bool new_bgp_ready);

View File

@ -965,46 +965,136 @@ void zebra_evpn_if_cleanup(struct zebra_if *zif)
* A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
* NH is then added to the L2-ECMP-NHG associated with the ES.
*/
static uint32_t zebra_evpn_nhid_alloc(bool is_nhg)
static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es *es)
{
uint32_t id;
int type;
uint32_t nh_id;
bf_assign_index(zmh_info->nh_id_bitmap, id);
if (!id)
return 0;
type = is_nhg ? EVPN_NHG_ID_TYPE_BIT : EVPN_NH_ID_TYPE_BIT;
return (id | type);
if (es) {
nh_id = id | EVPN_NHG_ID_TYPE_BIT;
/* Add to NHG hash */
es->nhg_id = nh_id;
if (!hash_get(zmh_info->nhg_table, es, hash_alloc_intern)) {
bf_release_index(zmh_info->nh_id_bitmap, id);
return 0;
}
} else {
nh_id = id | EVPN_NH_ID_TYPE_BIT;
}
return nh_id;
}
static void zebra_evpn_nhid_free(uint32_t nh_id)
static void zebra_evpn_nhid_free(uint32_t nh_id, struct zebra_evpn_es *es)
{
uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
if (!id)
return;
if (es) {
hash_release(zmh_info->nhg_table, es);
es->nhg_id = 0;
}
bf_release_index(zmh_info->nh_id_bitmap, id);
}
static unsigned int zebra_evpn_nhg_hash_keymake(const void *p)
{
const struct zebra_evpn_es *es = p;
return jhash_1word(es->nhg_id, 0);
}
static bool zebra_evpn_nhg_cmp(const void *p1, const void *p2)
{
const struct zebra_evpn_es *es1 = p1;
const struct zebra_evpn_es *es2 = p2;
if (es1 == NULL && es2 == NULL)
return true;
if (es1 == NULL || es2 == NULL)
return false;
return (es1->nhg_id == es2->nhg_id);
}
/* Lookup ES using the NHG id associated with it */
static struct zebra_evpn_es *zebra_evpn_nhg_find(uint32_t nhg_id)
{
struct zebra_evpn_es *es;
struct zebra_evpn_es tmp;
tmp.nhg_id = nhg_id;
es = hash_lookup(zmh_info->nhg_table, &tmp);
return es;
}
/* Returns TRUE if the NHG is associated with a local ES */
bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
struct zebra_evpn_es **local_es)
{
struct zebra_evpn_es *es;
es = zebra_evpn_nhg_find(nhg_id);
if (es && (es->flags & ZEBRA_EVPNES_LOCAL)) {
*local_es = es;
return true;
}
*local_es = NULL;
return false;
}
/* update remote macs associated with the ES */
static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es *es)
{
zebra_mac_t *mac;
struct listnode *node;
bool local_via_nw;
local_via_nw = zebra_evpn_es_local_mac_via_network_port(es);
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("mac update on es %s nhg %s", es->esi_str,
(es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
? "activate"
: "de-activate");
for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
continue;
if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
zebra_evpn_rem_mac_install(mac->zevpn, mac,
false /*was_static*/);
else
zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
true /*force*/);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|| (local_via_nw && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
&& zebra_evpn_mac_is_static(mac))) {
if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"%smac %pEA install via es %s nhg 0x%x",
(mac->flags & ZEBRA_MAC_REMOTE)
? "rem"
: "local-nw",
&mac->macaddr, es->esi_str,
es->nhg_id);
zebra_evpn_rem_mac_install(
mac->zevpn, mac, false /*was_static*/);
} else {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"%smac %pEA un-install es %s",
(mac->flags & ZEBRA_MAC_REMOTE)
? "rem"
: "local-nw",
&mac->macaddr, es->esi_str);
zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
true /*force*/);
}
}
}
}
@ -1078,7 +1168,7 @@ static void zebra_evpn_nh_add(struct zebra_evpn_es_vtep *es_vtep)
if (es_vtep->nh_id)
return;
es_vtep->nh_id = zebra_evpn_nhid_alloc(false);
es_vtep->nh_id = zebra_evpn_nhid_alloc(NULL /*NHG-es*/);
if (!es_vtep->nh_id)
return;
@ -1110,8 +1200,7 @@ static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
zebra_evpn_nhg_update(es_vtep->es);
/* uninstall the NH */
kernel_del_mac_nh(nh_id);
zebra_evpn_nhid_free(nh_id);
zebra_evpn_nhid_free(nh_id, NULL /*NHG-es*/);
}
/*****************************************************************************/
@ -1441,7 +1530,7 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
listset_app_node_mem(es->mac_list);
/* reserve a NHG */
es->nhg_id = zebra_evpn_nhid_alloc(true);
es->nhg_id = zebra_evpn_nhid_alloc(es);
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es %s nhg %u new", es->esi_str, es->nhg_id);
@ -1473,7 +1562,7 @@ static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
kernel_del_mac_nhg(es->nhg_id);
}
zebra_evpn_nhid_free(es->nhg_id);
zebra_evpn_nhid_free(es->nhg_id, es);
/* cleanup resources maintained against the ES */
list_delete(&es->es_evi_list);
@ -2313,6 +2402,7 @@ void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
es->flags &= ~ZEBRA_EVPNES_OPER_UP;
zebra_evpn_es_run_df_election(es, __func__);
zebra_evpn_local_mac_oper_state_change(es);
/* inform BGP of the ES oper state change */
if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
@ -3218,6 +3308,9 @@ void zebra_evpn_mh_config_write(struct vty *vty)
if (zmh_info->startup_delay_time != ZEBRA_EVPN_MH_STARTUP_DELAY_DEF)
vty_out(vty, "evpn mh startup-delay %d\n",
zmh_info->startup_delay_time);
if (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF)
vty_out(vty, "evpn mh redirect-off\n");
}
int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
@ -3254,6 +3347,19 @@ int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
return 0;
}
int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off)
{
/* This knob needs to be set before ESs are configured
* i.e. cannot be changed on the fly
*/
if (redirect_off)
zmh_info->flags |= ZEBRA_EVPN_MH_REDIRECT_OFF;
else
zmh_info->flags &= ~ZEBRA_EVPN_MH_REDIRECT_OFF;
return 0;
}
void zebra_evpn_interface_init(void)
{
install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
@ -3275,6 +3381,8 @@ void zebra_evpn_mh_init(void)
bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
bf_assign_zero_index(zmh_info->nh_id_bitmap);
zmh_info->nhg_table = hash_create(zebra_evpn_nhg_hash_keymake,
zebra_evpn_nhg_cmp, "l2 NHG table");
/* setup broadcast domain tables */
zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,

View File

@ -165,6 +165,11 @@ struct zebra_evpn_access_bd {
#define zmh_info (zrouter.mh_info)
struct zebra_evpn_mh_info {
uint32_t flags;
/* If the dataplane is not capable of handling a backup NHG on an access
* port we will need to explicitly failover each MAC entry on
* local ES down
*/
#define ZEBRA_EVPN_MH_REDIRECT_OFF (1 << 0)
/* DAD support for EVPN-MH is yet to be added. So on detection of
* first local ES, DAD is turned off
*/
@ -199,6 +204,8 @@ struct zebra_evpn_mh_info {
*/
#define EVPN_NH_ID_TYPE_BIT (1 << EVPN_NH_ID_TYPE_POS)
#define EVPN_NHG_ID_TYPE_BIT (2 << EVPN_NH_ID_TYPE_POS)
/* L2-NHG table - key: nhg_id, data: zebra_evpn_es */
struct hash *nhg_table;
/* XXX - re-visit the default hold timer value */
int mac_hold_time;
@ -234,12 +241,18 @@ static inline bool zebra_evpn_mh_is_fdb_nh(uint32_t id)
(id & EVPN_NH_ID_TYPE_BIT));
}
static inline bool
zebra_evpn_es_local_mac_via_network_port(struct zebra_evpn_es *es)
{
return !(es->flags & ZEBRA_EVPNES_OPER_UP)
&& (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF);
}
static inline bool zebra_evpn_mh_do_dup_addr_detect(void)
{
return !(zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF);
}
/*****************************************************************************/
extern esi_t *zero_esi;
extern void zebra_evpn_mh_init(void);
@ -296,5 +309,8 @@ extern bool zebra_evpn_is_es_bond(struct interface *ifp);
extern bool zebra_evpn_is_es_bond_member(struct interface *ifp);
extern void zebra_evpn_mh_print(struct vty *vty);
extern void zebra_evpn_mh_json(json_object *json);
extern bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
struct zebra_evpn_es **local_es);
extern int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off);
#endif /* _ZEBRA_EVPN_MH_H */

View File

@ -2497,6 +2497,20 @@ DEFPY (evpn_mh_startup_delay,
no ? true : false);
}
DEFPY(evpn_mh_redirect_off, evpn_mh_redirect_off_cmd,
"[no$no] evpn mh redirect-off",
NO_STR
"EVPN\n"
"Multihoming\n"
"ES bond redirect for fast-failover off\n")
{
bool redirect_off;
redirect_off = no ? false : true;
return zebra_evpn_mh_redirect_off(vty, redirect_off);
}
DEFUN (default_vrf_vni_mapping,
default_vrf_vni_mapping_cmd,
"vni " CMD_VNI_RANGE "[prefix-routes-only]",
@ -4055,6 +4069,7 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &evpn_mh_mac_holdtime_cmd);
install_element(CONFIG_NODE, &evpn_mh_neigh_holdtime_cmd);
install_element(CONFIG_NODE, &evpn_mh_startup_delay_cmd);
install_element(CONFIG_NODE, &evpn_mh_redirect_off_cmd);
install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
install_element(VRF_NODE, &vrf_vni_mapping_cmd);

View File

@ -3910,9 +3910,10 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
* us, this must involve a multihoming scenario. Treat this as implicit delete
* of any prior local MAC.
*/
int zebra_vxlan_check_del_local_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr,
vlanid_t vid)
{
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
@ -3969,14 +3970,48 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
return 0;
}
/*
* 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.
/* MAC notification from the dataplane with a network dest port -
* 1. This can be a local MAC on a down ES (if fast-failover is not possible
* 2. Or it can be a remote MAC
*/
int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
uint32_t nhg_id, bool sticky, bool dp_static)
{
struct zebra_evpn_es *es;
struct interface *acc_ifp;
/* if remote mac delete the local entry */
if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es)
|| !zebra_evpn_es_local_mac_via_network_port(es)) {
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpAdd remote MAC %pEA VID %u", macaddr,
vid);
return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr,
vid);
}
/* If local MAC on a down local ES translate the network-mac-add
* to a local-inactive-mac-add
*/
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpAdd local-nw-MAC %pEA VID %u", macaddr, vid);
acc_ifp = es->zif->ifp;
return zebra_vxlan_local_mac_add_update(
acc_ifp, br_if, macaddr, vid, sticky,
false /* local_inactive */, dp_static);
}
/*
* Handle network MAC delete by kernel -
* 1. readd the remote MAC if we have it
* 2. local MAC with does ES may also need to be re-installed
*/
static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac);
int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
{
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
@ -3984,7 +4019,6 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
zebra_mac_t *mac = NULL;
char buf[ETHER_ADDR_STRLEN];
zif = ifp->info;
assert(zif);
@ -4010,16 +4044,89 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
if (!mac)
return 0;
/* Is it a remote entry? */
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
return 0;
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
/* If remote entry simply re-install */
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"dpDel remote MAC %pEA intf %s(%u) VNI %u - readd",
macaddr, ifp->name, ifp->ifindex, vni);
zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && mac->es
&& zebra_evpn_es_local_mac_via_network_port(mac->es)) {
/* If local entry via nw-port call local-del which will
* re-install entry in the dataplane is needed
*/
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpDel local-nw-MAC %pEA VNI %u", macaddr,
vni);
zebra_vxlan_do_local_mac_del(zevpn, mac);
}
return 0;
}
static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
{
bool old_bgp_ready;
bool new_bgp_ready;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Del remote MAC %s intf %s(%u) VNI %u - readd",
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, vni);
zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
&mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
listcount(mac->neigh_list));
old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
if (zebra_evpn_mac_is_static(mac)) {
/* this is a synced entry and can only be removed when the
* es-peers stop advertising it.
*/
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
"re-add sync-mac vni %u mac %pEA es %s seq %d f 0x%x",
zevpn->vni, &mac->macaddr,
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
mac->flags);
/* inform-bgp about change in local-activity if any */
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
new_bgp_ready =
zebra_evpn_mac_is_ready_for_bgp(mac->flags);
zebra_evpn_mac_send_add_del_to_client(
mac, old_bgp_ready, new_bgp_ready);
}
/* re-install the entry in the kernel */
zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
false /* force_clear_static */,
__func__);
return 0;
}
/* Update all the neigh entries associated with this mac */
zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
/* Remove MAC from BGP. */
zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
false /* force */);
zebra_evpn_es_mac_deref_entry(mac);
/*
* 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)) {
zebra_evpn_mac_del(zevpn, mac);
} else {
UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
return 0;
}
@ -4030,6 +4137,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
{
zebra_evpn_t *zevpn;
zebra_mac_t *mac;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
@ -4044,7 +4152,16 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
return -1;
}
return zebra_evpn_del_local_mac(zevpn, macaddr, ifp);
/* If entry doesn't exist, nothing to do. */
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac)
return 0;
/* Is it a local entry? */
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return 0;
return zebra_vxlan_do_local_mac_del(zevpn, mac);
}
/*

View File

@ -177,13 +177,6 @@ extern int zebra_vxlan_local_mac_add_update(struct interface *ifp,
extern int zebra_vxlan_local_mac_del(struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac,
vlanid_t vid);
extern int zebra_vxlan_check_del_local_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_check_readd_vtep(struct interface *ifp,
struct in_addr vtep_ip);
extern int zebra_vxlan_if_up(struct interface *ifp);
@ -222,6 +215,15 @@ extern void zebra_evpn_init(void);
extern void zebra_vxlan_macvlan_up(struct interface *ifp);
extern void zebra_vxlan_macvlan_down(struct interface *ifp);
extern int vni_list_cmp(void *p1, void *p2);
extern int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
uint32_t nhg_id, bool sticky,
bool dp_static);
extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr,
vlanid_t vid);
#ifdef __cplusplus
}