summaryrefslogtreecommitdiff
path: root/zebra/zebra_evpn_mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_evpn_mac.c')
-rw-r--r--zebra/zebra_evpn_mac.c240
1 files changed, 213 insertions, 27 deletions
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index 5227a480fc..142a199bd7 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -94,6 +94,97 @@ uint32_t num_dup_detected_macs(zebra_evpn_t *zevpn)
return num_macs;
}
+/* Setup mac_list against the access port. This is done when a mac uses
+ * the ifp as destination for the first time
+ */
+static void zebra_evpn_mac_ifp_new(struct zebra_if *zif)
+{
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("MAC list created for ifp %s (%u)", zif->ifp->name,
+ zif->ifp->ifindex);
+
+ zif->mac_list = list_new();
+ listset_app_node_mem(zif->mac_list);
+}
+
+/* Free up the mac_list if any as a part of the interface del/cleanup */
+void zebra_evpn_mac_ifp_del(struct interface *ifp)
+{
+ struct zebra_if *zif = ifp->info;
+
+ if (zif->mac_list) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("MAC list deleted for ifp %s (%u)",
+ zif->ifp->name, zif->ifp->ifindex);
+ list_delete(&zif->mac_list);
+ }
+}
+
+/* Unlink local mac from a destination access port */
+static void zebra_evpn_mac_ifp_unlink(zebra_mac_t *zmac)
+{
+ struct zebra_if *zif;
+ struct interface *ifp = zmac->ifp;
+
+ if (!ifp)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)",
+ zmac->zevpn->vni,
+ &zmac->macaddr,
+ ifp->name, ifp->ifindex);
+
+ zif = ifp->info;
+ list_delete_node(zif->mac_list, &zmac->ifp_listnode);
+ zmac->ifp = NULL;
+}
+
+/* Link local mac to destination access port. This is done only if the
+ * local mac is associated with a zero ESI i.e. single attach or lacp-bypass
+ * bridge port member
+ */
+static void zebra_evpn_mac_ifp_link(zebra_mac_t *zmac, struct interface *ifp)
+{
+ struct zebra_if *zif;
+
+ if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
+ return;
+
+ /* already linked to the destination */
+ if (zmac->ifp == ifp)
+ return;
+
+ /* unlink the mac from any old destination */
+ if (zmac->ifp)
+ zebra_evpn_mac_ifp_unlink(zmac);
+
+ if (!ifp)
+ return;
+
+ zif = ifp->info;
+ /* the interface mac_list is created on first mac link attempt */
+ if (!zif->mac_list)
+ zebra_evpn_mac_ifp_new(zif);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)",
+ zmac->zevpn->vni,
+ &zmac->macaddr,
+ ifp->name, ifp->ifindex);
+
+ zmac->ifp = ifp;
+ listnode_init(&zmac->ifp_listnode, zmac);
+ listnode_add(zif->mac_list, &zmac->ifp_listnode);
+}
+
+/* If the mac is a local mac clear links to destination access port */
+void zebra_evpn_mac_clear_fwd_info(zebra_mac_t *zmac)
+{
+ zebra_evpn_mac_ifp_unlink(zmac);
+ memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
+}
+
/*
* Install remote MAC into the forwarding plane.
*/
@@ -221,8 +312,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 +674,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 +779,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 ");
@@ -747,14 +844,10 @@ static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
size_t flags_buf_sz)
{
snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
- mac->sync_neigh_cnt ?
- "N" : "",
- (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ?
- "P" : "",
- (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ?
- "X" : "",
- (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ?
- "I" : "");
+ mac->sync_neigh_cnt ? "N" : "",
+ (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "",
+ (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "",
+ (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : "");
return flags_buf;
}
@@ -1075,6 +1168,9 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
/* force de-ref any ES entry linked to the MAC */
zebra_evpn_es_mac_deref_entry(mac);
+ /* remove links to the destination access port */
+ zebra_evpn_mac_clear_fwd_info(mac);
+
/* Cancel proxy hold timer */
zebra_evpn_mac_stop_hold_timer(mac);
@@ -1684,7 +1780,7 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
}
}
mac->rem_seq = 0;
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ zebra_evpn_mac_clear_fwd_info(mac);
mac->flags = new_flags;
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
@@ -1710,6 +1806,7 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
inform_dataplane = true;
ctx->mac_inactive = true;
}
+
/* if peer-flag is being set notify dataplane that the
* entry must not be expired because of local inactivity
*/
@@ -1790,20 +1887,25 @@ static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac,
bool es_change;
ns_id_t local_ns_id = NS_DEFAULT;
struct zebra_vrf *zvrf;
+ struct zebra_evpn_es *es;
zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
if (zvrf && zvrf->zns)
local_ns_id = zvrf->zns->ns_id;
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ zebra_evpn_mac_clear_fwd_info(mac);
- es_change = zebra_evpn_es_mac_ref_entry(mac, zif->es_info.es);
+ es = zif->es_info.es;
+ if (es && (es->flags & ZEBRA_EVPNES_BYPASS))
+ es = NULL;
+ es_change = zebra_evpn_es_mac_ref_entry(mac, es);
if (!mac->es) {
/* if es is set fwd_info is not-relevant/taped-out */
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vid;
+ zebra_evpn_mac_ifp_link(mac, ifp);
}
return es_change;
@@ -1908,6 +2010,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
esi_t *old_esi;
bool old_static = false;
zebra_mac_t *mac;
+ bool old_es_present;
+ bool new_es_present;
sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
@@ -1971,7 +2075,16 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
zevpn, mac, seq, ipa_len, ipaddr, false))
return -1;
+ old_es_present = !!mac->es;
zebra_evpn_es_mac_ref(mac, esi);
+ new_es_present = !!mac->es;
+ /* XXX - dataplane is curently not able to handle a MAC
+ * replace if the destination changes from L2-NHG to
+ * single VTEP and vice-versa. So delete the old entry
+ * and re-install
+ */
+ if (old_es_present != new_es_present)
+ zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
}
/* Check MAC's curent state is local (this is the case
@@ -2016,8 +2129,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
}
/* Set "auto" and "remote" forwarding info. */
+ zebra_evpn_mac_clear_fwd_info(mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
mac->fwd_info.r_vtep_ip = vtep_ip;
@@ -2058,9 +2171,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
struct interface *ifp,
struct ethaddr *macaddr, vlanid_t vid,
bool sticky, bool local_inactive,
- bool dp_static)
+ bool dp_static, zebra_mac_t *mac)
{
- zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
bool mac_sticky = false;
bool inform_client = false;
@@ -2077,7 +2189,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
assert(ifp);
/* Check if we need to create or update or it is a NO-OP. */
- mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac)
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
@@ -2128,6 +2241,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
old_static = zebra_evpn_mac_is_static(mac);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
mac_sticky = true;
+ es_change = zebra_evpn_local_mac_update_fwd_info(
+ mac, ifp, vid);
/*
* Update any changes and if changes are relevant to
@@ -2136,7 +2251,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
if (mac_sticky == sticky && old_ifp == ifp
&& old_vid == vid
&& old_local_inactive == local_inactive
- && dp_static == old_static) {
+ && dp_static == old_static && !es_change) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
" Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, "
@@ -2160,15 +2275,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
inform_client = true;
}
- es_change = zebra_evpn_local_mac_update_fwd_info(
- mac, ifp, vid);
/* If an es_change is detected we need to advertise
* the route with a sequence that is one
* greater. This is need to indicate a mac-move
* to the ES peers
*/
if (es_change) {
- mac->loc_seq = mac->loc_seq + 1;
+ /* update the sequence number only if the entry
+ * is locally active
+ */
+ if (!local_inactive)
+ mac->loc_seq = mac->loc_seq + 1;
/* force drop the peer/sync info as it is
* simply no longer relevant
*/
@@ -2302,7 +2419,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
return 0;
}
-int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac,
+ bool clear_static)
{
char buf[ETHER_ADDR_STRLEN];
bool old_bgp_ready;
@@ -2315,11 +2433,11 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
listcount(mac->neigh_list));
old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
- if (zebra_evpn_mac_is_static(mac)) {
+ if (!clear_static && 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));
+ zebra_evpn_mac_clear_fwd_info(mac);
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
@@ -2350,6 +2468,9 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
return 0;
}
+ /* flush the peer info */
+ zebra_evpn_mac_clear_sync_info(mac);
+
/* Update all the neigh entries associated with this mac */
zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
@@ -2359,6 +2480,9 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
zebra_evpn_es_mac_deref_entry(mac);
+ /* remove links to the destination access port */
+ zebra_evpn_mac_clear_fwd_info(mac);
+
/*
* If there are no neigh associated with the mac delete the mac
* else mark it as AUTO for forward reference
@@ -2376,7 +2500,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;
@@ -2400,10 +2525,11 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
}
/* Set "local" forwarding info. */
+ zebra_evpn_mac_clear_fwd_info(mac);
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ if (def_gw)
+ SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vlan_id;
@@ -2412,3 +2538,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);
+}