mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-14 16:29:32 +00:00
zebra: dup addr detect warn-only
Duplicate address detection warning only action upon an address detected as duplicate. Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
This commit is contained in:
parent
3950b52c54
commit
e22a946a89
@ -694,6 +694,33 @@ static struct log_ref ferr_zebra_err[] = {
|
||||
.suggestion =
|
||||
"Do not use v6 sourcedest routes, or upgrade your kernel.",
|
||||
},
|
||||
{
|
||||
.code = EC_ZEBRA_DUP_MAC_DETECTED,
|
||||
.title =
|
||||
"EVPN MAC is detected duplicate",
|
||||
.description =
|
||||
"Zebra has hit duplicate address detection threshold which means host MAC is moving.",
|
||||
.suggestion =
|
||||
"Check network topology to detect duplicate host MAC for correctness.",
|
||||
},
|
||||
{
|
||||
.code = EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
||||
.title =
|
||||
"EVPN IP is detected duplicate by MAC",
|
||||
.description =
|
||||
"Zebra has hit duplicate address detection threshold which means MAC-IP pair is moving.",
|
||||
.suggestion =
|
||||
"Check network topology to detect duplicate host MAC for correctness.",
|
||||
},
|
||||
{
|
||||
.code = EC_ZEBRA_DUP_IP_DETECTED,
|
||||
.title =
|
||||
"EVPN IP is detected duplicate",
|
||||
.description =
|
||||
"Zebra has hit duplicate address detection threshold which means host IP is moving.",
|
||||
.suggestion =
|
||||
"Check network topology to detect duplicate host IP for correctness.",
|
||||
},
|
||||
{
|
||||
.code = END_FERR,
|
||||
}
|
||||
|
@ -117,6 +117,9 @@ enum zebra_log_refs {
|
||||
EC_ZEBRA_MAX_LABELS_PUSH,
|
||||
EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
|
||||
EC_ZEBRA_UNSUPPORTED_V6_SRCDEST,
|
||||
EC_ZEBRA_DUP_MAC_DETECTED,
|
||||
EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
||||
EC_ZEBRA_DUP_IP_DETECTED,
|
||||
};
|
||||
|
||||
void zebra_error_init(void);
|
||||
|
@ -178,6 +178,10 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
|
||||
struct ipaddr *ip);
|
||||
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
|
||||
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
|
||||
static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
|
||||
zebra_mac_t *old_zmac,
|
||||
zebra_mac_t *new_zmac,
|
||||
zebra_neigh_t *nbr);
|
||||
static int remote_neigh_count(zebra_mac_t *zmac);
|
||||
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac);
|
||||
|
||||
@ -269,6 +273,49 @@ static int advertise_gw_macip_enabled(zebra_vni_t *zvni)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* As part Duplicate Address Detection (DAD) for IP mobility
|
||||
* MAC binding changes, ensure to inheirt duplicate flag
|
||||
*/
|
||||
static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
|
||||
zebra_mac_t *old_zmac,
|
||||
zebra_mac_t *new_zmac,
|
||||
zebra_neigh_t *nbr)
|
||||
{
|
||||
bool is_old_mac_dup = false;
|
||||
bool is_new_mac_dup = false;
|
||||
|
||||
if (!zvrf->dup_addr_detect)
|
||||
return 0;
|
||||
/* Check old or new MAC is detected as duplicate
|
||||
* mark this neigh as duplicate
|
||||
*/
|
||||
if (old_zmac)
|
||||
is_old_mac_dup = CHECK_FLAG(old_zmac->flags,
|
||||
ZEBRA_MAC_DUPLICATE);
|
||||
if (new_zmac)
|
||||
is_new_mac_dup = CHECK_FLAG(new_zmac->flags,
|
||||
ZEBRA_MAC_DUPLICATE);
|
||||
/* Old and/or new MAC can be in duplicate state,
|
||||
* based on that IP/Neigh Inherits the flag.
|
||||
* If New MAC is marked duplicate, inherit to the IP.
|
||||
* If old MAC is duplicate but new MAC is not, clear
|
||||
* duplicate flag for IP and reset detection params
|
||||
* and let IP DAD retrigger.
|
||||
*/
|
||||
if (is_new_mac_dup && !CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
||||
SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
||||
/* Capture Duplicate detection time */
|
||||
nbr->dad_dup_detect_time = monotime(NULL);
|
||||
return 1;
|
||||
} else if (is_old_mac_dup && !is_new_mac_dup) {
|
||||
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
||||
nbr->dad_count = 0;
|
||||
nbr->detect_start_time.tv_sec = 0;
|
||||
nbr->detect_start_time.tv_usec = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to determine maximum width of neighbor IP address for
|
||||
* display - just because we're dealing with IPv6 addresses that can
|
||||
@ -2059,12 +2106,16 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
{
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
char buf2[INET6_ADDRSTRLEN];
|
||||
struct zebra_vrf *zvrf;
|
||||
zebra_neigh_t *n = NULL;
|
||||
zebra_mac_t *zmac = NULL, *old_zmac = NULL;
|
||||
uint32_t old_mac_seq = 0, mac_new_seq = 0;
|
||||
bool upd_mac_seq = false;
|
||||
bool neigh_mac_change = false;
|
||||
bool check_rbit = false;
|
||||
bool neigh_on_hold = false;
|
||||
bool neigh_was_remote = false;
|
||||
struct in_addr vtep_ip = {.s_addr = 0};
|
||||
struct timeval elapsed = {0, 0};
|
||||
|
||||
/* Check if the MAC exists. */
|
||||
zmac = zvni_mac_lookup(zvni, macaddr);
|
||||
@ -2100,6 +2151,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
}
|
||||
}
|
||||
|
||||
zvrf = vrf_info_lookup(zvni->vrf_id);
|
||||
if (!zvrf)
|
||||
return -1;
|
||||
|
||||
/* Check if the neighbor exists. */
|
||||
n = zvni_neigh_lookup(zvni, ip);
|
||||
if (!n) {
|
||||
@ -2117,7 +2172,6 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
/* Set "local" forwarding info. */
|
||||
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
||||
n->ifindex = ifp->ifindex;
|
||||
check_rbit = true;
|
||||
} else {
|
||||
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
||||
bool mac_different;
|
||||
@ -2134,6 +2188,8 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
}
|
||||
|
||||
if (!mac_different) {
|
||||
bool is_neigh_freezed = false;
|
||||
|
||||
/* Only the router flag has changed. */
|
||||
if (is_router)
|
||||
SET_FLAG(n->flags,
|
||||
@ -2142,7 +2198,16 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
UNSET_FLAG(n->flags,
|
||||
ZEBRA_NEIGH_ROUTER_FLAG);
|
||||
|
||||
if (IS_ZEBRA_NEIGH_ACTIVE(n))
|
||||
/* Neigh is in freeze state and freeze action
|
||||
* is enabled, do not send update to client.
|
||||
*/
|
||||
is_neigh_freezed = (zvrf->dup_addr_detect &&
|
||||
zvrf->dad_freeze &&
|
||||
CHECK_FLAG(n->flags,
|
||||
ZEBRA_NEIGH_DUPLICATE));
|
||||
|
||||
if (IS_ZEBRA_NEIGH_ACTIVE(n) &&
|
||||
!is_neigh_freezed)
|
||||
return zvni_neigh_send_add_to_client(
|
||||
zvni->vni, ip, macaddr,
|
||||
n->flags, n->loc_seq);
|
||||
@ -2198,13 +2263,17 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
memcpy(&n->emac, macaddr, ETH_ALEN);
|
||||
listnode_add_sort(zmac->neigh_list, n);
|
||||
}
|
||||
|
||||
/* Based on Mobility event Scenario-B from the
|
||||
* draft, neigh's previous state was remote treat this
|
||||
* event for DAD.
|
||||
*/
|
||||
neigh_was_remote = true;
|
||||
vtep_ip = n->r_vtep_ip;
|
||||
/* Mark appropriately */
|
||||
UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
||||
n->r_vtep_ip.s_addr = 0;
|
||||
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
||||
n->ifindex = ifp->ifindex;
|
||||
check_rbit = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2221,12 +2290,98 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
MAX(seq1, seq2) : zmac->loc_seq;
|
||||
}
|
||||
|
||||
/*Mark Router flag (R-bit) */
|
||||
/* Mark Router flag (R-bit) */
|
||||
if (is_router)
|
||||
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
||||
else
|
||||
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
||||
|
||||
/* Check old and/or new MAC detected as duplicate mark
|
||||
* the neigh as duplicate
|
||||
*/
|
||||
if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) {
|
||||
flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
||||
"VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC",
|
||||
zvni->vni,
|
||||
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
||||
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
||||
}
|
||||
|
||||
/* Duplicate Address Detection (DAD) is enabled.
|
||||
* Based on Mobility event Scenario-B from the
|
||||
* draft, IP/Neigh's MAC binding changed and
|
||||
* neigh's previous state was remote, trigger DAD.
|
||||
*/
|
||||
if (zvrf->dup_addr_detect) {
|
||||
/* Neigh could have inherit dup flag or IP DAD
|
||||
* detected earlier
|
||||
*/
|
||||
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s: duplicate addr MAC %s IP %s skip update to client, learn count %u recover time %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr,
|
||||
buf, sizeof(buf)),
|
||||
ipaddr2str(ip, buf2, sizeof(buf2)),
|
||||
n->dad_count,
|
||||
zvrf->dad_freeze_time);
|
||||
|
||||
/* In case of warn-only, inform client and update neigh
|
||||
*/
|
||||
if (zvrf->dad_freeze)
|
||||
neigh_on_hold = true;
|
||||
|
||||
goto send_notif;
|
||||
}
|
||||
/* MAC binding changed and previous state was remote */
|
||||
if (!(neigh_mac_change && neigh_was_remote))
|
||||
goto send_notif;
|
||||
|
||||
/* First check if neigh is already marked duplicate via
|
||||
* MAC dup detection, before firing M Seconds
|
||||
* duplicate detection.
|
||||
* RFC-7432: A PE/VTEP that detects a MAC mobility
|
||||
* event via local learning starts an M-second timer.
|
||||
*
|
||||
* Check if detection time (M-secs) expired.
|
||||
* Reset learn count and detection start time.
|
||||
*/
|
||||
monotime_since(&n->detect_start_time, &elapsed);
|
||||
if (n->dad_count == 0 || elapsed.tv_sec > zvrf->dad_time) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("%s: duplicate addr MAC %s detection time passed, reset learn count %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr, buf,
|
||||
sizeof(buf)),
|
||||
n->dad_count);
|
||||
n->dad_count = 0;
|
||||
/* Start dup. detection time */
|
||||
monotime(&n->detect_start_time);
|
||||
}
|
||||
|
||||
n->dad_count++;
|
||||
|
||||
if (n->dad_count >= zvrf->dad_max_moves) {
|
||||
flog_warn(EC_ZEBRA_DUP_IP_DETECTED,
|
||||
"VNI %u: MAC %s IP %s detected as duplicate during local update, last VTEP %s",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&n->emac, buf, sizeof(buf)),
|
||||
ipaddr2str(ip, buf2, sizeof(buf2)),
|
||||
inet_ntoa(vtep_ip));
|
||||
|
||||
/* Mark Duplicate */
|
||||
SET_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE);
|
||||
|
||||
/* Capture Duplicate detection time */
|
||||
n->dad_dup_detect_time = monotime(NULL);
|
||||
|
||||
if (zvrf->dad_freeze)
|
||||
neigh_on_hold = true;
|
||||
}
|
||||
}
|
||||
|
||||
send_notif:
|
||||
/* Before we program this in BGP, we need to check if MAC is locally
|
||||
* learnt. If not, force neighbor to be inactive and reset its seq.
|
||||
*/
|
||||
@ -2237,9 +2392,6 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!check_rbit)
|
||||
return 0;
|
||||
|
||||
/* If the MAC's sequence number has changed, inform the MAC and all
|
||||
* neighbors associated with the MAC to BGP, else just inform this
|
||||
* neighbor.
|
||||
@ -2260,8 +2412,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
|
||||
ZEBRA_NEIGH_SET_ACTIVE(n);
|
||||
n->loc_seq = zmac->loc_seq;
|
||||
|
||||
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
|
||||
if (!neigh_on_hold)
|
||||
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
|
||||
n->flags, n->loc_seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zvni_remote_neigh_update(zebra_vni_t *zvni,
|
||||
@ -4167,17 +4321,22 @@ static void process_remote_macip_add(vni_t vni,
|
||||
{
|
||||
zebra_vni_t *zvni;
|
||||
zebra_vtep_t *zvtep;
|
||||
zebra_mac_t *mac, *old_mac;
|
||||
zebra_mac_t *mac = NULL, *old_mac = NULL;
|
||||
zebra_neigh_t *n = NULL;
|
||||
int update_mac = 0, update_neigh = 0;
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
char buf1[INET6_ADDRSTRLEN];
|
||||
struct interface *ifp = NULL;
|
||||
struct zebra_if *zif = NULL;
|
||||
struct zebra_vrf *zvrf;
|
||||
uint32_t tmp_seq;
|
||||
bool sticky;
|
||||
bool remote_gw;
|
||||
bool is_router;
|
||||
bool do_dad = false;
|
||||
bool is_dup_detect = false;
|
||||
struct listnode *node = NULL;
|
||||
struct timeval elapsed = {0, 0};
|
||||
|
||||
/* Locate VNI hash entry - expected to exist. */
|
||||
zvni = zvni_lookup(vni);
|
||||
@ -4235,6 +4394,10 @@ static void process_remote_macip_add(vni_t vni,
|
||||
return;
|
||||
}
|
||||
|
||||
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
||||
if (!zvrf)
|
||||
return;
|
||||
|
||||
/* check if the remote MAC is unknown or has a change.
|
||||
* If so, that needs to be updated first. Note that client could
|
||||
* install MAC and MACIP separately or just install the latter.
|
||||
@ -4296,6 +4459,19 @@ static void process_remote_macip_add(vni_t vni,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check MAC's curent state is local (this is the case
|
||||
* where MAC has moved from L->R) and check previous
|
||||
* detection started via local learning.
|
||||
* RFC-7432: A PE/VTEP that detects a MAC mobility
|
||||
* event via local learning starts an M-second timer.
|
||||
*
|
||||
* VTEP-IP or seq. change along is not considered
|
||||
* for dup. detection.
|
||||
*/
|
||||
if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) &&
|
||||
mac->dad_count)
|
||||
do_dad = true;
|
||||
|
||||
/* Remove local MAC from BGP. */
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
||||
zvni_mac_send_del_to_client(zvni->vni, macaddr);
|
||||
@ -4316,11 +4492,99 @@ static void process_remote_macip_add(vni_t vni,
|
||||
else
|
||||
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
|
||||
|
||||
if (zvrf->dup_addr_detect && do_dad) {
|
||||
/* MAC is detected as duplicate, hold on to
|
||||
* install as remote entry.
|
||||
*/
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s: duplicate addr MAC %s skip installing, learn count %u recover time %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr,
|
||||
buf, sizeof(buf)),
|
||||
mac->dad_count,
|
||||
zvrf->dad_freeze_time);
|
||||
/* Do not install MAC but process neigh
|
||||
* due to the remote MAC add.
|
||||
*/
|
||||
goto process_neigh;
|
||||
}
|
||||
|
||||
/* Check if detection time (M-secs) expired.
|
||||
* Reset learn count and detection start time.
|
||||
*/
|
||||
monotime_since(&mac->detect_start_time, &elapsed);
|
||||
if (elapsed.tv_sec > zvrf->dad_time) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("%s: duplicate addr MAC %s flags 0%x detection time passed, reset learn count %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr, buf,
|
||||
sizeof(buf)),
|
||||
mac->flags, mac->dad_count);
|
||||
/* Reset learn count but do not start detection
|
||||
* during remote learn.
|
||||
* Next local learn event start time wil be
|
||||
* resetted.
|
||||
*/
|
||||
mac->dad_count = 0;
|
||||
} else {
|
||||
/* Increment detection count while in probe
|
||||
* window
|
||||
*/
|
||||
mac->dad_count++;
|
||||
}
|
||||
|
||||
if (mac->dad_count >= zvrf->dad_max_moves) {
|
||||
flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
|
||||
"VNI %u: MAC %s detected as duplicate during remote update, from VTEP %s",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&mac->macaddr,
|
||||
buf, sizeof(buf)),
|
||||
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
||||
|
||||
SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
||||
|
||||
/* Capture Duplicate detection time */
|
||||
mac->dad_dup_detect_time = monotime(NULL);
|
||||
|
||||
/* Mark all IPs/Neighs as duplicate associcated
|
||||
* with this MAC
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list,
|
||||
node, n)) {
|
||||
/* Ony Mark IPs which are Remote */
|
||||
if (!CHECK_FLAG(n->flags,
|
||||
ZEBRA_NEIGH_REMOTE))
|
||||
continue;
|
||||
|
||||
SET_FLAG(n->flags,
|
||||
ZEBRA_NEIGH_DUPLICATE);
|
||||
|
||||
/* Capture Duplicate detection time */
|
||||
n->dad_dup_detect_time = monotime(NULL);
|
||||
|
||||
flog_warn(
|
||||
EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
||||
"VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&mac->macaddr,
|
||||
buf, sizeof(buf)),
|
||||
ipaddr2str(&n->ip, buf1,
|
||||
sizeof(buf1)));
|
||||
}
|
||||
|
||||
if (zvrf->dad_freeze)
|
||||
is_dup_detect = true;
|
||||
}
|
||||
|
||||
}
|
||||
process_neigh:
|
||||
zvni_process_neigh_on_remote_mac_add(zvni, mac);
|
||||
|
||||
/* Install the entry. */
|
||||
zvni_mac_install(zvni, mac);
|
||||
|
||||
if (!is_dup_detect)
|
||||
zvni_mac_install(zvni, mac);
|
||||
}
|
||||
|
||||
/* Update seq number. */
|
||||
@ -4332,6 +4596,9 @@ static void process_remote_macip_add(vni_t vni,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset flag */
|
||||
do_dad = false;
|
||||
|
||||
/* Check if the remote neighbor itself is unknown or has a
|
||||
* change. If so, create or update and then install the entry.
|
||||
*/
|
||||
@ -4406,6 +4673,25 @@ static void process_remote_macip_add(vni_t vni,
|
||||
}
|
||||
listnode_add_sort(mac->neigh_list, n);
|
||||
memcpy(&n->emac, macaddr, ETH_ALEN);
|
||||
|
||||
/* Check Neigh's curent state is local
|
||||
* (this is the case where neigh/host has moved
|
||||
* from L->R) and check previous detction
|
||||
* started via local learning.
|
||||
*
|
||||
* RFC-7432: A PE/VTEP that detects a MAC
|
||||
* mobilit event via local learning starts
|
||||
* an M-second timer.
|
||||
* VTEP-IP or seq. change along is not
|
||||
* considered for dup. detection.
|
||||
*
|
||||
* Mobilty event scenario-B IP-MAC binding
|
||||
* changed.
|
||||
*/
|
||||
if ((!CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
|
||||
&& n->dad_count)
|
||||
do_dad = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -4420,8 +4706,96 @@ static void process_remote_macip_add(vni_t vni,
|
||||
else
|
||||
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
|
||||
|
||||
/* Check old or new MAC detected as duplicate,
|
||||
* inherit duplicate flag to this neigh.
|
||||
*/
|
||||
if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_mac,
|
||||
mac, n)) {
|
||||
flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
|
||||
"VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
|
||||
ipaddr2str(&n->ip, buf1, sizeof(buf1)));
|
||||
}
|
||||
|
||||
if (zvrf->dup_addr_detect) {
|
||||
/* IP is detected as duplicate or inherit dup
|
||||
* state, hold on to install as remote entry
|
||||
* only if freeze is enabled.
|
||||
*/
|
||||
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s: duplicate addr MAC %s IP %s skip installing, learn count %u recover time %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr,
|
||||
buf, sizeof(buf)),
|
||||
ipaddr2str(ipaddr, buf1,
|
||||
sizeof(buf1)),
|
||||
n->dad_count,
|
||||
zvrf->dad_freeze_time);
|
||||
|
||||
if (zvrf->dad_freeze)
|
||||
is_dup_detect = true;
|
||||
/* warn-only action, neigh will be installed.
|
||||
* freeze action, it wil not be installed.
|
||||
*/
|
||||
goto install_neigh;
|
||||
}
|
||||
|
||||
if (!do_dad)
|
||||
goto install_neigh;
|
||||
|
||||
/* Check if detection time (M-secs) expired.
|
||||
* Reset learn count and detection start time.
|
||||
* During remote mac add, count should already be 1
|
||||
* via local learning.
|
||||
*/
|
||||
monotime_since(&n->detect_start_time, &elapsed);
|
||||
if (elapsed.tv_sec > zvrf->dad_time) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("%s: duplicate addr MAC %s IP %s flags 0x%x detection time passed, reset learn count %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr, buf,
|
||||
sizeof(buf)),
|
||||
ipaddr2str(ipaddr, buf1,
|
||||
sizeof(buf1)),
|
||||
n->flags,
|
||||
n->dad_count);
|
||||
/* Reset learn count but do not start detection
|
||||
* during remote learn event.
|
||||
*/
|
||||
n->dad_count = 0;
|
||||
} else {
|
||||
/* Increment detection count while in probe
|
||||
* window
|
||||
*/
|
||||
n->dad_count++;
|
||||
}
|
||||
|
||||
if (n->dad_count >= zvrf->dad_max_moves) {
|
||||
flog_warn(EC_ZEBRA_DUP_IP_DETECTED,
|
||||
"VNI %u: MAC %s IP %s detected as duplicate during remote update, from VTEP %s",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&mac->macaddr,
|
||||
buf, sizeof(buf)),
|
||||
ipaddr2str(ipaddr, buf1,
|
||||
sizeof(buf1)),
|
||||
inet_ntoa(n->r_vtep_ip));
|
||||
|
||||
SET_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE);
|
||||
|
||||
/* Capture Duplicate detection time */
|
||||
n->dad_dup_detect_time = monotime(NULL);
|
||||
|
||||
if (zvrf->dad_freeze)
|
||||
is_dup_detect = true;
|
||||
}
|
||||
}
|
||||
install_neigh:
|
||||
/* Install the entry. */
|
||||
zvni_neigh_install(zvni, n);
|
||||
if (!is_dup_detect)
|
||||
zvni_neigh_install(zvni, n);
|
||||
}
|
||||
|
||||
/* Update seq number. */
|
||||
@ -5907,10 +6281,16 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
||||
{
|
||||
zebra_vni_t *zvni;
|
||||
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;
|
||||
zebra_neigh_t *n = NULL;
|
||||
struct listnode *node = NULL;
|
||||
struct in_addr vtep_ip = {.s_addr = 0};
|
||||
struct timeval elapsed = {0, 0};
|
||||
char buf2[INET6_ADDRSTRLEN];
|
||||
|
||||
/* We are interested in MACs only on ports or (port, VLAN) that
|
||||
* map to a VNI.
|
||||
@ -5933,6 +6313,10 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
||||
return -1;
|
||||
}
|
||||
|
||||
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
|
||||
if (!zvrf)
|
||||
return -1;
|
||||
|
||||
/* Check if we need to create or update or it is a NO-OP. */
|
||||
mac = zvni_mac_lookup(zvni, macaddr);
|
||||
if (!mac) {
|
||||
@ -6006,6 +6390,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
||||
|
||||
} 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
|
||||
@ -6025,9 +6410,14 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
||||
}
|
||||
|
||||
/* If an actual move, compute MAC's seq number */
|
||||
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
|
||||
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);
|
||||
@ -6044,9 +6434,113 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
||||
*/
|
||||
inform_client = true;
|
||||
upd_neigh = true;
|
||||
|
||||
if (zvrf->dup_addr_detect && do_dad) {
|
||||
/* MAC is detected as duplicate, hold on
|
||||
* advertising to BGP.
|
||||
*/
|
||||
if (CHECK_FLAG(mac->flags,
|
||||
ZEBRA_MAC_DUPLICATE)) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"%s: duplicate addr MAC %s skip update to client, learn count %u recover time %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(macaddr,
|
||||
buf, sizeof(buf)),
|
||||
mac->dad_count,
|
||||
zvrf->dad_freeze_time);
|
||||
/* For duplicate MAC do not update
|
||||
* client but update neigh due to
|
||||
* this MAC update.
|
||||
*/
|
||||
if (zvrf->dad_freeze)
|
||||
inform_client = false;
|
||||
|
||||
goto send_notif;
|
||||
}
|
||||
|
||||
/* Check if detection time (M-secs) expired.
|
||||
* Reset learn count and detection start time.
|
||||
*/
|
||||
monotime_since(&mac->detect_start_time,
|
||||
&elapsed);
|
||||
if (mac->dad_count == 0 ||
|
||||
elapsed.tv_sec >= zvrf->dad_time) {
|
||||
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix_mac2str(
|
||||
macaddr, buf,
|
||||
sizeof(buf)),
|
||||
mac->flags,
|
||||
mac->dad_count);
|
||||
|
||||
mac->dad_count = 0;
|
||||
/* Capture start dup. detection time */
|
||||
monotime(&mac->detect_start_time);
|
||||
}
|
||||
|
||||
/* Increment move count */
|
||||
mac->dad_count++;
|
||||
|
||||
if (mac->dad_count >= zvrf->dad_max_moves) {
|
||||
flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
|
||||
"VNI %u: MAC %s detected as duplicate during local update, last VTEP %s",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&mac->macaddr,
|
||||
buf, sizeof(buf)),
|
||||
inet_ntoa(vtep_ip));
|
||||
|
||||
SET_FLAG(mac->flags,
|
||||
ZEBRA_MAC_DUPLICATE);
|
||||
|
||||
/* Capture Duplicate detection time */
|
||||
mac->dad_dup_detect_time =
|
||||
monotime(NULL);
|
||||
|
||||
/* Mark all IPs/Neighs as duplicate
|
||||
* associcated with this MAC
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS_RO(
|
||||
mac->neigh_list,
|
||||
node, n)) {
|
||||
|
||||
/* Ony Mark IPs which are Local
|
||||
*/
|
||||
if (!CHECK_FLAG(n->flags,
|
||||
ZEBRA_NEIGH_LOCAL))
|
||||
continue;
|
||||
|
||||
SET_FLAG(n->flags,
|
||||
ZEBRA_NEIGH_DUPLICATE);
|
||||
|
||||
n->dad_dup_detect_time =
|
||||
monotime(NULL);
|
||||
|
||||
flog_warn(
|
||||
EC_ZEBRA_DUP_IP_INHERIT_DETECTED
|
||||
,
|
||||
"VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC",
|
||||
zvni->vni,
|
||||
prefix_mac2str(&mac->macaddr,
|
||||
buf, sizeof(buf)),
|
||||
ipaddr2str(&n->ip, buf2,
|
||||
sizeof(buf2)));
|
||||
}
|
||||
|
||||
/* Do not inform to client (BGPd),
|
||||
* upd_neigh for neigh sequence change.
|
||||
*/
|
||||
if (zvrf->dad_freeze)
|
||||
inform_client = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_notif:
|
||||
|
||||
/* Inform BGP if required. */
|
||||
if (inform_client) {
|
||||
if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
|
||||
|
@ -249,6 +249,10 @@ struct zebra_mac_t_ {
|
||||
#define ZEBRA_MAC_DEF_GW 0x20
|
||||
/* remote VTEP advertised MAC as default GW */
|
||||
#define ZEBRA_MAC_REMOTE_DEF_GW 0x40
|
||||
#define ZEBRA_MAC_DUPLICATE 0x80
|
||||
|
||||
/* back pointer to zvni */
|
||||
zebra_vni_t *zvni;
|
||||
|
||||
/* Local or remote info. */
|
||||
union {
|
||||
@ -269,6 +273,15 @@ struct zebra_mac_t_ {
|
||||
|
||||
/* list of hosts pointing to this remote RMAC */
|
||||
struct host_rb_tree_entry host_rb;
|
||||
|
||||
/* Duplicate mac detection */
|
||||
uint32_t dad_count;
|
||||
|
||||
struct thread *dad_mac_auto_recovery_timer;
|
||||
|
||||
struct timeval detect_start_time;
|
||||
|
||||
time_t dad_dup_detect_time;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -336,6 +349,7 @@ struct zebra_neigh_t_ {
|
||||
#define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */
|
||||
#define ZEBRA_NEIGH_DEF_GW 0x08
|
||||
#define ZEBRA_NEIGH_ROUTER_FLAG 0x10
|
||||
#define ZEBRA_NEIGH_DUPLICATE 0x20
|
||||
|
||||
enum zebra_neigh_state state;
|
||||
|
||||
@ -354,6 +368,15 @@ struct zebra_neigh_t_ {
|
||||
|
||||
/* list of hosts pointing to this remote NH entry */
|
||||
struct host_rb_tree_entry host_rb;
|
||||
|
||||
/* Duplicate ip detection */
|
||||
uint32_t dad_count;
|
||||
|
||||
struct thread *dad_ip_auto_recovery_timer;
|
||||
|
||||
struct timeval detect_start_time;
|
||||
|
||||
time_t dad_dup_detect_time;
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user