From d9d3455e09b4b3005c9d4e3d5be93be5293c3e0d Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Thu, 23 Jul 2020 15:04:53 -0700 Subject: [PATCH] zebra: extract local mac add code from vxlan extract the local mac add code from zebra_vxlan_local_mac_add_update and create a new generic local mac add function zebra_evpn_add_update_local_mac Signed-off-by: Pat Ruddy --- zebra/zebra_evpn_mac.c | 256 +++++++++++++++++++++++++++++++++++++++-- zebra/zebra_evpn_mac.h | 21 ++-- zebra/zebra_vxlan.c | 232 +------------------------------------ 3 files changed, 258 insertions(+), 251 deletions(-) diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index a220da4553..de0f2b80d7 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -226,8 +226,9 @@ void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevpn, zebra_mac_t *mac) zebra_evpn_mac_del(zevpn, mac); } -void zebra_evpn_mac_get_access_info(zebra_mac_t *mac, struct interface **ifpP, - vlanid_t *vid) +static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac, + struct interface **ifpP, + vlanid_t *vid) { /* if the mac is associated with an ES we must get the access * info from the ES @@ -329,10 +330,11 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) return 0; } -void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, - zebra_mac_t *mac, - struct in_addr vtep_ip, bool do_dad, - bool *is_dup_detect, bool is_local) +static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, + zebra_mac_t *mac, + struct in_addr vtep_ip, + bool do_dad, bool *is_dup_detect, + bool is_local) { zebra_neigh_t *nbr; struct listnode *node = NULL; @@ -1602,8 +1604,9 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, /* update local fowarding info. return true if a dest-ES change * is detected */ -bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac, - struct interface *ifp, vlanid_t vid) +static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac, + struct interface *ifp, + vlanid_t vid) { struct zebra_if *zif = ifp->info; bool es_change; @@ -1877,3 +1880,240 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, *macp = mac; return 0; } + +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) +{ + zebra_mac_t *mac; + char buf[ETHER_ADDR_STRLEN]; + bool mac_sticky = false; + bool inform_client = false; + bool upd_neigh = false; + bool is_dup_detect = false; + struct in_addr vtep_ip = {.s_addr = 0}; + bool es_change = false; + bool new_bgp_ready; + /* assume inactive if not present or if not local */ + bool old_local_inactive = true; + bool old_bgp_ready = false; + bool inform_dataplane = false; + bool new_static = false; + + /* Check if we need to create or update or it is a NO-OP. */ + mac = zebra_evpn_mac_lookup(zevpn, macaddr); + if (!mac) { + if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug( + "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u%s", + sticky ? "sticky " : "", + prefix_mac2str(macaddr, buf, sizeof(buf)), + ifp->name, ifp->ifindex, vid, zevpn->vni, + local_inactive ? " local-inactive" : ""); + + mac = zebra_evpn_mac_add(zevpn, macaddr); + if (!mac) { + flog_err( + EC_ZEBRA_MAC_ADD_FAILED, + "Failed to add MAC %s intf %s(%u) VID %u VNI %u", + prefix_mac2str(macaddr, buf, sizeof(buf)), + ifp->name, ifp->ifindex, vid, zevpn->vni); + return -1; + } + SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); + if (sticky) + SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + inform_client = true; + } else { + if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug( + "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x", + sticky ? "sticky " : "", + prefix_mac2str(macaddr, buf, sizeof(buf)), + ifp->name, ifp->ifindex, vid, zevpn->vni, + local_inactive ? "local-inactive " : "", + mac->flags); + + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + struct interface *old_ifp; + vlanid_t old_vid; + bool old_static; + + zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid); + old_bgp_ready = + zebra_evpn_mac_is_ready_for_bgp(mac->flags); + old_local_inactive = + !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE); + old_static = zebra_evpn_mac_is_static(mac); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) + mac_sticky = true; + + /* + * Update any changes and if changes are relevant to + * BGP, note it. + */ + if (mac_sticky == sticky && old_ifp == ifp + && old_vid == vid + && old_local_inactive == local_inactive + && dp_static == old_static) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, " + "entry exists and has not changed ", + sticky ? "sticky " : "", + prefix_mac2str(macaddr, buf, + sizeof(buf)), + ifp->name, ifp->ifindex, vid, + zevpn->vni, + local_inactive + ? " local_inactive" + : ""); + return 0; + } + if (mac_sticky != sticky) { + if (sticky) + SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + else + UNSET_FLAG(mac->flags, + ZEBRA_MAC_STICKY); + 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; + /* force drop the peer/sync info as it is + * simply no longer relevant + */ + if (CHECK_FLAG(mac->flags, + ZEBRA_MAC_ALL_PEER_FLAGS)) { + zebra_evpn_mac_clear_sync_info(mac); + new_static = + zebra_evpn_mac_is_static(mac); + /* if we clear peer-flags we + * also need to notify the dataplane + * to drop the static flag + */ + if (old_static != new_static) + inform_dataplane = true; + } + } + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) + || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { + bool do_dad = false; + + /* + * MAC has either moved or was "internally" created due + * to a neighbor learn and is now actually learnt. If + * it was learnt as a remote sticky MAC, this is an + * operator error. + */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { + flog_warn( + EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, + "MAC %s already learnt as remote sticky MAC behind VTEP %s VNI %u", + prefix_mac2str(macaddr, buf, + sizeof(buf)), + inet_ntoa(mac->fwd_info.r_vtep_ip), + zevpn->vni); + return 0; + } + + /* If an actual move, compute MAC's seq number */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + mac->loc_seq = + MAX(mac->rem_seq + 1, mac->loc_seq); + vtep_ip = mac->fwd_info.r_vtep_ip; + /* Trigger DAD for remote MAC */ + do_dad = true; + } + + UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); + UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + es_change = zebra_evpn_local_mac_update_fwd_info( + mac, ifp, vid); + if (sticky) + SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + else + UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + /* + * We have to inform BGP of this MAC as well as process + * all neighbors. + */ + inform_client = true; + upd_neigh = true; + + zebra_evpn_dup_addr_detect_for_mac( + zvrf, mac, vtep_ip, do_dad, &is_dup_detect, + true); + if (is_dup_detect) { + inform_client = false; + upd_neigh = false; + } + } + } + + /* if the dataplane thinks the entry is sync but it is + * not sync in zebra we need to re-install to fixup + */ + if (dp_static) { + new_static = zebra_evpn_mac_is_static(mac); + if (!new_static) + inform_dataplane = true; + } + + if (local_inactive) + SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); + else + UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); + + new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + /* if local-activity has changed we need update bgp + * even if bgp already knows about the mac + */ + if ((old_local_inactive != local_inactive) + || (new_bgp_ready != old_bgp_ready)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug( + "local mac vni %u mac %s es %s seq %d f 0x%x%s", + zevpn->vni, + prefix_mac2str(macaddr, buf, sizeof(buf)), + mac->es ? mac->es->esi_str : "", mac->loc_seq, + mac->flags, + local_inactive ? " local-inactive" : ""); + inform_client = true; + } + + if (es_change) { + inform_client = true; + upd_neigh = true; + } + + /* Inform dataplane if required. */ + if (inform_dataplane) + zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, + false /* force_clear_static */, + __func__); + + /* Inform BGP if required. */ + if (inform_client) + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + new_bgp_ready); + + /* Process all neighbors associated with this MAC, if required. */ + if (upd_neigh) + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, + es_change); + + return 0; +} diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index 8bb18396a3..1ecd4aaf87 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -205,8 +205,6 @@ int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevi, zebra_mac_t *mac); int zebra_evpn_rem_mac_install(zebra_evpn_t *zevi, zebra_mac_t *mac, bool was_static); void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevi, zebra_mac_t *mac); -void zebra_evpn_mac_get_access_info(zebra_mac_t *mac, struct interface **ifpP, - vlanid_t *vid); zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevi, struct ethaddr *mac); zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevi, struct ethaddr *macaddr); int zebra_evpn_mac_del(zebra_evpn_t *zevi, zebra_mac_t *mac); @@ -214,18 +212,14 @@ int zebra_evpn_macip_send_msg_to_client(uint32_t id, struct ethaddr *macaddr, struct ipaddr *ip, uint8_t flags, uint32_t seq, int state, struct zebra_evpn_es *es, uint16_t cmd); -void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready, - bool new_bgp_ready); -void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, - zebra_mac_t *mac, - struct in_addr vtep_ip, bool do_dad, - bool *is_dup_detect, bool is_local); 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); +void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready, + bool new_bgp_ready); void zebra_evpn_mac_del_all(zebra_evpn_t *zevi, int uninstall, int upd_client, uint32_t flags); @@ -251,12 +245,11 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, struct in_addr vtep_ip, uint8_t flags, uint32_t seq, esi_t *esi); -// remove later -void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready, - bool new_bgp_ready); -bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac, - struct interface *ifp, vlanid_t vid); - +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); #ifdef __cplusplus } #endif diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 2d58c275d1..22194ee612 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -7998,21 +7998,8 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, bool dp_static) { zebra_evpn_t *zevpn; - zebra_mac_t *mac; struct zebra_vrf *zvrf; char buf[ETHER_ADDR_STRLEN]; - bool mac_sticky = false; - bool inform_client = false; - bool upd_neigh = false; - bool is_dup_detect = false; - struct in_addr vtep_ip = {.s_addr = 0}; - bool es_change = false; - bool new_bgp_ready; - /* assume inactive if not present or if not local */ - bool old_local_inactive = true; - bool old_bgp_ready = false; - bool inform_dataplane = false; - bool new_static = false; if (ifp == NULL) return -1; @@ -8047,222 +8034,9 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, return -1; } - /* Check if we need to create or update or it is a NO-OP. */ - mac = zebra_evpn_mac_lookup(zevpn, macaddr); - if (!mac) { - if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug( - "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u%s", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, vid, zevpn->vni, - local_inactive ? " local-inactive" : ""); - - mac = zebra_evpn_mac_add(zevpn, macaddr); - if (!mac) { - flog_err( - EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add MAC %s intf %s(%u) VID %u VNI %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, vid, zevpn->vni); - return -1; - } - SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); - es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); - if (sticky) - SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); - inform_client = true; - } else { - if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug( - "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, vid, zevpn->vni, - local_inactive ? "local-inactive " : "", - mac->flags); - - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { - struct interface *old_ifp; - vlanid_t old_vid; - bool old_static; - - zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid); - old_bgp_ready = - zebra_evpn_mac_is_ready_for_bgp(mac->flags); - old_local_inactive = !!(mac->flags & - ZEBRA_MAC_LOCAL_INACTIVE); - old_static = zebra_evpn_mac_is_static(mac); - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) - mac_sticky = true; - - /* - * Update any changes and if changes are relevant to - * BGP, note it. - */ - if (mac_sticky == sticky - && old_ifp == ifp - && old_vid == vid - && old_local_inactive == local_inactive - && dp_static == old_static) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, entry exists and has not changed ", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, - sizeof(buf)), - ifp->name, ifp->ifindex, vid, - zevpn->vni, - local_inactive ? - " local_inactive" : ""); - return 0; - } - if (mac_sticky != sticky) { - if (sticky) - SET_FLAG(mac->flags, - ZEBRA_MAC_STICKY); - else - UNSET_FLAG(mac->flags, - ZEBRA_MAC_STICKY); - 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; - /* force drop the peer/sync info as it is - * simply no longer relevant - */ - if (CHECK_FLAG(mac->flags, - ZEBRA_MAC_ALL_PEER_FLAGS)) { - zebra_evpn_mac_clear_sync_info(mac); - new_static = - zebra_evpn_mac_is_static(mac); - /* if we clear peer-flags we - * also need to notify the dataplane - * to drop the static flag - */ - if (old_static != new_static) - inform_dataplane = true; - } - } - } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || - CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { - bool do_dad = false; - - /* - * MAC has either moved or was "internally" created due - * to a neighbor learn and is now actually learnt. If - * it was learnt as a remote sticky MAC, this is an - * operator error. - */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { - flog_warn( - EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, - "MAC %s already learnt as remote sticky MAC behind VTEP %s VNI %u", - prefix_mac2str(macaddr, buf, - sizeof(buf)), - inet_ntoa(mac->fwd_info.r_vtep_ip), - zevpn->vni); - return 0; - } - - /* If an actual move, compute MAC's seq number */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - mac->loc_seq = MAX(mac->rem_seq + 1, - mac->loc_seq); - vtep_ip = mac->fwd_info.r_vtep_ip; - /* Trigger DAD for remote MAC */ - do_dad = true; - } - - UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); - UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); - SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); - es_change = zebra_evpn_local_mac_update_fwd_info( - mac, ifp, vid); - if (sticky) - SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); - else - UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); - /* - * We have to inform BGP of this MAC as well as process - * all neighbors. - */ - inform_client = true; - upd_neigh = true; - - zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, vtep_ip, do_dad, &is_dup_detect, - true); - if (is_dup_detect) { - inform_client = false; - upd_neigh = false; - } - } - } - - /* if the dataplane thinks the entry is sync but it is - * not sync in zebra we need to re-install to fixup - */ - if (dp_static) { - new_static = zebra_evpn_mac_is_static(mac); - if (!new_static) - inform_dataplane = true; - } - - if (local_inactive) - SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); - else - UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); - - new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - /* if local-activity has changed we need update bgp - * even if bgp already knows about the mac - */ - if ((old_local_inactive != local_inactive) || - (new_bgp_ready != old_bgp_ready)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug("local mac vni %u mac %s es %s seq %d f 0x%x%s", - zevpn->vni, - prefix_mac2str(macaddr, - buf, sizeof(buf)), - mac->es ? mac->es->esi_str : "", - mac->loc_seq, - mac->flags, - local_inactive ? - " local-inactive" : ""); - inform_client = true; - } - - if (es_change) { - inform_client = true; - upd_neigh = true; - } - - /* Inform dataplane if required. */ - if (inform_dataplane) - zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); - - /* Inform BGP if required. */ - if (inform_client) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); - - /* Process all neighbors associated with this MAC, if required. */ - if (upd_neigh) - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, - es_change); - - return 0; + return zebra_evpn_add_update_local_mac(zvrf, zevpn, ifp, macaddr, vid, + sticky, local_inactive, + dp_static); } /*