mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 16:20:08 +00:00
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:
parent
69711b3f83
commit
15400f95b7
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user