From 09de9258a950b42219d38a541e10e2ab654c1aae Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Sun, 4 Nov 2018 10:55:39 -0800 Subject: [PATCH] zebra: dup addr detect clear command Signed-off-by: Chirag Shah --- zebra/zebra_vty.c | 50 +++++++ zebra/zebra_vxlan.c | 335 ++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_vxlan.h | 12 ++ 3 files changed, 397 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 1b8a12e319..536fdabcbc 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2277,6 +2277,55 @@ DEFUN (show_pbr_iptable, return CMD_SUCCESS; } +DEFPY (clear_evpn_dup_addr, + clear_evpn_dup_addr_cmd, + "clear evpn dup-addr vni ]>", + CLEAR_STR + "EVPN\n" + "Duplicate address \n" + "VxLAN Network Identifier\n" + "VNI number\n" + "All VNIs\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IPv4 address\n" + "IPv6 address\n") +{ + struct zebra_vrf *zvrf; + vni_t vni = 0; + struct ipaddr host_ip = {.ipa_type = IPADDR_NONE }; + struct ethaddr mac_addr; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (vni_val) { + vni = strtoul(vni_val, NULL, 10); + + if (mac_val) { + prefix_str2mac(mac_val, &mac_addr); + zebra_vxlan_clear_dup_detect_vni_mac(vty, zvrf, vni, + &mac_addr); + } else if (ip) { + if (sockunion_family(ip) == AF_INET) { + host_ip.ipa_type = IPADDR_V4; + host_ip.ipaddr_v4.s_addr = sockunion2ip(ip); + } else { + host_ip.ipa_type = IPADDR_V6; + memcpy(&host_ip.ipaddr_v6, &ip->sin6.sin6_addr, + sizeof(struct in6_addr)); + } + zebra_vxlan_clear_dup_detect_vni_ip(vty, zvrf, vni, + &host_ip); + } else + zebra_vxlan_clear_dup_detect_vni(vty, zvrf, vni); + + } else { + zebra_vxlan_clear_dup_detect_vni_all(vty, zvrf); + } + + return CMD_SUCCESS; +} + /* Static ip route configuration write function. */ static int zebra_ip_config(struct vty *vty) { @@ -2847,6 +2896,7 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd); + install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd); install_element(VIEW_NODE, &show_pbr_ipset_cmd); install_element(VIEW_NODE, &show_pbr_iptable_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 00ba39d92f..702aa5812d 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -6011,6 +6011,335 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty, } +void zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty, + struct zebra_vrf *zvrf, + vni_t vni, struct ethaddr *macaddr) +{ + zebra_vni_t *zvni; + zebra_mac_t *mac; + struct listnode *node = NULL; + zebra_neigh_t *nbr = NULL; + + if (!is_evpn_enabled()) + return; + zvni = zvni_lookup(vni); + if (!zvni) { + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + + mac = zvni_mac_lookup(zvni, macaddr); + if (!mac) { + vty_out(vty, "%% Requested MAC does not exist in VNI %u\n", + vni); + return; + } + + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { + vty_out(vty, "%% Requested MAC is not duplicate detected\n"); + return; + } + + /* Remove all IPs as duplicate associcated with this MAC */ + for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { + /* For local neigh mark inactive so MACIP update is generated + * to BGP. This is a scenario where MAC update received + * and detected as duplicate which marked neigh as duplicate. + * Later local neigh update did not get a chance to relay + * to BGP. Similarly remote macip update, neigh needs to be + * installed locally. + */ + if (nbr->dad_count) { + if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) + ZEBRA_NEIGH_SET_INACTIVE(nbr); + else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) + zvni_neigh_install(zvni, nbr); + } + + UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); + nbr->dad_count = 0; + nbr->detect_start_time.tv_sec = 0; + nbr->dad_dup_detect_time = 0; + } + + UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); + mac->dad_count = 0; + mac->detect_start_time.tv_sec = 0; + mac->detect_start_time.tv_usec = 0; + mac->dad_dup_detect_time = 0; + THREAD_OFF(mac->dad_mac_auto_recovery_timer); + + /* Local: Notify Peer VTEPs, Remote: Install the entry */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + /* Inform to BGP */ + if (zvni_mac_send_add_to_client(zvni->vni, + &mac->macaddr, + mac->flags, + mac->loc_seq)) + return; + + /* Process all neighbors associated with this MAC. */ + zvni_process_neigh_on_local_mac_change(zvni, mac, 0); + + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + zvni_process_neigh_on_remote_mac_add(zvni, mac); + + /* Install the entry. */ + zvni_mac_install(zvni, mac); + } + +} + +void zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty, + struct zebra_vrf *zvrf, + vni_t vni, struct ipaddr *ip) +{ + zebra_vni_t *zvni; + zebra_neigh_t *nbr; + zebra_mac_t *mac; + char buf[INET6_ADDRSTRLEN]; + char buf2[ETHER_ADDR_STRLEN]; + + if (!is_evpn_enabled()) + return; + + zvni = zvni_lookup(vni); + if (!zvni) { + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + + nbr = zvni_neigh_lookup(zvni, ip); + if (!nbr) { + vty_out(vty, + "%% Requested host IP does not exist in VNI %u\n", + vni); + return; + } + + ipaddr2str(&nbr->ip, buf, sizeof(buf)); + + if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { + vty_out(vty, + "%% Requsted host IP %s is not duplicate detected\n", + buf); + return; + } + + mac = zvni_mac_lookup(zvni, &nbr->emac); + + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { + vty_out(vty, + "%% Requested IP's associated MAC %s is still in duplicate state\n", + prefix_mac2str(&nbr->emac, buf2, sizeof(buf2))); + return; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: clear neigh %s in dup state, flags 0x%x seq %u", + __PRETTY_FUNCTION__, buf, nbr->flags, + nbr->loc_seq); + + 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; + nbr->dad_dup_detect_time = 0; + THREAD_OFF(nbr->dad_ip_auto_recovery_timer); + + if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) { + zvni_neigh_send_add_to_client(zvni->vni, ip, + &nbr->emac, + nbr->flags, nbr->loc_seq); + } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { + zvni_neigh_install(zvni, nbr); + } + +} + +static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) +{ + struct mac_walk_ctx *wctx = ctxt; + zebra_mac_t *mac; + zebra_vni_t *zvni; + struct listnode *node = NULL; + zebra_neigh_t *nbr = NULL; + + mac = (zebra_mac_t *)backet->data; + if (!mac) + return; + + zvni = wctx->zvni; + + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) + return; + + UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); + mac->dad_count = 0; + mac->detect_start_time.tv_sec = 0; + mac->detect_start_time.tv_usec = 0; + mac->dad_dup_detect_time = 0; + THREAD_OFF(mac->dad_mac_auto_recovery_timer); + + /* Remove all IPs as duplicate associcated with this MAC */ + for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { + if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) + && nbr->dad_count) + ZEBRA_NEIGH_SET_INACTIVE(nbr); + + UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); + nbr->dad_count = 0; + nbr->detect_start_time.tv_sec = 0; + nbr->dad_dup_detect_time = 0; + } + + /* Local: Notify Peer VTEPs, Remote: Install the entry */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + /* Inform to BGP */ + if (zvni_mac_send_add_to_client(zvni->vni, + &mac->macaddr, + mac->flags, mac->loc_seq)) + return; + + /* Process all neighbors associated with this MAC. */ + zvni_process_neigh_on_local_mac_change(zvni, mac, 0); + + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + zvni_process_neigh_on_remote_mac_add(zvni, mac); + + /* Install the entry. */ + zvni_mac_install(zvni, mac); + } +} + +static void zvni_clear_dup_neigh_hash(struct hash_backet *backet, void *ctxt) +{ + struct neigh_walk_ctx *wctx = ctxt; + zebra_neigh_t *nbr; + zebra_vni_t *zvni; + char buf[INET6_ADDRSTRLEN]; + + nbr = (zebra_neigh_t *)backet->data; + if (!nbr) + return; + + zvni = wctx->zvni; + + if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) + return; + + if (IS_ZEBRA_DEBUG_VXLAN) { + ipaddr2str(&nbr->ip, buf, sizeof(buf)); + zlog_debug( + "%s: clear neigh %s dup state, flags 0x%x seq %u", + __PRETTY_FUNCTION__, buf, + nbr->flags, nbr->loc_seq); + } + + 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; + nbr->dad_dup_detect_time = 0; + THREAD_OFF(nbr->dad_ip_auto_recovery_timer); + + if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) { + zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip, + &nbr->emac, + nbr->flags, nbr->loc_seq); + } else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { + zvni_neigh_install(zvni, nbr); + } +} + +static void zvni_clear_dup_detect_hash_vni_all(struct hash_backet *backet, + void **args) +{ + struct vty *vty; + zebra_vni_t *zvni; + struct zebra_vrf *zvrf; + struct mac_walk_ctx m_wctx; + struct neigh_walk_ctx n_wctx; + + zvni = (zebra_vni_t *)backet->data; + if (!zvni) + return; + + vty = (struct vty *)args[0]; + zvrf = (struct zebra_vrf *)args[1]; + + if (hashcount(zvni->neigh_table)) { + memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); + n_wctx.vty = vty; + n_wctx.zvni = zvni; + n_wctx.zvrf = zvrf; + hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash, + &n_wctx); + } + + if (num_valid_macs(zvni)) { + memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); + m_wctx.zvni = zvni; + m_wctx.vty = vty; + m_wctx.zvrf = zvrf; + hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx); + } + +} + +void zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, + struct zebra_vrf *zvrf) +{ + void *args[2]; + + if (!is_evpn_enabled()) + return; + + args[0] = vty; + args[1] = zvrf; + + hash_iterate(zvrf->vni_table, + (void (*)(struct hash_backet *, void *)) + zvni_clear_dup_detect_hash_vni_all, args); + +} + +void zebra_vxlan_clear_dup_detect_vni(struct vty *vty, + struct zebra_vrf *zvrf, + vni_t vni) +{ + zebra_vni_t *zvni; + struct mac_walk_ctx m_wctx; + struct neigh_walk_ctx n_wctx; + + if (!is_evpn_enabled()) + return; + + zvni = zvni_lookup(vni); + if (!zvni) { + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + + if (hashcount(zvni->neigh_table)) { + memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); + n_wctx.vty = vty; + n_wctx.zvni = zvni; + n_wctx.zvrf = zvrf; + hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash, + &n_wctx); + } + + if (num_valid_macs(zvni)) { + memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); + m_wctx.zvni = zvni; + m_wctx.vty = vty; + m_wctx.zvrf = zvrf; + hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx); + } + +} + /* * Display MACs for a VNI from specific VTEP (VTY command handler). */ @@ -6200,6 +6529,12 @@ void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS) STREAM_GETL(s, freeze); STREAM_GETL(s, freeze_time); + /* DAD previous state was enabled, and new state is disable, + * clear all duplicate detected addresses. + */ + if (zvrf->dup_addr_detect && !dup_addr_detect) + zebra_vxlan_clear_dup_detect_vni_all(NULL, zvrf); + zvrf->dup_addr_detect = dup_addr_detect; zvrf->dad_time = time; zvrf->dad_max_moves = max_moves; diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index b33219d5e9..bf6e4290dc 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -181,5 +181,17 @@ extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, struct ipaddr *vtep_ip, struct prefix *host_prefix); +extern void zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty, + struct zebra_vrf *zvrf, + vni_t vni, + struct ethaddr *macaddr); +extern void zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty, + struct zebra_vrf *zvrf, + vni_t vni, struct ipaddr *ip); +extern void zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, + struct zebra_vrf *zvrf); +extern void zebra_vxlan_clear_dup_detect_vni(struct vty *vty, + struct zebra_vrf *zvrf, + vni_t vni); #endif /* _ZEBRA_VXLAN_H */