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 <pat@voltanet.io>
This commit is contained in:
Pat Ruddy 2020-07-23 15:04:53 -07:00
parent 19fdd1be29
commit d9d3455e09
3 changed files with 258 additions and 251 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
/*