mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 06:34:44 +00:00
Merge pull request #7879 from AnuradhaKaruppiah/advertise-svi-mac
evpn-mh: Advertise SVI MAC as a type-2 route if EVPN MH is enabled
This commit is contained in:
commit
0ff7911386
@ -561,6 +561,8 @@ static void netlink_interface_update_l2info(struct interface *ifp,
|
||||
|
||||
netlink_extract_vlan_info(link_data, &vlan_info);
|
||||
zebra_l2_vlanif_update(ifp, &vlan_info);
|
||||
zebra_evpn_acc_bd_svi_set(ifp->info, NULL,
|
||||
!!if_is_operative(ifp));
|
||||
} else if (IS_ZEBRA_IF_VXLAN(ifp)) {
|
||||
struct zebra_l2info_vxlan vxlan_info;
|
||||
|
||||
|
@ -1183,6 +1183,11 @@ void zebra_if_update_all_links(void)
|
||||
zif->link?zif->link->name:"unk",
|
||||
zif->link_ifindex);
|
||||
}
|
||||
|
||||
/* Update VLAN<=>SVI map */
|
||||
if (IS_ZEBRA_IF_VLAN(ifp))
|
||||
zebra_evpn_acc_bd_svi_set(zif, NULL,
|
||||
!!if_is_operative(ifp));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,9 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
|
||||
buf, sizeof(buf)));
|
||||
json_object_string_add(json, "advertiseGatewayMacip",
|
||||
zevpn->advertise_gw_macip ? "Yes" : "No");
|
||||
json_object_string_add(json, "advertiseSviMacip",
|
||||
zevpn->advertise_svi_macip ? "Yes"
|
||||
: "No");
|
||||
json_object_int_add(json, "numMacs", num_macs);
|
||||
json_object_int_add(json, "numArpNd", num_neigh);
|
||||
}
|
||||
@ -194,6 +197,8 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
|
||||
num_neigh);
|
||||
vty_out(vty, " Advertise-gw-macip: %s\n",
|
||||
zevpn->advertise_gw_macip ? "Yes" : "No");
|
||||
vty_out(vty, " Advertise-svi-macip: %s\n",
|
||||
zevpn->advertise_svi_macip ? "Yes" : "No");
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +434,7 @@ int zebra_evpn_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
|
||||
vxl = &zif->l2info.vxl;
|
||||
|
||||
if (zebra_evpn_mac_gw_macip_add(ifp, zevpn, ip, &mac, macaddr,
|
||||
vxl->access_vlan)
|
||||
vxl->access_vlan, true)
|
||||
!= 0)
|
||||
return -1;
|
||||
|
||||
@ -569,7 +574,9 @@ void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
|
||||
return;
|
||||
|
||||
/* Add primary SVI MAC-IP */
|
||||
zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
|
||||
if (advertise_svi_macip_enabled(zevpn)
|
||||
|| advertise_gw_macip_enabled(zevpn))
|
||||
zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
|
||||
|
||||
if (advertise_gw_macip_enabled(zevpn)) {
|
||||
/* Add VRR MAC-IP - if any*/
|
||||
@ -925,14 +932,20 @@ void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp)
|
||||
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);
|
||||
if (vlan_if) {
|
||||
/* Add SVI MAC */
|
||||
zebra_evpn_acc_bd_svi_mac_add(vlan_if);
|
||||
|
||||
/* Add SVI MAC-IP */
|
||||
zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
|
||||
if (advertise_svi_macip_enabled(zevpn)
|
||||
|| advertise_gw_macip_enabled(zevpn))
|
||||
zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
|
||||
|
||||
/* Add VRR MAC-IP - if any*/
|
||||
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
||||
if (vrr_if)
|
||||
zebra_evpn_add_macip_for_intf(vrr_if, zevpn);
|
||||
if (advertise_gw_macip_enabled(zevpn)) {
|
||||
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
||||
if (vrr_if)
|
||||
zebra_evpn_add_macip_for_intf(vrr_if, zevpn);
|
||||
}
|
||||
|
||||
neigh_read_for_vlan(zns, vlan_if);
|
||||
}
|
||||
|
@ -221,8 +221,8 @@ void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
|
||||
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
||||
}
|
||||
|
||||
/* If no neighbors, delete the MAC. */
|
||||
if (list_isempty(mac->neigh_list))
|
||||
/* If no references, delete the MAC. */
|
||||
if (!zebra_evpn_mac_in_use(mac))
|
||||
zebra_evpn_mac_del(zevpn, mac);
|
||||
}
|
||||
|
||||
@ -583,6 +583,9 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
|
||||
json_object_boolean_true_add(json_mac, "stickyMac");
|
||||
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
|
||||
json_object_boolean_true_add(json_mac, "sviMac");
|
||||
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
|
||||
json_object_boolean_true_add(json_mac,
|
||||
"defaultGateway");
|
||||
@ -685,6 +688,9 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
|
||||
vty_out(vty, " Sticky Mac ");
|
||||
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
|
||||
vty_out(vty, " SVI-Mac ");
|
||||
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
|
||||
vty_out(vty, " Default-gateway Mac ");
|
||||
|
||||
@ -2376,7 +2382,8 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
|
||||
|
||||
int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
|
||||
struct ipaddr *ip, zebra_mac_t **macp,
|
||||
struct ethaddr *macaddr, vlanid_t vlan_id)
|
||||
struct ethaddr *macaddr, vlanid_t vlan_id,
|
||||
bool def_gw)
|
||||
{
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
zebra_mac_t *mac;
|
||||
@ -2402,7 +2409,8 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
|
||||
/* Set "local" forwarding info. */
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
|
||||
if (def_gw)
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
|
||||
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
||||
mac->fwd_info.local.ifindex = ifp->ifindex;
|
||||
mac->fwd_info.local.ns_id = local_ns_id;
|
||||
@ -2412,3 +2420,63 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zebra_evpn_mac_svi_del(struct interface *ifp, zebra_evpn_t *zevpn)
|
||||
{
|
||||
zebra_mac_t *mac;
|
||||
struct ethaddr macaddr;
|
||||
bool old_bgp_ready;
|
||||
|
||||
if (!zebra_evpn_mh_do_adv_svi_mac())
|
||||
return;
|
||||
|
||||
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
||||
mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
|
||||
if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("SVI %s mac free", ifp->name);
|
||||
|
||||
old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
|
||||
UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
|
||||
zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
|
||||
false);
|
||||
zebra_evpn_deref_ip2mac(mac->zevpn, mac);
|
||||
}
|
||||
}
|
||||
|
||||
void zebra_evpn_mac_svi_add(struct interface *ifp, zebra_evpn_t *zevpn)
|
||||
{
|
||||
zebra_mac_t *mac = NULL;
|
||||
struct ethaddr macaddr;
|
||||
struct zebra_if *zif = ifp->info;
|
||||
bool old_bgp_ready;
|
||||
bool new_bgp_ready;
|
||||
|
||||
if (!zebra_evpn_mh_do_adv_svi_mac()
|
||||
|| !zebra_evpn_send_to_client_ok(zevpn))
|
||||
return;
|
||||
|
||||
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
||||
|
||||
/* dup check */
|
||||
mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
|
||||
if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
|
||||
return;
|
||||
|
||||
/* add/update mac */
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("SVI %s mac add", zif->ifp->name);
|
||||
|
||||
old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags))
|
||||
? true
|
||||
: false;
|
||||
|
||||
mac = NULL;
|
||||
zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false);
|
||||
if (mac)
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_SVI);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ struct zebra_mac_t_ {
|
||||
* to advertise it as locally attached but with a "proxy" flag
|
||||
*/
|
||||
#define ZEBRA_MAC_LOCAL_INACTIVE 0x800
|
||||
/* The MAC entry was created because of advertise_svi_mac */
|
||||
#define ZEBRA_MAC_SVI 0x1000
|
||||
|
||||
#define ZEBRA_MAC_ALL_LOCAL_FLAGS (ZEBRA_MAC_LOCAL | ZEBRA_MAC_LOCAL_INACTIVE)
|
||||
#define ZEBRA_MAC_ALL_PEER_FLAGS \
|
||||
@ -201,6 +203,12 @@ static inline void zebra_evpn_mac_clear_sync_info(zebra_mac_t *mac)
|
||||
zebra_evpn_mac_stop_hold_timer(mac);
|
||||
}
|
||||
|
||||
static inline bool zebra_evpn_mac_in_use(zebra_mac_t *mac)
|
||||
{
|
||||
return !list_isempty(mac->neigh_list)
|
||||
|| CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI);
|
||||
}
|
||||
|
||||
struct hash *zebra_mac_db_create(const char *desc);
|
||||
uint32_t num_valid_macs(zebra_evpn_t *zevi);
|
||||
uint32_t num_dup_detected_macs(zebra_evpn_t *zevi);
|
||||
@ -256,7 +264,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
|
||||
int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac);
|
||||
int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
|
||||
struct ipaddr *ip, zebra_mac_t **macp,
|
||||
struct ethaddr *macaddr, vlanid_t vlan_id);
|
||||
struct ethaddr *macaddr, vlanid_t vlan_id,
|
||||
bool def_gw);
|
||||
void zebra_evpn_mac_svi_add(struct interface *ifp, zebra_evpn_t *zevpn);
|
||||
void zebra_evpn_mac_svi_del(struct interface *ifp, zebra_evpn_t *zevpn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -130,12 +130,6 @@ static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
|
||||
return es_evi;
|
||||
}
|
||||
|
||||
/* returns TRUE if the EVPN is ready to be sent to BGP */
|
||||
static inline bool zebra_evpn_send_to_client_ok(zebra_evpn_t *zevpn)
|
||||
{
|
||||
return !!(zevpn->flags & ZEVPN_READY_FOR_BGP);
|
||||
}
|
||||
|
||||
/* Evaluate if the es_evi is ready to be sent BGP -
|
||||
* 1. If it is ready an add is sent to BGP
|
||||
* 2. If it is not ready a del is sent (if the ES had been previously added
|
||||
@ -466,6 +460,9 @@ void zebra_evpn_update_all_es(zebra_evpn_t *zevpn)
|
||||
{
|
||||
struct zebra_evpn_es_evi *es_evi;
|
||||
struct listnode *node;
|
||||
struct interface *vlan_if;
|
||||
struct interface *vxlan_if;
|
||||
struct zebra_if *vxlan_zif;
|
||||
|
||||
/* the EVPN is now elgible as a base for EVPN-MH */
|
||||
if (zebra_evpn_send_to_client_ok(zevpn))
|
||||
@ -475,6 +472,20 @@ void zebra_evpn_update_all_es(zebra_evpn_t *zevpn)
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
|
||||
zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
|
||||
|
||||
/* reinstall SVI MAC */
|
||||
vxlan_if = zevpn->vxlan_if;
|
||||
if (vxlan_if) {
|
||||
vxlan_zif = vxlan_if->info;
|
||||
if (if_is_operative(vxlan_if)
|
||||
&& vxlan_zif->brslave_info.br_if) {
|
||||
vlan_if = zvni_map_to_svi(
|
||||
vxlan_zif->l2info.vxl.access_vlan,
|
||||
vxlan_zif->brslave_info.br_if);
|
||||
if (vlan_if)
|
||||
zebra_evpn_acc_bd_svi_mac_add(vlan_if);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -524,9 +535,11 @@ static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
|
||||
/* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
|
||||
* mapping is added.
|
||||
*/
|
||||
static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_new(vlanid_t vid)
|
||||
static struct zebra_evpn_access_bd *
|
||||
zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
|
||||
{
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
struct interface *vlan_if;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d add", vid);
|
||||
@ -544,6 +557,16 @@ static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_new(vlanid_t vid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check if an svi exists for the vlan */
|
||||
if (br_if) {
|
||||
vlan_if = zvni_map_to_svi(vid, br_if);
|
||||
if (vlan_if) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d SVI %s set", vid,
|
||||
vlan_if->name);
|
||||
acc_bd->vlan_zif = vlan_if->info;
|
||||
}
|
||||
}
|
||||
return acc_bd;
|
||||
}
|
||||
|
||||
@ -556,6 +579,9 @@ static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd)
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d del", acc_bd->vid);
|
||||
|
||||
if (acc_bd->vlan_zif && acc_bd->zevpn && acc_bd->zevpn->mac_table)
|
||||
zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
|
||||
|
||||
/* cleanup resources maintained against the ES */
|
||||
list_delete(&acc_bd->mbr_zifs);
|
||||
|
||||
@ -584,6 +610,59 @@ static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
|
||||
zebra_evpn_acc_vl_free(acc_bd);
|
||||
}
|
||||
|
||||
/* called when a SVI is goes up/down */
|
||||
void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
|
||||
struct zebra_if *br_zif, bool is_up)
|
||||
{
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
struct zebra_l2info_bridge *br;
|
||||
uint16_t vid;
|
||||
struct zebra_if *tmp_br_zif = br_zif;
|
||||
|
||||
if (!tmp_br_zif) {
|
||||
if (!vlan_zif->link || !vlan_zif->link->info)
|
||||
return;
|
||||
|
||||
tmp_br_zif = vlan_zif->link->info;
|
||||
}
|
||||
|
||||
br = &tmp_br_zif->l2info.br;
|
||||
/* ignore vlan unaware bridges */
|
||||
if (!br->vlan_aware)
|
||||
return;
|
||||
|
||||
vid = vlan_zif->l2info.vl.vid;
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
if (!acc_bd)
|
||||
return;
|
||||
|
||||
if (is_up) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d SVI %s set", vid,
|
||||
vlan_zif->ifp->name);
|
||||
|
||||
acc_bd->vlan_zif = vlan_zif;
|
||||
if (acc_bd->zevpn)
|
||||
zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
|
||||
acc_bd->zevpn);
|
||||
} else if (acc_bd->vlan_zif) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d SVI clear", vid);
|
||||
acc_bd->vlan_zif = NULL;
|
||||
if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
|
||||
zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
|
||||
}
|
||||
}
|
||||
|
||||
/* On some events macs are force-flushed. This api can be used to reinstate
|
||||
* the svi-mac after such cleanup-events.
|
||||
*/
|
||||
void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if)
|
||||
{
|
||||
zebra_evpn_acc_bd_svi_set(vlan_if->info, NULL,
|
||||
if_is_operative(vlan_if));
|
||||
}
|
||||
|
||||
/* called when a EVPN-L2VNI is set or cleared against a BD */
|
||||
static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
|
||||
zebra_evpn_t *zevpn, zebra_evpn_t *old_zevpn)
|
||||
@ -604,6 +683,15 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
|
||||
else if (old_zevpn)
|
||||
zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
|
||||
}
|
||||
|
||||
if (acc_bd->vlan_zif) {
|
||||
if (zevpn)
|
||||
zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
|
||||
acc_bd->zevpn);
|
||||
else if (old_zevpn && old_zevpn->mac_table)
|
||||
zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp,
|
||||
old_zevpn);
|
||||
}
|
||||
}
|
||||
|
||||
/* handle VLAN->VxLAN_IF association */
|
||||
@ -618,7 +706,8 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
if (!acc_bd)
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid);
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid,
|
||||
vxlan_zif->brslave_info.br_if);
|
||||
|
||||
old_vxlan_zif = acc_bd->vxlan_zif;
|
||||
acc_bd->vxlan_zif = vxlan_zif;
|
||||
@ -712,7 +801,7 @@ void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
if (!acc_bd)
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid);
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if);
|
||||
|
||||
if (listnode_lookup(acc_bd->mbr_zifs, zif))
|
||||
return;
|
||||
@ -756,6 +845,22 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
|
||||
zebra_evpn_acc_bd_free_on_deref(acc_bd);
|
||||
}
|
||||
|
||||
static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket *bucket,
|
||||
void *ctxt)
|
||||
{
|
||||
struct zebra_evpn_access_bd *acc_bd = bucket->data;
|
||||
|
||||
if (acc_bd->vlan_zif && acc_bd->zevpn)
|
||||
zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
|
||||
}
|
||||
|
||||
/* called when advertise SVI MAC is enabled on the switch */
|
||||
static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
|
||||
{
|
||||
hash_iterate(zmh_info->evpn_vlan_table,
|
||||
zebra_evpn_acc_vl_adv_svi_mac_cb, NULL);
|
||||
}
|
||||
|
||||
static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd *acc_bd,
|
||||
json_object *json, bool detail)
|
||||
{
|
||||
@ -800,6 +905,8 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
|
||||
vty_out(vty, " VxLAN Interface: %s\n",
|
||||
acc_bd->vxlan_zif ?
|
||||
acc_bd->vxlan_zif->ifp->name : "-");
|
||||
vty_out(vty, " SVI: %s\n",
|
||||
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
|
||||
vty_out(vty, " L2-VNI: %d\n",
|
||||
acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
|
||||
vty_out(vty, " Member Count: %d\n",
|
||||
@ -817,12 +924,11 @@ static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
|
||||
if (json) {
|
||||
zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
|
||||
} else {
|
||||
vty_out(vty, "%-5u %21s %-8d %u\n",
|
||||
acc_bd->vid,
|
||||
acc_bd->vxlan_zif ?
|
||||
acc_bd->vxlan_zif->ifp->name : "-",
|
||||
acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
|
||||
listcount(acc_bd->mbr_zifs));
|
||||
vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid,
|
||||
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
|
||||
acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
|
||||
acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
|
||||
listcount(acc_bd->mbr_zifs));
|
||||
}
|
||||
}
|
||||
|
||||
@ -856,8 +962,8 @@ void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
|
||||
wctx.detail = false;
|
||||
|
||||
if (!uj)
|
||||
vty_out(vty, "%-5s %21s %-8s %s\n",
|
||||
"VLAN", "VxLAN-IF", "L2-VNI", "# Members");
|
||||
vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
|
||||
"L2-VNI", "VXLAN-IF", "# Members");
|
||||
|
||||
hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
|
||||
&wctx);
|
||||
@ -1960,6 +2066,20 @@ static void zebra_evpn_mh_advertise_reach_neigh_only(void)
|
||||
*/
|
||||
}
|
||||
|
||||
/* On config of first local-ES turn on advertisement of local SVI-MAC */
|
||||
static void zebra_evpn_mh_advertise_svi_mac(void)
|
||||
{
|
||||
if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC)
|
||||
return;
|
||||
|
||||
zmh_info->flags |= ZEBRA_EVPN_MH_ADV_SVI_MAC;
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("evpn-mh: advertise SVI MAC");
|
||||
|
||||
/* walk through all SVIs and see if we need to advertise the MAC */
|
||||
zebra_evpn_acc_vl_adv_svi_mac_all();
|
||||
}
|
||||
|
||||
static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
|
||||
{
|
||||
struct zebra_evpn_es *es;
|
||||
@ -1974,6 +2094,17 @@ static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* currently there is no global config to turn on MH instead we use
|
||||
* the addition of the first local Ethernet Segment as the trigger to
|
||||
* init MH specific processing
|
||||
*/
|
||||
static void zebra_evpn_mh_on_first_local_es(void)
|
||||
{
|
||||
zebra_evpn_mh_dup_addr_detect_off();
|
||||
zebra_evpn_mh_advertise_reach_neigh_only();
|
||||
zebra_evpn_mh_advertise_svi_mac();
|
||||
}
|
||||
|
||||
static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
|
||||
struct zebra_if *zif)
|
||||
{
|
||||
@ -1984,8 +2115,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
|
||||
zlog_debug("local es %s add; nhg %u if %s", es->esi_str,
|
||||
es->nhg_id, zif->ifp->name);
|
||||
|
||||
zebra_evpn_mh_dup_addr_detect_off();
|
||||
zebra_evpn_mh_advertise_reach_neigh_only();
|
||||
zebra_evpn_mh_on_first_local_es();
|
||||
|
||||
es->flags |= ZEBRA_EVPNES_LOCAL;
|
||||
listnode_init(&es->local_es_listnode, es);
|
||||
|
@ -180,6 +180,8 @@ struct zebra_evpn_access_bd {
|
||||
struct list *mbr_zifs;
|
||||
/* presence of zevpn activates the EVI on all the ESs in mbr_zifs */
|
||||
zebra_evpn_t *zevpn;
|
||||
/* SVI associated with the VLAN */
|
||||
struct zebra_if *vlan_zif;
|
||||
};
|
||||
|
||||
/* multihoming information stored in zrouter */
|
||||
@ -200,6 +202,10 @@ struct zebra_evpn_mh_info {
|
||||
* this flag when the first local ES is detected.
|
||||
*/
|
||||
#define ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY (1 << 2)
|
||||
/* If EVPN MH is enabled we advertise the SVI MAC address to avoid
|
||||
* flooding of ARP replies rxed from the multi-homed host
|
||||
*/
|
||||
#define ZEBRA_EVPN_MH_ADV_SVI_MAC (1 << 3)
|
||||
|
||||
/* RB tree of Ethernet segments (used for EVPN-MH) */
|
||||
struct zebra_es_rb_head es_rb_tree;
|
||||
@ -256,6 +262,12 @@ struct zebra_evpn_mh_info {
|
||||
enum protodown_reasons protodown_rc;
|
||||
};
|
||||
|
||||
/* returns TRUE if the EVPN is ready to be sent to BGP */
|
||||
static inline bool zebra_evpn_send_to_client_ok(zebra_evpn_t *zevpn)
|
||||
{
|
||||
return !!(zevpn->flags & ZEVPN_READY_FOR_BGP);
|
||||
}
|
||||
|
||||
static inline bool zebra_evpn_mac_is_es_local(zebra_mac_t *mac)
|
||||
{
|
||||
return mac->es && (mac->es->flags & ZEBRA_EVPNES_LOCAL);
|
||||
@ -285,6 +297,10 @@ static inline bool zebra_evpn_mh_do_adv_reachable_neigh_only(void)
|
||||
return !!(zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY);
|
||||
}
|
||||
|
||||
static inline bool zebra_evpn_mh_do_adv_svi_mac(void)
|
||||
{
|
||||
return zmh_info && (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
extern esi_t *zero_esi;
|
||||
@ -357,5 +373,8 @@ 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 void zebra_evpn_l2_nh_show(struct vty *vty, bool uj);
|
||||
extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
|
||||
struct zebra_if *br_zif, bool is_up);
|
||||
extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if);
|
||||
|
||||
#endif /* _ZEBRA_EVPN_MH_H */
|
||||
|
@ -2464,7 +2464,7 @@ int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip)
|
||||
|
||||
/* see if the AUTO mac needs to be deleted */
|
||||
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
|
||||
&& !listcount(zmac->neigh_list))
|
||||
&& !zebra_evpn_mac_in_use(zmac))
|
||||
zebra_evpn_mac_del(zevpn, zmac);
|
||||
|
||||
return 0;
|
||||
|
@ -3503,6 +3503,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
|
||||
zvrf->advertise_gw_macip ? "Yes" : "No");
|
||||
vty_out(vty, "Advertise svi mac-ip: %s\n",
|
||||
zvrf->advertise_svi_macip ? "Yes" : "No");
|
||||
vty_out(vty, "Advertise svi mac: %s\n",
|
||||
zebra_evpn_mh_do_adv_svi_mac() ? "Yes" : "No");
|
||||
vty_out(vty, "Duplicate address detection: %s\n",
|
||||
zebra_evpn_do_dup_addr_detect(zvrf) ? "Enable"
|
||||
: "Disable");
|
||||
@ -4493,6 +4495,16 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* VRR IP is advertised only if gw-macip-adv-enabled */
|
||||
if (IS_ZEBRA_IF_MACVLAN(ifp)) {
|
||||
if (!advertise_gw_macip_enabled(zevpn))
|
||||
return 0;
|
||||
} else {
|
||||
/* SVI IP is advertised if gw or svi macip-adv-enabled */
|
||||
if (!advertise_svi_macip_enabled(zevpn)
|
||||
&& !advertise_gw_macip_enabled(zevpn))
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
||||
|
||||
@ -4539,10 +4551,14 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
|
||||
} else {
|
||||
zebra_evpn_t *zevpn = NULL;
|
||||
|
||||
/* Unlink the SVI from the access VLAN */
|
||||
zebra_evpn_acc_bd_svi_set(ifp->info, link_if->info, false);
|
||||
|
||||
/* since we dont have svi corresponding to zevpn, we associate it
|
||||
* to default vrf. Note: the corresponding neigh entries on the
|
||||
* SVI would have already been deleted */
|
||||
zevpn = zebra_evpn_from_svi(ifp, link_if);
|
||||
|
||||
if (zevpn) {
|
||||
zevpn->vrf_id = VRF_DEFAULT;
|
||||
|
||||
@ -4606,6 +4622,9 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
|
||||
n_wctx.zevpn = zevpn;
|
||||
hash_iterate(zevpn->neigh_table, zebra_evpn_install_neigh_hash,
|
||||
&n_wctx);
|
||||
|
||||
/* Link the SVI from the access VLAN */
|
||||
zebra_evpn_acc_bd_svi_set(ifp->info, link_if->info, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user