]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #3356 from opensourcerouting/router-id-loopbacks
authorRuss White <russ@riw.us>
Mon, 26 Nov 2018 13:07:28 +0000 (08:07 -0500)
committerGitHub <noreply@github.com>
Mon, 26 Nov 2018 13:07:28 +0000 (08:07 -0500)
zebra: improve identification of loopback interfaces in the router-id code

59 files changed:
bgpd/bgp_attr.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_nht.c
bgpd/bgp_pbr.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
configure.ac
doc/developer/index.rst
doc/developer/vtysh.rst [new file with mode: 0644]
doc/developer/workflow.rst
isisd/fabricd.c
isisd/isis_lsp.c
isisd/isis_mt.c
isisd/isis_pdu.c
isisd/isis_route.c
isisd/isis_tlvs.c
lib/agg_table.h
lib/command_py.c
lib/distribute.c
lib/log.c
lib/monotime.h
lib/openbsd-tree.h
lib/subdir.am
lib/thread.h
lib/vty.c
lib/yang.c
lib/yang.h
lib/zclient.h
ospfd/ospf_packet.c
pbrd/pbr_nht.c
pimd/pim_ifchannel.c
pimd/pim_zebra.c
python/clidef.py
ripd/subdir.am
staticd/static_routes.c
staticd/static_routes.h
staticd/static_zebra.c
tools/checkpatch.pl
vtysh/vtysh.c
yang/.gitignore [new file with mode: 0644]
yang/embedmodel.py [new file with mode: 0644]
yang/subdir.am
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_errors.c
zebra/zebra_errors.h
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.c
zebra/zserv.h

index 65a46bb9657b797b9a9a2ac9d39b34e6144cfaad..87ebb9c285f91eaf214fe3314d7048d2071019e3 100644 (file)
@@ -3495,8 +3495,8 @@ void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
                num_labels = 1;
        }
 
-       return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, num_labels,
-                                       addpath_encode, addpath_tx_id, attr);
+       bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, num_labels,
+                                addpath_encode, addpath_tx_id, attr);
 }
 
 void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt)
index fc3ac287235aaa0be8991341c222430f781d9a40..e5e80cd5c4853eaa431959d20fa13096a137bb8b 100644 (file)
@@ -5802,6 +5802,21 @@ void bgp_evpn_init(struct bgp *bgp)
        bgp->vrf_export_rtl->del = evpn_xxport_delete_ecomm;
        bgp->l2vnis = list_new();
        bgp->l2vnis->cmp = vni_list_cmp;
+       /* By default Duplicate Address Dection is enabled.
+        * Max-moves (N) 5, detection time (M) 180
+        * default action is warning-only
+        * freeze action permanently freezes address,
+        * and freeze time (auto-recovery) is disabled.
+        */
+       if (bgp->evpn_info) {
+               bgp->evpn_info->dup_addr_detect = true;
+               bgp->evpn_info->dad_time = EVPN_DAD_DEFAULT_TIME;
+               bgp->evpn_info->dad_max_moves = EVPN_DAD_DEFAULT_MAX_MOVES;
+               bgp->evpn_info->dad_freeze = false;
+               bgp->evpn_info->dad_freeze_time = 0;
+               /* Initialize zebra vxlan */
+               bgp_zebra_dup_addr_detection(bgp);
+       }
 
        /* Default BUM handling is to do head-end replication. */
        bgp->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;
index f0017f3533fac2d7f57edc1b752040e1978a48f4..b2f16fc28435c895aa37e9bdcec222d53b76d561 100644 (file)
@@ -161,6 +161,24 @@ struct vrf_irt_node {
 #define RT_TYPE_EXPORT 2
 #define RT_TYPE_BOTH   3
 
+#define EVPN_DAD_DEFAULT_TIME 180 /* secs */
+#define EVPN_DAD_DEFAULT_MAX_MOVES 5 /* default from RFC 7432 */
+#define EVPN_DAD_DEFAULT_AUTO_RECOVERY_TIME 1800 /* secs */
+
+struct bgp_evpn_info {
+       /* enable disable dup detect */
+       bool dup_addr_detect;
+
+       /* Detection time(M) */
+       int dad_time;
+       /* Detection max moves(N) */
+       uint32_t dad_max_moves;
+       /* Permanent freeze */
+       bool dad_freeze;
+       /* Recovery time */
+       uint32_t dad_freeze_time;
+};
+
 static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
 {
        return (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD));
index aa5eabeadef74cf688cdd1cef87fd7e0a21bd70b..e915574ed0a0f264ce3a99a7214c5442c9e35419 100644 (file)
@@ -1696,10 +1696,10 @@ static void evpn_unconfigure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
 
        /* Delete all import RTs */
        if (ecomdel == NULL) {
-               for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom))
+               for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
                        ecommunity_free(&ecom);
-
-               list_delete_all_node(vpn->import_rtl);
+                       list_delete_node(vpn->import_rtl, node);
+               }
        }
 
        /* Delete a specific import RT */
@@ -1764,10 +1764,10 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
        /* Delete all export RTs */
        if (ecomdel == NULL) {
                /* Reset to default and process all routes. */
-               for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
+               for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) {
                        ecommunity_free(&ecom);
-
-               list_delete_all_node(vpn->export_rtl);
+                       list_delete_node(vpn->export_rtl, node);
+               }
        }
 
        /* Delete a specific export RT */
@@ -2999,6 +2999,130 @@ DEFUN (no_bgp_evpn_default_originate,
        return CMD_SUCCESS;
 }
 
+DEFPY (dup_addr_detection,
+       dup_addr_detection_cmd,
+       "dup-addr-detection [max-moves (2-1000)$max_moves_val time (2-1800)$time_val]",
+       "Duplicate address detection\n"
+       "Max allowed moves before address detected as duplicate\n"
+       "Num of max allowed moves (2-1000) default 5\n"
+       "Duplicate address detection time\n"
+       "Time in seconds (2-1800) default 180\n")
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       bgp_vrf->evpn_info->dup_addr_detect = true;
+
+       if (time_val)
+               bgp_vrf->evpn_info->dad_time = time_val;
+       if (max_moves_val)
+               bgp_vrf->evpn_info->dad_max_moves = max_moves_val;
+
+       bgp_zebra_dup_addr_detection(bgp_vrf);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (dup_addr_detection_auto_recovery,
+       dup_addr_detection_auto_recovery_cmd,
+       "dup-addr-detection freeze <permanent |(30-3600)$freeze_time_val>",
+       "Duplicate address detection\n"
+       "Duplicate address detection freeze\n"
+       "Duplicate address detection permanent freeze\n"
+       "Duplicate address detection freeze time (30-3600)\n")
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+       uint32_t freeze_time = freeze_time_val;
+
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       bgp_vrf->evpn_info->dup_addr_detect = true;
+       bgp_vrf->evpn_info->dad_freeze = true;
+       bgp_vrf->evpn_info->dad_freeze_time = freeze_time;
+
+       bgp_zebra_dup_addr_detection(bgp_vrf);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (no_dup_addr_detection,
+       no_dup_addr_detection_cmd,
+       "no dup-addr-detection [max-moves (2-1000)$max_moves_val time (2-1800)$time_val | freeze <permanent$permanent_val | (30-3600)$freeze_time_val>]",
+       NO_STR
+       "Duplicate address detection\n"
+       "Max allowed moves before address detected as duplicate\n"
+       "Num of max allowed moves (2-1000) default 5\n"
+       "Duplicate address detection time\n"
+       "Time in seconds (2-1800) default 180\n"
+       "Duplicate address detection freeze\n"
+       "Duplicate address detection permanent freeze\n"
+       "Duplicate address detection freeze time (30-3600)\n")
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+       uint32_t max_moves = (uint32_t)max_moves_val;
+       uint32_t freeze_time = (uint32_t)freeze_time_val;
+
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       if (argc == 2) {
+               if (!bgp_vrf->evpn_info->dup_addr_detect)
+                       return CMD_SUCCESS;
+               /* Reset all parameters to default. */
+               bgp_vrf->evpn_info->dup_addr_detect = false;
+               bgp_vrf->evpn_info->dad_time = EVPN_DAD_DEFAULT_TIME;
+               bgp_vrf->evpn_info->dad_max_moves = EVPN_DAD_DEFAULT_MAX_MOVES;
+               bgp_vrf->evpn_info->dad_freeze = false;
+               bgp_vrf->evpn_info->dad_freeze_time = 0;
+       } else {
+               if (max_moves) {
+                       if (bgp_vrf->evpn_info->dad_max_moves != max_moves) {
+                               vty_out(vty,
+                               "%% Value does not match with config\n");
+                               return CMD_SUCCESS;
+                       }
+                       bgp_vrf->evpn_info->dad_max_moves =
+                               EVPN_DAD_DEFAULT_MAX_MOVES;
+               }
+
+               if (time_val) {
+                       if (bgp_vrf->evpn_info->dad_time != time_val) {
+                               vty_out(vty,
+                               "%% Value does not match with config\n");
+                               return CMD_SUCCESS;
+                       }
+                       bgp_vrf->evpn_info->dad_time = EVPN_DAD_DEFAULT_TIME;
+               }
+
+               if (freeze_time) {
+                       if (bgp_vrf->evpn_info->dad_freeze_time
+                           != freeze_time) {
+                               vty_out(vty,
+                               "%% Value does not match with config\n");
+                               return CMD_SUCCESS;
+                       }
+                       bgp_vrf->evpn_info->dad_freeze_time = 0;
+                       bgp_vrf->evpn_info->dad_freeze = false;
+               }
+
+               if (permanent_val) {
+                       if (bgp_vrf->evpn_info->dad_freeze_time) {
+                               vty_out(vty,
+                               "%% Value does not match with config\n");
+                               return CMD_SUCCESS;
+                       }
+                       bgp_vrf->evpn_info->dad_freeze = false;
+               }
+       }
+
+       bgp_zebra_dup_addr_detection(bgp_vrf);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet,
              bgp_evpn_advertise_vni_subnet_cmd,
              "advertise-subnet",
@@ -4919,6 +5043,26 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
        if (bgp->advertise_gw_macip)
                vty_out(vty, "  advertise-default-gw\n");
 
+       if (!bgp->evpn_info->dup_addr_detect)
+               vty_out(vty, "  no dup-addr-detection\n");
+
+       if (bgp->evpn_info->dad_max_moves !=
+               EVPN_DAD_DEFAULT_MAX_MOVES ||
+               bgp->evpn_info->dad_time != EVPN_DAD_DEFAULT_TIME)
+               vty_out(vty, "  dup-addr-detection max-moves %u time %u\n",
+                       bgp->evpn_info->dad_max_moves,
+                       bgp->evpn_info->dad_time);
+
+       if (bgp->evpn_info->dad_freeze) {
+               if (bgp->evpn_info->dad_freeze_time)
+                       vty_out(vty,
+                               "  dup-addr-detection freeze %u\n",
+                               bgp->evpn_info->dad_freeze_time);
+               else
+                       vty_out(vty,
+                               "  dup-addr-detection freeze permanent\n");
+       }
+
        if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_DISABLED)
                vty_out(vty, "  flooding disable\n");
 
@@ -5013,6 +5157,9 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
+       install_element(BGP_EVPN_NODE, &dup_addr_detection_cmd);
+       install_element(BGP_EVPN_NODE, &dup_addr_detection_auto_recovery_cmd);
+       install_element(BGP_EVPN_NODE, &no_dup_addr_detection_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd);
 
        /* test commands */
index 1f0cfd6e257e92ce815f9bf14ceccce8430fdfa6..b70c8bbd631cb88b2cf55b12838185ade095d858 100644 (file)
@@ -935,9 +935,29 @@ static void bgp_update_delay_process_status_change(struct peer *peer)
    read/write and timer thread. */
 void bgp_fsm_change_status(struct peer *peer, int status)
 {
+       struct bgp *bgp;
+       uint32_t peer_count;
 
        bgp_dump_state(peer, peer->status, status);
 
+       bgp = peer->bgp;
+       peer_count = bgp->established_peers;
+
+       if (status == Established)
+               bgp->established_peers++;
+       else if ((peer->status == Established) && (status != Established))
+               bgp->established_peers--;
+
+       if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
+               zlog_debug("%s : vrf %u, established_peers %u", __func__,
+                               bgp->vrf_id, bgp->established_peers);
+       /* Set to router ID to the value provided by RIB if there are no peers
+        * in the established state and peer count did not change
+        */
+       if ((peer_count != bgp->established_peers) &&
+           (bgp->established_peers == 0))
+               bgp_router_id_zebra_bump(bgp->vrf_id, NULL);
+
        /* Transition into Clearing or Deleted must /always/ clear all routes..
         * (and must do so before actually changing into Deleted..
         */
index 0dce96f43240c5703dc52548a118ed9f318498f0..c5d12a570678febe0aa5bdce7fd7ebef85585db6 100644 (file)
@@ -866,6 +866,8 @@ void bgp_nht_register_enhe_capability_interfaces(struct peer *peer)
        if (p.family != AF_INET6)
                return;
        rn = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
+       if (!rn)
+               return;
 
        bnc = bgp_nexthop_get_node_info(rn);
        if (!bnc)
index edd8317c3161058c5bba53db19f1d19fa87c8fa0..4e050df3e5a3ef46e149bb8ef978dc2d7dcab69d 100644 (file)
@@ -1508,9 +1508,10 @@ static void bgp_pbr_policyroute_remove_from_zebra_recursive(
        struct list *orig_list;
        struct bgp_pbr_val_mask **target_val;
 
-       if (type_entry == 0)
-               return bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path,
-                                                                 bpf);
+       if (type_entry == 0) {
+               bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
+               return;
+       }
        next_type_entry = bgp_pbr_next_type_entry(type_entry);
        if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
                orig_list = bpof->tcpflags;
@@ -1530,8 +1531,9 @@ static void bgp_pbr_policyroute_remove_from_zebra_recursive(
                bgp_pbr_icmp_action(bgp, path, bpf, bpof, false, NULL, NULL);
                return;
        } else {
-               return bgp_pbr_policyroute_remove_from_zebra_recursive(
+               bgp_pbr_policyroute_remove_from_zebra_recursive(
                        bgp, path, bpf, bpof, next_type_entry);
+               return;
        }
        for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
                *target_val = valmask;
@@ -1544,9 +1546,10 @@ static void bgp_pbr_policyroute_remove_from_zebra(
        struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
        struct bgp_pbr_or_filter *bpof)
 {
-       if (!bpof)
-               return bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path,
-                                                                 bpf);
+       if (!bpof) {
+               bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
+               return;
+       }
        if (bpof->tcpflags)
                bgp_pbr_policyroute_remove_from_zebra_recursive(
                        bgp, path, bpf, bpof, FLOWSPEC_TCP_FLAGS);
@@ -1903,9 +1906,10 @@ static void bgp_pbr_policyroute_add_to_zebra_recursive(
        struct list *orig_list;
        struct bgp_pbr_val_mask **target_val;
 
-       if (type_entry == 0)
-               return bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh,
-                                                            rate);
+       if (type_entry == 0) {
+               bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
+               return;
+       }
        next_type_entry = bgp_pbr_next_type_entry(type_entry);
        if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
                orig_list = bpof->tcpflags;
@@ -1925,8 +1929,9 @@ static void bgp_pbr_policyroute_add_to_zebra_recursive(
                bgp_pbr_icmp_action(bgp, path, bpf, bpof, true, nh, rate);
                return;
        } else {
-               return bgp_pbr_policyroute_add_to_zebra_recursive(
+               bgp_pbr_policyroute_add_to_zebra_recursive(
                        bgp, path, bpf, bpof, nh, rate, next_type_entry);
+               return;
        }
        for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
                *target_val = valmask;
@@ -1941,9 +1946,10 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
                                             struct bgp_pbr_or_filter *bpof,
                                             struct nexthop *nh, float *rate)
 {
-       if (!bpof)
-               return bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh,
-                                                            rate);
+       if (!bpof) {
+               bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
+               return;
+       }
        if (bpof->tcpflags)
                bgp_pbr_policyroute_add_to_zebra_recursive(
                        bgp, path, bpf, bpof, nh, rate, FLOWSPEC_TCP_FLAGS);
@@ -2112,9 +2118,10 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
        bpf.protocol = proto;
        bpf.src_port = srcp;
        bpf.dst_port = dstp;
-       if (!add)
-               return bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf,
-                                                            &bpof);
+       if (!add) {
+               bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof);
+               return;
+       }
        /* no action for add = true */
        for (i = 0; i < api->action_num; i++) {
                switch (api->actions[i].action) {
index 85b6414e481cd0aacb2363b1a3e768f9b5175d3e..69a0b78378039fe23bb9644f8f5b72b7ed70cbba 100644 (file)
@@ -602,7 +602,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                        bgp->update_delay_over = 0;
 
                if (!found)
-                       vty_out(vty, "%%BGP: No %s peer configured",
+                       vty_out(vty, "%%BGP: No %s peer configured\n",
                                afi_safi_print(afi, safi));
 
                return CMD_SUCCESS;
@@ -972,6 +972,7 @@ DEFUN_NOSH (router_bgp,
        int idx_asn = 2;
        int idx_view_vrf = 3;
        int idx_vrf = 4;
+       int is_new_bgp = 0;
        int ret;
        as_t as;
        struct bgp *bgp;
@@ -1011,6 +1012,9 @@ DEFUN_NOSH (router_bgp,
                                inst_type = BGP_INSTANCE_TYPE_VIEW;
                }
 
+               if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+                       is_new_bgp = (bgp_lookup(as, name) == NULL);
+
                ret = bgp_get(&bgp, &as, name, inst_type);
                switch (ret) {
                case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
@@ -1034,7 +1038,7 @@ DEFUN_NOSH (router_bgp,
                 * any pending VRF-VPN leaking that was configured via
                 * earlier "router bgp X vrf FOO" blocks.
                 */
-               if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+               if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                        vpn_leak_postchange_all();
 
                /* Pending: handle when user tries to change a view to vrf n vv.
index 62f977eee14b370b0c8d873217383412252bc535..1e0abaa29e94d8f99775beca0275d2d24bafd991 100644 (file)
@@ -58,6 +58,7 @@
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_labelpool.h"
 #include "bgpd/bgp_pbr.h"
+#include "bgpd/bgp_evpn_private.h"
 
 /* All information about zebra. */
 struct zclient *zclient = NULL;
@@ -1217,9 +1218,10 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
        if (bgp_debug_zebra(p))
                prefix2str(p, buf_prefix, sizeof(buf_prefix));
 
-       if (safi == SAFI_FLOWSPEC)
-               return bgp_pbr_update_entry(bgp, &rn->p,
-                                           info, afi, safi, true);
+       if (safi == SAFI_FLOWSPEC) {
+               bgp_pbr_update_entry(bgp, &rn->p, info, afi, safi, true);
+               return;
+       }
 
        /*
         * vrf leaking support (will have only one nexthop)
@@ -1505,8 +1507,8 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *info,
 
        if (safi == SAFI_FLOWSPEC) {
                peer = info->peer;
-               return bgp_pbr_update_entry(peer->bgp, p,
-                                           info, AFI_IP, safi, false);
+               bgp_pbr_update_entry(peer->bgp, p, info, AFI_IP, safi, false);
+               return;
        }
 
        memset(&api, 0, sizeof(api));
@@ -1998,6 +2000,42 @@ int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise)
        return zclient_send_message(zclient);
 }
 
+int bgp_zebra_dup_addr_detection(struct bgp *bgp)
+{
+       struct stream *s;
+
+       /* Check socket. */
+       if (!zclient || zclient->sock < 0)
+               return 0;
+
+       /* Don't try to register if Zebra doesn't know of this instance. */
+       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+               return 0;
+
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("dup addr detect %s max_moves %u time %u freeze %s freeze_time %u",
+                          bgp->evpn_info->dup_addr_detect ?
+                          "enable" : "disable",
+                          bgp->evpn_info->dad_max_moves,
+                          bgp->evpn_info->dad_time,
+                          bgp->evpn_info->dad_freeze ?
+                          "enable" : "disable",
+                          bgp->evpn_info->dad_freeze_time);
+
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s, ZEBRA_DUPLICATE_ADDR_DETECTION,
+                             bgp->vrf_id);
+       stream_putl(s, bgp->evpn_info->dup_addr_detect);
+       stream_putl(s, bgp->evpn_info->dad_time);
+       stream_putl(s, bgp->evpn_info->dad_max_moves);
+       stream_putl(s, bgp->evpn_info->dad_freeze);
+       stream_putl(s, bgp->evpn_info->dad_freeze_time);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
 static int rule_notify_owner(int command, struct zclient *zclient,
                             zebra_size_t length, vrf_id_t vrf_id)
 {
@@ -2501,19 +2539,19 @@ static void bgp_zebra_process_local_ip_prefix(int cmd, struct zclient *zclient,
        if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) {
 
                if (p.family == AF_INET)
-                       return bgp_evpn_advertise_type5_route(
-                               bgp_vrf, &p, NULL, AFI_IP, SAFI_UNICAST);
+                       bgp_evpn_advertise_type5_route(bgp_vrf, &p, NULL,
+                                                      AFI_IP, SAFI_UNICAST);
                else
-                       return bgp_evpn_advertise_type5_route(
-                               bgp_vrf, &p, NULL, AFI_IP6, SAFI_UNICAST);
+                       bgp_evpn_advertise_type5_route(bgp_vrf, &p, NULL,
+                                                      AFI_IP6, SAFI_UNICAST);
 
        } else {
                if (p.family == AF_INET)
-                       return bgp_evpn_withdraw_type5_route(
-                               bgp_vrf, &p, AFI_IP, SAFI_UNICAST);
+                       bgp_evpn_withdraw_type5_route(bgp_vrf, &p, AFI_IP,
+                                                     SAFI_UNICAST);
                else
-                       return bgp_evpn_withdraw_type5_route(
-                               bgp_vrf, &p, AFI_IP6, SAFI_UNICAST);
+                       bgp_evpn_withdraw_type5_route(bgp_vrf, &p, AFI_IP6,
+                                                     SAFI_UNICAST);
        }
 }
 
index 2ea1fc777c26b0e7d41d51ba09a5c98f895a7598..e7b7d683aff10cfc731c02a5bf15ff76ed87bc88 100644 (file)
@@ -73,6 +73,7 @@ extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise,
                                      vni_t vni);
 extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
 extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
+extern int bgp_zebra_dup_addr_detection(struct bgp *bgp);
 extern int bgp_zebra_vxlan_flood_control(struct bgp *bgp,
                                         enum vxlan_flood_control flood_ctrl);
 
index a078c4f58743b8c7065f241556709a109941cc7e..94cb285a0368f5d24e8f1c402cadc501c44083da 100644 (file)
 #include "bgpd/bgp_labelpool.h"
 #include "bgpd/bgp_pbr.h"
 #include "bgpd/bgp_addpath.h"
+#include "bgpd/bgp_evpn_private.h"
 
 DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
+DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
 DEFINE_QOBJ_TYPE(bgp_master)
 DEFINE_QOBJ_TYPE(bgp)
 DEFINE_QOBJ_TYPE(peer)
@@ -274,6 +276,10 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
+       struct in_addr *addr = NULL;
+
+       if (router_id != NULL)
+               addr = (struct in_addr *)&(router_id->u.prefix4);
 
        if (vrf_id == VRF_DEFAULT) {
                /* Router-id change for default VRF has to also update all
@@ -282,17 +288,43 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id)
                        if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
                                continue;
 
-                       bgp->router_id_zebra = router_id->u.prefix4;
-                       if (!bgp->router_id_static.s_addr)
-                               bgp_router_id_set(bgp, &router_id->u.prefix4);
+                       if (addr)
+                               bgp->router_id_zebra = *addr;
+                       else
+                               addr = &bgp->router_id_zebra;
+
+                       if (!bgp->router_id_static.s_addr) {
+                               /* Router ID is updated if there are no active
+                                * peer sessions
+                                */
+                               if (bgp->established_peers == 0) {
+                                       if (BGP_DEBUG(zebra, ZEBRA))
+                                               zlog_debug("RID change : vrf %u, RTR ID %s",
+                                       bgp->vrf_id, inet_ntoa(*addr));
+                                       bgp_router_id_set(bgp, addr);
+                               }
+                       }
                }
        } else {
                bgp = bgp_lookup_by_vrf_id(vrf_id);
                if (bgp) {
-                       bgp->router_id_zebra = router_id->u.prefix4;
+                       if (addr)
+                               bgp->router_id_zebra = *addr;
+                       else
+                               addr = &bgp->router_id_zebra;
+
+                       if (!bgp->router_id_static.s_addr) {
+                               /* Router ID is updated if there are no active
+                                * peer sessions
+                                */
+                               if (bgp->established_peers == 0) {
+                                       if (BGP_DEBUG(zebra, ZEBRA))
+                                               zlog_debug("RID change : vrf %u, RTR ID %s",
+                                       bgp->vrf_id, inet_ntoa(*addr));
+                                       bgp_router_id_set(bgp, addr);
+                               }
+                       }
 
-                       if (!bgp->router_id_static.s_addr)
-                               bgp_router_id_set(bgp, &router_id->u.prefix4);
                }
        }
 }
@@ -2952,6 +2984,9 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        /* assign a unique rd id for auto derivation of vrf's RD */
        bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id);
 
+       bgp->evpn_info = XCALLOC(MTYPE_BGP_EVPN_INFO,
+                                sizeof(struct bgp_evpn_info));
+
        bgp_evpn_init(bgp);
        bgp_pbr_init(bgp);
        return bgp;
@@ -3343,6 +3378,7 @@ void bgp_free(struct bgp *bgp)
 
        bgp_evpn_cleanup(bgp);
        bgp_pbr_cleanup(bgp);
+       XFREE(MTYPE_BGP_EVPN_INFO, bgp->evpn_info);
 
        for (afi = AFI_IP; afi < AFI_MAX; afi++) {
                vpn_policy_direction_t dir;
index 70193104b41b30dc85aaa273d1a1ac2acf1e17a1..62096d651affee5e1d2930c2aed63d30798bb12e 100644 (file)
@@ -482,6 +482,8 @@ struct bgp {
        /* EVPN enable - advertise local VNIs and their MACs etc. */
        int advertise_all_vni;
 
+       struct bgp_evpn_info *evpn_info;
+
        /* EVPN - use RFC 8365 to auto-derive RT */
        int advertise_autort_rfc8365;
 
@@ -542,6 +544,9 @@ struct bgp {
        /* local esi hash table */
        struct hash *esihash;
 
+       /* Count of peers in established state */
+       uint32_t established_peers;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp)
@@ -1004,7 +1009,7 @@ struct peer {
        struct thread *t_process_packet;
 
        /* Thread flags. */
-       _Atomic uint16_t thread_flags;
+       _Atomic uint32_t thread_flags;
 #define PEER_THREAD_WRITES_ON         (1 << 0)
 #define PEER_THREAD_READS_ON          (1 << 1)
 #define PEER_THREAD_KEEPALIVES_ON     (1 << 2)
@@ -1886,5 +1891,4 @@ extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
 
 /* For benefit of rfapi */
 extern struct peer *peer_new(struct bgp *bgp);
-
 #endif /* _QUAGGA_BGPD_H */
index 13f6fdab72af98c4ba49170666724adae14594f7..c925509fafac96f46bf451f13aa3f9ae425b06dd 100755 (executable)
@@ -334,6 +334,12 @@ _LT_CONFIG_LIBTOOL([
 ])
 if test "$enable_static_bin" = "yes"; then
   AC_LDFLAGS="-static"
+  if test "$enable_static" != "yes"; then
+    AC_MSG_ERROR([The --enable-static-bin option must be combined with --enable-static.])
+  fi
+fi
+if test "$enable_shared" != "yes"; then
+  AC_MSG_ERROR([FRR cannot be built with --disable-shared.  If you want statically linked daemons, use --enable-shared --enable-static --enable-static-bin])
 fi
 AC_SUBST([AC_LDFLAGS])
 AM_CONDITIONAL([STATIC_BIN], [test "x$enable_static_bin" = "xyes"])
index 42192db637da57abe93d02541fef01029f1b5aac..9838e1098caf5ebc05a87baf702376d4c0c0888d 100644 (file)
@@ -12,3 +12,4 @@ FRRouting Developer's Guide
    bgpd
    ospf
    zebra
+   vtysh
diff --git a/doc/developer/vtysh.rst b/doc/developer/vtysh.rst
new file mode 100644 (file)
index 0000000..4a52eb0
--- /dev/null
@@ -0,0 +1,201 @@
+.. _vtysh:
+
+*****
+VTYSH
+*****
+
+.. seealso:: :ref:`command-line-interface`
+
+.. _vtysh-architecture:
+
+Architecture
+============
+
+VTYSH is a shell for FRR daemons. It amalgamates all the CLI commands defined
+in each of the daemons and presents them to the user in a single shell, which
+saves the user from having to telnet to each of the daemons and use their
+individual shells.  The amalgamation is achieved by
+:ref:`extracting <vtysh-command-extraction>` commands from daemons and
+injecting them into VTYSH at build time.
+
+At runtime, VTYSH maintains an instance of a CLI mode tree just like each
+daemon. However, the mode tree in VTYSH contains (almost) all commands from
+every daemon in the same tree, whereas individual daemons have trees that only
+contain commands relevant to themselves. VTYSH also uses the library CLI
+facilities to maintain the user's current position in the tree (the current
+node). Note that this position must be synchronized with all daemons; if a
+daemon receives a command that causes it to change its current node, VTYSH must
+also change its node. Since the extraction script does not understand the
+handler code of commands, but only their definitions, this and other behaviors
+must be manually programmed into VTYSH for every case where the internal state
+of VTYSH must change in response to a command. Details on how this is done are
+discussed in the :ref:`vtysh-special-defuns` section.
+
+VTYSH also handles writing and applying the integrated configuration file,
+:file:`/etc/frr/frr.conf`. Since it has knowledge of the entire command space
+of FRR, it can intelligently distribute configuration commands only to the
+daemons that understand them. Similarly, when writing the configuration file it
+takes care of combining multiple instances of configuration blocks and
+simplifying the output. This is discussed in :ref:`vtysh-configuration`.
+
+.. _vtysh-command-extraction:
+
+Command Extraction
+------------------
+
+When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR
+codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
+them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
+contains the name of the command plus ``_vtysh``, as well as a flag that
+indicates which daemons the command was found in. When the command is executed
+in VTYSH, this flag is inspected to determine which daemons to send the command
+to. This way, commands are only sent to the daemons that know about them,
+avoiding spurious errors from daemons that don't have the command defined.
+
+The extraction script contains lots of hardcoded knowledge about what sources
+to look at and what flags to use for certain commands.
+
+.. _vtysh-special-defuns:
+
+Special DEFUNs
+--------------
+
+In addition to the vanilla ``DEFUN`` macro for defining CLI commands, there are
+several VTYSH-specific ``DEFUN`` variants that each serve different purposes.
+
+``DEFSH``
+   Used almost exclusively by generated VTYSH code. This macro defines a
+   ``cmd_element`` with no handler function; the command, when executed, is
+   simply forwarded to the daemons indicated in the daemon flag.
+
+``DEFUN_NOSH``
+   Used by daemons. Has the same expansion as a ``DEFUN``, but ``extract.pl``
+   will skip these definitions when extracting commands. This is typically used
+   when VTYSH must take some special action upon receiving the command, and the
+   programmer therefore needs to write VTYSH's copy of the command manually
+   instead of using the generated version.
+
+``DEFUNSH``
+   The same as ``DEFUN``, but with an argument that allows specifying the
+   ``->daemon`` field of the generated ``cmd_element``. This is used by VTYSH
+   to determine which daemons to send the command to.
+
+``DEFUNSH_ATTR``
+   A version of ``DEFUNSH`` that allows setting the ``->attr`` field of the
+   generated ``cmd_element``. Not used in practice.
+
+.. _vtysh-configuration:
+
+Configuration Management
+------------------------
+
+When integrated configuration is used, VTYSH manages writing, reading and
+applying the FRR configuration file. VTYSH can be made to read and apply an
+integrated configuration to all running daemons by launching it with ``-f
+<file>``. It sends the appropriate configuration lines to the relevant daemons
+in the same way that commands entered by the user on VTYSH's shell prompt are
+processed.
+
+Configuration writing is more complicated. VTYSH makes a best-effort attempt to
+combine and simplify the configuration as much as possible. A working example
+is best to explain this behavior.
+
+Example
+^^^^^^^
+
+Suppose we have just *staticd* and *zebra* running on the system, and use VTYSH
+to apply the following configuration snippet:
+
+.. code-block:: frr
+
+   !
+   vrf blue
+    ip protocol static route-map ExampleRoutemap
+    ip route 192.168.0.0/24 192.168.0.1
+    exit-vrf
+   !
+
+Note that *staticd* defines static route commands and *zebra* defines ``ip
+protocol`` commands. Therefore if we ask only *zebra* for its configuration, we
+get the following::
+
+   (config)# do sh running-config zebra
+   Building configuration...
+
+   ...
+   !
+   vrf blue
+    ip protocol static route-map ExampleRoutemap
+    exit-vrf
+   !
+   ...
+
+Note that the static route doesn't show up there. Similarly, if we ask
+*staticd* for its configuration, we get::
+
+   (config)# do sh running-config staticd
+
+   ...
+   !
+   vrf blue
+    ip route 192.168.0.0/24 192.168.0.1
+    exit-vrf
+   !
+   ...
+
+But when we display the configuration with VTYSH, we see::
+
+   ubuntu-bionic(config)# do sh running-config
+
+   ...
+   !
+   vrf blue
+    ip protocol static route-map ExampleRoutemap
+    ip route 192.168.0.0/24 192.168.0.1
+    exit-vrf
+   !
+   ...
+
+This is because VTYSH asks each daemon for its currently running configuration,
+and combines equivalent blocks together. In the above example, it combined the
+``vrf blue`` blocks from both *zebra* and *staticd* together into one. This is
+done in :file:`vtysh_config.c`.
+
+Protocol
+========
+
+VTYSH communicates with FRR daemons by way of domain socket. Each daemon
+creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The
+protocol is very simple. In the VTYSH to daemon direction, messages are simply
+NULL-terminated strings, whose content are CLI commands. Here is a typical
+message from VTYSH to a daemon:
+
+::
+
+   Request
+
+   00000000: 646f 2077 7269 7465 2074 6572 6d69 6e61  do write termina
+   00000010: 6c0a 00                                  l..
+
+
+The response format has some more data in it. First is a NULL-terminated string
+containing the plaintext response, which is just the output of the command that
+was sent in the request. This is displayed to the user. The plaintext response
+is followed by 3 null marker bytes, followed by a 1-byte status code that
+indicates whether the command was successful or not.
+
+::
+
+   Response
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                       Plaintext Response                      |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                 Marker (0x00)                 |  Status Code  |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+The first ``0x00`` byte in the marker also serves to terminate the plaintext
+response.
index ee7592fd6a46890d521cd5cff42989b2788865cc..543dfdd3b994b301fcbc93998d2044edff7f2501 100644 (file)
@@ -91,17 +91,63 @@ documentation and packaging systems will be updated to reflect the next
 possible release name to allow for easy distinguishing.
 
 After one month the development branch will be renamed to
-``stable/MAJOR.MINOR``.  This process is not held up unless a crash or security
-issue has been found and needs to be addressed. Issues being fixed will not
-cause a delay.
+``stable/MAJOR.MINOR``.  The branch is a stable branch. This process is not
+held up unless a crash or security issue has been found and needs to
+be addressed. Issues being fixed will not cause a delay.
 
 Bugfix releases are made as needed at 1 month intervals until the next
-``MAJOR.MINOR`` relese branch is pulled. Depending on the severity of the bugs,
+``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
 bugfix releases may occur sooner.
 
 Bugfixes are applied to the two most recent releases. Security fixes are
-backported to all releases less than or equal to one year old. Security fixes
-may also be backported to older releases depending on severity.
+backported to all releases less than or equal to at least one year old. Security
+fixes may also be backported to older releases depending on severity.
+
+Long term support branches ( LTS )
+-----------------------------------------
+
+This kind of branch is not yet officially supported, and need experimentation
+before being effective.
+
+Previous definition of releases prevents long term support of previous releases.
+For instance, bug and security fixes are not applied if the stable branch is too
+old.
+
+Because the FRR users have a need to backport bug and security fixes after the
+stable branch becomes too old, there is a need to provide support on a long term
+basis on that stable branch. If that support is applied on that stable branch,
+then that branch is a long term support branch.
+
+Having a LTS branch requires extra-work and requires one person to be in charge
+of that maintenance branch for a certain amount of time. The amount of time will
+be by default set to 4 months, and can be increased. 4 months stands for the time
+between two releases, this time can be applied to the decision to continue with a
+LTS release or not. In all cases, that time period will be well-defined and
+published. Also, a self nomination from a person that proposes to handle the LTS
+branch is required. The work can be shared by multiple people. In all cases, there
+must be at least one person that is in charge of the maintenance branch. The person
+on people responsible for a maintenance branch must be a FRR maintainer. Note that
+they may choose to abandon support for the maintenance branch at any time. If
+noone takes over the responsibility of the LTS branch, then the support will be
+discontinued.
+
+The LTS branch duties are the following ones:
+
+- organise meetings on a (bi-)weekly or monthly basis, the handling of issues
+  and pull requested relative to that branch. When time permits, this may be done
+  during the regularly scheduled FRR meeting.
+
+- ensure the stability of the branch, by using and eventually adapting the
+  checking the CI tools of FRR ( indeed, maintaining may lead to create
+  maintenance branches for topotests or for CI).
+
+It will not be possible to backport feature requests to LTS branches. Actually, it
+is a false good idea to use LTS for that need. Introducing feature requests may
+break the paradigm where all more recent releases should also include the feature
+request. This would require the LTS maintainer to ensure that all more recent
+releases have support for this feature request. Moreover, introducing features
+requests may result in breaking the stability of the branch. LTS branches are first
+done to bring long term support for stability.
 
 Changelog
 ---------
index 76c8087f2d8331b14bfffee89a2552cd88adadaa..2b3116b1ff19fd107d4f69c31b7cf1db1903f7a4 100644 (file)
@@ -585,17 +585,19 @@ void fabricd_lsp_flood(struct isis_lsp *lsp)
        while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
                n->present = true;
 
-               struct isis_lsp *lsp = lsp_for_vertex(f->spftree, n->vertex);
-               if (!lsp || !lsp->tlvs || !lsp->tlvs->spine_leaf)
-                       continue;
-
-               if (!lsp->tlvs->spine_leaf->has_tier
-                   || lsp->tlvs->spine_leaf->tier != 0)
+               struct isis_lsp *node_lsp = lsp_for_vertex(f->spftree,
+                                                          n->vertex);
+               if (!node_lsp
+                   || !node_lsp->tlvs
+                   || !node_lsp->tlvs->spine_leaf
+                   || !node_lsp->tlvs->spine_leaf->has_tier
+                   || node_lsp->tlvs->spine_leaf->tier != 0) {
                        continue;
+               }
 
                if (isis->debugs & DEBUG_FABRICD_FLOODING) {
                        zlog_debug("Moving %s to DNR because it's T0",
-                                  rawlspid_print(lsp->hdr.lsp_id));
+                                  rawlspid_print(node_lsp->hdr.lsp_id));
                }
 
                move_to_dnr(lsp, n);
index 38239d5919ccc9fec89aaa1981d810da63e994a9..9a57d0d0ac2f522cba654e01bb40e9ac10873257 100644 (file)
@@ -253,7 +253,8 @@ int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
        if (seqno > lsp->hdr.seqno
            || (seqno == lsp->hdr.seqno
                && ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
-                   || lsp->hdr.checksum != checksum))) {
+                   || (lsp->hdr.checksum != checksum
+                       && lsp->hdr.rem_lifetime)))) {
                if (isis->debugs & DEBUG_SNP_PACKETS) {
                        zlog_debug(
                                "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
index 7493b90d33638a63e8c812c86db1a2c3aa6031f2..f7d4c7170f5c8a759a011e50e4d86d58c3ac5852 100644 (file)
@@ -398,7 +398,7 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
                    && !tlvs->mt_router_info_empty) {
                        /* Other end does not have MT enabled */
                        if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST
-                           && v4_usable)
+                           && (v4_usable || v6_usable))
                                adj_mt_set(adj, intersect_count++,
                                           ISIS_MT_IPV4_UNICAST);
                } else {
index 99041b0e61c7e2289c5a5b190325b2dcaecdce48..7df152f1fabdb366a7e0d60b81523a54d4b0a66f 100644 (file)
@@ -747,7 +747,7 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
                                       stream_get_endp(circuit->rcv_stream));
        }
 
-       struct isis_lsp_hdr hdr = {};
+       struct isis_lsp_hdr hdr = {0};
 
        hdr.pdu_len = stream_getw(circuit->rcv_stream);
        hdr.rem_lifetime = stream_getw(circuit->rcv_stream);
@@ -1011,19 +1011,26 @@ dontcheckadj:
                 * is
                 * "greater" than that held by S, ... */
 
-               if (hdr.seqno > lsp->hdr.seqno) {
+               if (comp == LSP_NEWER) {
                        /* 7.3.16.1  */
                        lsp_inc_seqno(lsp, hdr.seqno);
-                       if (isis->debugs & DEBUG_UPDATE_PACKETS)
+                       if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                                zlog_debug(
                                        "ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08" PRIx32,
                                        circuit->area->area_tag,
                                        rawlspid_print(hdr.lsp_id),
                                        lsp->hdr.seqno);
+                       }
+                       lsp_flood(lsp, NULL);
+               } else if (comp == LSP_EQUAL) {
+                       isis_tx_queue_del(circuit->tx_queue, lsp);
+                       if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+                               ISIS_SET_FLAG(lsp->SSNflags, circuit);
+               } else {
+                       isis_tx_queue_add(circuit->tx_queue, lsp,
+                                         TX_LSP_NORMAL);
+                       ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                }
-               /* If the received LSP is older or equal,
-                * resend the LSP which will act as ACK */
-               lsp_flood(lsp, NULL);
        } else {
                /* 7.3.15.1 e) - This lsp originated on another system */
 
@@ -1119,8 +1126,8 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
        stream_get(rem_sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
        stream_forward_getp(circuit->rcv_stream, 1); /* Circuit ID - unused */
 
-       uint8_t start_lsp_id[ISIS_SYS_ID_LEN + 2] = {};
-       uint8_t stop_lsp_id[ISIS_SYS_ID_LEN + 2] = {};
+       uint8_t start_lsp_id[ISIS_SYS_ID_LEN + 2] = {0};
+       uint8_t stop_lsp_id[ISIS_SYS_ID_LEN + 2] = {0};
 
        if (is_csnp) {
                stream_get(start_lsp_id, circuit->rcv_stream,
index f9b4a2b146e42760ff64e10c93c848efece820b3..1439a4229a1aec7591dba49bad4d96e30132825e 100644 (file)
@@ -492,7 +492,7 @@ static void _isis_route_verify_table(struct isis_area *area,
 
 void isis_route_verify_table(struct isis_area *area, struct route_table *table)
 {
-       return _isis_route_verify_table(area, table, NULL);
+       _isis_route_verify_table(area, table, NULL);
 }
 
 /* Function to validate route tables for L1L2 areas. In this case we can't use
index fce3a0a113912802fc9b7172a75d26922a6d510c..5e73baa841564dad309d80136ad3c5133b65c97c 100644 (file)
@@ -171,8 +171,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
                                  struct sbuf *log, void *dest, int indent)
 {
        struct isis_subtlvs *subtlvs = dest;
-       struct isis_prefix_sid sid = {
-       };
+       struct isis_prefix_sid sid = {0};
 
        sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
 
@@ -2052,7 +2051,7 @@ static int unpack_tlv_purge_originator(enum isis_tlv_context context,
                                       void *dest, int indent)
 {
        struct isis_tlvs *tlvs = dest;
-       struct isis_purge_originator poi = {};
+       struct isis_purge_originator poi = {0};
 
        sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
        if (tlv_len < 7) {
@@ -3131,7 +3130,7 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
                [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
                [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
        },
-       [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
+       [ISIS_CONTEXT_SUBTLV_NE_REACH] = {0},
        [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
                [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
        },
@@ -3397,7 +3396,7 @@ static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
                        ipv6_supported = true;
        }
 
-       struct nlpids reduced = {};
+       struct nlpids reduced = {0};
 
        if (ipv4_supported && ipv6_supported) {
                reduced.count = 2;
@@ -3408,7 +3407,7 @@ static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
                reduced.nlpids[0] = NLPID_IP;
        } else if (ipv6_supported) {
                reduced.count = 1;
-               reduced.nlpids[1] = NLPID_IPV6;
+               reduced.nlpids[0] = NLPID_IPV6;
        } else {
                reduced.count = 0;
        }
index a703969fdb1cf4ef89bc0839fe44647f6203d424..dc2ff03b674828151e05d5ace71ac6c4887fbdde 100644 (file)
@@ -58,7 +58,7 @@ static inline struct agg_node *agg_lock_node(struct agg_node *node)
 
 static inline void agg_unlock_node(struct agg_node *node)
 {
-       return route_unlock_node(agg_node_to_rnode(node));
+       route_unlock_node(agg_node_to_rnode(node));
 }
 
 static inline void agg_set_table_info(struct agg_table *atable, void *data)
index 58b7982665571a927b3cb0951ed622b2573f95a9..ca0c8be79da34b777c49e1f938271640743c8c4c 100644 (file)
@@ -92,7 +92,7 @@ static PyMemberDef members_graph_node[] = {
        member(deprecated, T_BOOL),  member(hidden, T_BOOL),
        member(text, T_STRING),      member(desc, T_STRING),
        member(min, T_LONGLONG),     member(max, T_LONGLONG),
-       member(varname, T_STRING),   {},
+       member(varname, T_STRING),   {0},
 };
 #undef member
 
@@ -137,7 +137,7 @@ static PyObject *graph_node_join(PyObject *self, PyObject *args)
 static PyMethodDef methods_graph_node[] = {
        {"next", graph_node_next, METH_NOARGS, "outbound graph edge list"},
        {"join", graph_node_join, METH_NOARGS, "outbound join node"},
-       {}};
+       {0}};
 
 static void graph_node_wrap_free(void *arg)
 {
@@ -228,7 +228,7 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
        }
 static PyMemberDef members_graph[] = {
        member(definition, T_STRING),
-       {},
+       {0},
 };
 #undef member
 
@@ -242,7 +242,7 @@ static PyObject *graph_first(PyObject *self, PyObject *args)
 
 static PyMethodDef methods_graph[] = {
        {"first", graph_first, METH_NOARGS, "first graph node"},
-       {}};
+       {0}};
 
 static PyObject *graph_parse(PyTypeObject *type, PyObject *args,
                             PyObject *kwds);
index 0f1d666aeb9ae3d1c98ee911671c705acec25cb5..96979163323480b3a78a64a04bfb1fe40c357b4b 100644 (file)
@@ -299,16 +299,15 @@ DEFUN (ipv6_distribute_list,
                ifname = argv[argc - 1]->arg;
 
        /* Get interface name corresponding distribute list. */
-       distfn(ifname, type, argv[1 + prefix]->arg);
+       distfn(ifname, type, argv[2 + prefix]->arg);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (no_distribute_list,
        no_distribute_list_cmd,
-       "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
+       "no distribute-list [prefix] WORD <in|out> [WORD]",
        NO_STR
-       "IPv6\n"
        "Filter networks in routing updates\n"
        "Specify a prefix\n"
        "Access-list name\n"
@@ -316,20 +315,53 @@ DEFUN (no_distribute_list,
        "Filter outgoing routing updates\n"
        "Interface name\n")
 {
-       int ipv6 = strmatch(argv[1]->text, "ipv6");
-       int prefix = (argv[2 + ipv6]->type == WORD_TKN) ? 1 : 0;
+       int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
 
-       int idx_alname = 2 + ipv6 + prefix;
+       int idx_alname = 2 + prefix;
        int idx_disttype = idx_alname + 1;
+       enum distribute_type type =
+               argv[idx_disttype]->arg[0] == 'i' ?
+               DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
 
-       /* Check of distribute list type. */
-       enum distribute_type distin =
-               (ipv6) ? DISTRIBUTE_V6_IN : DISTRIBUTE_V4_IN;
-       enum distribute_type distout =
-               (ipv6) ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V4_OUT;
+       /* Set appropriate function call */
+       int (*distfn)(const char *, enum distribute_type,
+                     const char *) =
+               prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
+
+       /* if interface is present, get name */
+       const char *ifname = NULL;
+       if (argv[argc - 1]->type == VARIABLE_TKN)
+               ifname = argv[argc - 1]->arg;
+       /* Get interface name corresponding distribute list. */
+       int ret = distfn(ifname, type, argv[2 + prefix]->arg);
+
+       if (!ret) {
+               vty_out(vty, "distribute list doesn't exist\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_distribute_list,
+       no_ipv6_distribute_list_cmd,
+       "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+       NO_STR
+       "IPv6\n"
+       "Filter networks in routing updates\n"
+       "Specify a prefix\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+       int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0;
+
+       int idx_alname = 3 + prefix;
+       int idx_disttype = idx_alname + 1;
 
        enum distribute_type type =
-               argv[idx_disttype]->arg[0] == 'i' ? distin : distout;
+               argv[idx_disttype]->arg[0] == 'i' ?
+               DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT;
 
        /* Set appropriate function call */
        int (*distfn)(const char *, enum distribute_type, const char *) =
@@ -337,10 +369,11 @@ DEFUN (no_distribute_list,
 
        /* if interface is present, get name */
        const char *ifname = NULL;
+
        if (argv[argc - 1]->type == VARIABLE_TKN)
                ifname = argv[argc - 1]->arg;
        /* Get interface name corresponding distribute list. */
-       int ret = distfn(ifname, type, argv[2 + prefix]->arg);
+       int ret = distfn(ifname, type, argv[3 + prefix]->arg);
 
        if (!ret) {
                vty_out(vty, "distribute list doesn't exist\n");
@@ -535,6 +568,7 @@ void distribute_list_init(int node)
        /* install v6 */
        if (node == RIPNG_NODE) {
                install_element(RIPNG_NODE, &ipv6_distribute_list_cmd);
+               install_element(RIPNG_NODE, &no_ipv6_distribute_list_cmd);
        }
 
        /* TODO: install v4 syntax command for v6 only protocols. */
index 5cc303daf07e20688dfaedc1db76567fb63b4fdb..12a1d7fbe04062a1c8ae24863c568a8ea00b2878 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -1034,6 +1034,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_DEL),
        DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD),
        DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL),
+       DESC_ENTRY(ZEBRA_DUPLICATE_ADDR_DETECTION),
        DESC_ENTRY(ZEBRA_PW_ADD),
        DESC_ENTRY(ZEBRA_PW_DELETE),
        DESC_ENTRY(ZEBRA_PW_SET),
index 8e50c1874ade466415ac85b4c34b083783738b99..00b9400462e2f6c8b6e49c29ae6e1099fd80854c 100644 (file)
@@ -80,4 +80,15 @@ static inline int64_t monotime_until(const struct timeval *ref,
        return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
 }
 
+static inline char *time_to_string(time_t ts)
+{
+       struct timeval tv;
+       time_t tbuf;
+
+       monotime(&tv);
+       tbuf = time(NULL) - (tv.tv_sec - ts);
+
+       return ctime(&tbuf);
+}
+
 #endif /* _FRR_MONOTIME_H */
index 859f751678f7ac45c82366a19ffc0a67773e0dc0..1383ef6de070424fcb4ab77d708f41248765b503 100644 (file)
@@ -475,25 +475,25 @@ int _rb_check(const struct rb_type *, void *, unsigned long);
        __attribute__((__unused__)) static inline void _name##_RB_SET_LEFT(    \
                struct _type *elm, struct _type *left)                         \
        {                                                                      \
-               return _rb_set_left(_name##_RB_TYPE, elm, left);               \
+               _rb_set_left(_name##_RB_TYPE, elm, left);                      \
        }                                                                      \
                                                                                \
        __attribute__((__unused__)) static inline void _name##_RB_SET_RIGHT(   \
                struct _type *elm, struct _type *right)                        \
        {                                                                      \
-               return _rb_set_right(_name##_RB_TYPE, elm, right);             \
+               _rb_set_right(_name##_RB_TYPE, elm, right);                    \
        }                                                                      \
                                                                                \
        __attribute__((__unused__)) static inline void _name##_RB_SET_PARENT(  \
                struct _type *elm, struct _type *parent)                       \
        {                                                                      \
-               return _rb_set_parent(_name##_RB_TYPE, elm, parent);           \
+               _rb_set_parent(_name##_RB_TYPE, elm, parent);                  \
        }                                                                      \
                                                                                \
        __attribute__((__unused__)) static inline void _name##_RB_POISON(      \
                struct _type *elm, unsigned long poison)                       \
        {                                                                      \
-               return _rb_poison(_name##_RB_TYPE, elm, poison);               \
+               _rb_poison(_name##_RB_TYPE, elm, poison);                      \
        }                                                                      \
                                                                                \
        __attribute__((__unused__)) static inline int _name##_RB_CHECK(        \
index c144c2c2e1d87205ca6050b7e44734418fa9eb17..43b39100cb3a701675bf540109f9d08db75fee8f 100644 (file)
@@ -92,6 +92,12 @@ lib_libfrr_la_SOURCES = \
        lib/lua.c \
        # end
 
+nodist_lib_libfrr_la_SOURCES = \
+       yang/frr-interface.yang.c \
+       yang/frr-route-types.yang.c \
+       yang/frr-module-translator.yang.c \
+       # end
+
 vtysh_scan += \
        $(top_srcdir)/lib/distribute.c \
        $(top_srcdir)/lib/filter.c \
index 70090cf7841447b4146cc0747aca95d9dba09ba6..4de9a65562ab13895c760325d06e278e52bc7421 100644 (file)
@@ -125,7 +125,7 @@ struct cpu_thread_history {
                _Atomic unsigned long total, max;
        } real;
        struct time_stats cpu;
-       _Atomic uint8_t types;
+       _Atomic uint32_t types;
        const char *funcname;
 };
 
index 90ca5f502a1c0c41f0bcf3aede28a8c028880557..811c23c2186a4dc818b6eee27cdee5808d0f5202 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2458,8 +2458,6 @@ static void vty_read_file(struct nb_config *config, FILE *confp)
         */
        if (config == NULL && vty->candidate_config
            && frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
-               int ret;
-
                ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI,
                                          true, "Read configuration file",
                                          NULL);
index bb5d38e2e664197295306efed1c7c0161f7fc4ef..a7a50a46b0fcb225aff52c24217e96cda2083ad1 100644 (file)
@@ -32,6 +32,45 @@ DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
 /* libyang container. */
 struct ly_ctx *ly_native_ctx;
 
+static struct yang_module_embed *embeds, **embedupd = &embeds;
+
+void yang_module_embed(struct yang_module_embed *embed)
+{
+       embed->next = NULL;
+       *embedupd = embed;
+       embedupd = &embed->next;
+}
+
+static const char *yang_module_imp_clb(const char *mod_name,
+                                      const char *mod_rev,
+                                      const char *submod_name,
+                                      const char *submod_rev,
+                                      void *user_data,
+                                      LYS_INFORMAT *format,
+                                      void (**free_module_data)
+                                               (void *, void*))
+{
+       struct yang_module_embed *e;
+
+       if (submod_name || submod_rev)
+               return NULL;
+
+       for (e = embeds; e; e = e->next) {
+               if (strcmp(e->mod_name, mod_name))
+                       continue;
+               if (mod_rev && strcmp(e->mod_rev, mod_rev))
+                       continue;
+
+               *format = e->format;
+               return e->data;
+       }
+
+       flog_warn(EC_LIB_YANG_MODULE_LOAD,
+                 "YANG model \"%s@%s\" not embedded, trying external file",
+                 mod_name, mod_rev ? mod_rev : "*");
+       return NULL;
+}
+
 /* Generate the yang_modules tree. */
 static inline int yang_module_compare(const struct yang_module *a,
                                      const struct yang_module *b)
@@ -575,6 +614,7 @@ void yang_init(void)
                flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
                exit(1);
        }
+       ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
        ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
        ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
 
index cd5597ff8c1f5cb0e90733b2ac48798a200a3b7c..b0348e320b3b6ab5b7073e2357c8f53acfe4b150 100644 (file)
@@ -44,6 +44,13 @@ DECLARE_MTYPE(YANG_DATA)
 /* Maximum string length of an YANG value. */
 #define YANG_VALUE_MAXLEN 1024
 
+struct yang_module_embed {
+       struct yang_module_embed *next;
+       const char *mod_name, *mod_rev;
+       const char *data;
+       LYS_INFORMAT format;
+};
+
 struct yang_module {
        RB_ENTRY(yang_module) entry;
        const char *name;
@@ -132,6 +139,16 @@ extern struct yang_module *yang_module_load(const char *module_name);
  */
 extern struct yang_module *yang_module_find(const char *module_name);
 
+/*
+ * Register a YANG module embedded in the binary file.  Should be called
+ * from a constructor function.
+ *
+ * embed
+ *    YANG module embedding structure to register.  (static global provided
+ *    by caller.)
+ */
+extern void yang_module_embed(struct yang_module_embed *embed);
+
 /*
  * Iterate over all libyang schema nodes from the given YANG module.
  *
index 07fe512a3cc5ea7fe091e9659bf54b5a1065e31c..adb48b252a6973e692edbe7f77e40b4668cbc92d 100644 (file)
@@ -135,6 +135,7 @@ typedef enum {
        ZEBRA_IP_PREFIX_ROUTE_DEL,
        ZEBRA_REMOTE_MACIP_ADD,
        ZEBRA_REMOTE_MACIP_DEL,
+       ZEBRA_DUPLICATE_ADDR_DETECTION,
        ZEBRA_PW_ADD,
        ZEBRA_PW_DELETE,
        ZEBRA_PW_SET,
index 3bb3b79a6a728481e75f041f88c5ad58cb786a3c..27a94f2310e1ccf5b90430083e2a3297a6c673ae 100644 (file)
@@ -655,7 +655,7 @@ static int ospf_write(struct thread *thread)
        int pkt_count = 0;
 
 #ifdef GNU_LINUX
-       unsigned char cmsgbuf[64] = {};
+       unsigned char cmsgbuf[64] = {0};
        struct cmsghdr *cm = (struct cmsghdr *)cmsgbuf;
        struct in_pktinfo *pi;
 #endif
index 6103bd7db5e2cf71a6e85f90cc018c480b040aac..db958e833f68cf4bcd5c14ebbf73d9f5edfc6631 100644 (file)
@@ -232,9 +232,9 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
                                const struct nexthop *nhop)
 {
        char debugstr[256];
-       struct pbr_nexthop_group_cache pnhgc_find = {};
+       struct pbr_nexthop_group_cache pnhgc_find = {0};
        struct pbr_nexthop_group_cache *pnhgc;
-       struct pbr_nexthop_cache pnhc_find = {};
+       struct pbr_nexthop_cache pnhc_find = {0};
        struct pbr_nexthop_cache *pnhc;
 
        if (!pbr_nht_get_next_tableid(true)) {
@@ -270,9 +270,9 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
                                const struct nexthop *nhop)
 {
        char debugstr[256];
-       struct pbr_nexthop_group_cache pnhgc_find = {};
+       struct pbr_nexthop_group_cache pnhgc_find = {0};
        struct pbr_nexthop_group_cache *pnhgc;
-       struct pbr_nexthop_cache pnhc_find = {};
+       struct pbr_nexthop_cache pnhc_find = {0};
        struct pbr_nexthop_cache *pnhc;
        enum nexthop_types_t nh_afi = nhop->type;
 
index 129d569c87a1d15b811b4099bd6e5933be31dac5..8f6a9ece5316ab7943202337cb167127faea32a2 100644 (file)
@@ -1012,10 +1012,21 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
 
        /* PIM enabled on interface? */
        pim_ifp = ifp->info;
-       if (!pim_ifp)
+       if (!pim_ifp) {
+               if (PIM_DEBUG_EVENTS)
+                       zlog_debug("%s:%s Expected pim interface setup for %s",
+                                  __PRETTY_FUNCTION__,
+                                  pim_str_sg_dump(sg), ifp->name);
                return 0;
-       if (!PIM_IF_TEST_PIM(pim_ifp->options))
+       }
+
+       if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
+               if (PIM_DEBUG_EVENTS)
+                       zlog_debug("%s:%s PIM is not configured on this interface %s",
+                                  __PRETTY_FUNCTION__,
+                                  pim_str_sg_dump(sg), ifp->name);
                return 0;
+       }
 
        pim = pim_ifp->pim;
 
@@ -1033,6 +1044,10 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
 
        ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
        if (!ch) {
+               if (PIM_DEBUG_EVENTS)
+                       zlog_debug("%s:%s Unable to add ifchannel",
+                                  __PRETTY_FUNCTION__,
+                                  pim_str_sg_dump(sg));
                return 0;
        }
 
index 3dfc36a0c2e8ae18d060741031786a267522f0b5..10ea17cf1f80dfe0487c1a09bc99033c1e875570 100644 (file)
@@ -1048,6 +1048,10 @@ void igmp_source_forward_start(struct pim_instance *pim,
                                   __PRETTY_FUNCTION__,
                                   pim_str_sg_dump(&sg),
                                   group->group_igmp_sock->interface->name);
+
+               pim_channel_del_oif(source->source_channel_oil,
+                                   group->group_igmp_sock->interface,
+                                   PIM_OIF_FLAG_PROTO_IGMP);
                return;
        }
        /*
@@ -1059,6 +1063,10 @@ void igmp_source_forward_start(struct pim_instance *pim,
                if (PIM_DEBUG_MROUTE)
                        zlog_warn("%s: Failure to add local membership for %s",
                                  __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
+
+               pim_channel_del_oif(source->source_channel_oil,
+                                   group->group_igmp_sock->interface,
+                                   PIM_OIF_FLAG_PROTO_IGMP);
                return;
        }
 
index a140ce3d5454404312181bb02dee46f542b311b7..b6eb490b676994ca8397a7176ace89ebb1ec09e5 100644 (file)
@@ -67,19 +67,19 @@ class PrefixBase(RenderHandler):
     deref = '&'
 class Prefix4Handler(PrefixBase):
     argtype = 'const struct prefix_ipv4 *'
-    decl = Template('struct prefix_ipv4 $varname = { };')
+    decl = Template('struct prefix_ipv4 $varname = {0};')
     code = Template('_fail = !str2prefix_ipv4(argv[_i]->arg, &$varname);')
 class Prefix6Handler(PrefixBase):
     argtype = 'const struct prefix_ipv6 *'
-    decl = Template('struct prefix_ipv6 $varname = { };')
+    decl = Template('struct prefix_ipv6 $varname = {0};')
     code = Template('_fail = !str2prefix_ipv6(argv[_i]->arg, &$varname);')
 class PrefixEthHandler(PrefixBase):
     argtype = 'struct prefix_eth *'
-    decl = Template('struct prefix_eth $varname = { };')
+    decl = Template('struct prefix_eth $varname = {0};')
     code = Template('_fail = !str2prefix_eth(argv[_i]->arg, &$varname);')
 class PrefixGenHandler(PrefixBase):
     argtype = 'const struct prefix *'
-    decl = Template('struct prefix $varname = { };')
+    decl = Template('struct prefix $varname = {0};')
     code = Template('_fail = !str2prefix(argv[_i]->arg, &$varname);')
 
 # same for IP addresses.  result is union sockunion.
@@ -96,7 +96,7 @@ class IP4Handler(IPBase):
     code = Template('_fail = !inet_aton(argv[_i]->arg, &$varname);')
 class IP6Handler(IPBase):
     argtype = 'struct in6_addr'
-    decl = Template('struct in6_addr $varname = {};')
+    decl = Template('struct in6_addr $varname = {0};')
     code = Template('_fail = !inet_pton(AF_INET6, argv[_i]->arg, &$varname);')
 class IPGenHandler(IPBase):
     argtype = 'const union sockunion *'
index 480fa1e47f559114dd6504619222bd85475f4e3d..ed74047ccef933f11f7b61fc8ab09caec9d2badf 100644 (file)
@@ -51,6 +51,9 @@ ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@
 ripd_ripd_SOURCES = \
        ripd/rip_main.c \
        # end
+nodist_ripd_ripd_SOURCES = \
+       yang/frr-ripd.yang.c \
+       # end
 
 ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
 ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
index cd0330ed82065a17fa5a45af0a425103fb49b95e..a5f0f74b003e667d21ae201ee068b29e3f8412c2 100644 (file)
@@ -497,6 +497,66 @@ void static_cleanup_vrf_ids(struct static_vrf *disable_svrf)
        }
 }
 
+/*
+ * This function enables static routes when an interface it relies
+ * on in a different vrf is coming up.
+ *
+ * stable -> The stable we are looking at.
+ * ifp -> interface coming up
+ * afi -> the afi in question
+ * safi -> the safi in question
+ */
+static void static_fixup_intf_nh(struct route_table *stable,
+                                struct interface *ifp,
+                                afi_t afi, safi_t safi)
+{
+       struct route_node *rn;
+       struct static_route *si;
+
+       for (rn = route_top(stable); rn; rn = route_next(rn)) {
+               for (si = rn->info; si; si = si->next) {
+                       if (si->nh_vrf_id != ifp->vrf_id)
+                               continue;
+
+                       if (si->ifindex != ifp->ifindex)
+                               continue;
+
+                       static_install_route(rn, si, safi);
+               }
+       }
+}
+
+/*
+ * This function enables static routes that rely on an interface in
+ * a different vrf when that interface comes up.
+ */
+void static_install_intf_nh(struct interface *ifp)
+{
+       struct route_table *stable;
+       struct vrf *vrf;
+       afi_t afi;
+       safi_t safi;
+
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
+               struct static_vrf *svrf = vrf->info;
+
+               /* Not needed if same vrf since happens naturally */
+               if (vrf->vrf_id == ifp->vrf_id)
+                       continue;
+
+               /* Install any static routes configured for this interface. */
+               for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+                       for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+                               stable = svrf->stable[afi][safi];
+                               if (!stable)
+                                       continue;
+
+                               static_fixup_intf_nh(stable, ifp, afi, safi);
+                       }
+               }
+       }
+}
+
 /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
 void static_ifindex_update(struct interface *ifp, bool up)
 {
index 916ddcd7eb024145e49f5e81296e1e8ac660397d..6036bfe396970df625915b759ee4e68f5e909233 100644 (file)
@@ -113,5 +113,7 @@ extern int static_delete_route(afi_t afi, safi_t safi, uint8_t type,
 
 extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf);
 
+extern void static_install_intf_nh(struct interface *ifp);
+
 extern void static_ifindex_update(struct interface *ifp, bool up);
 #endif
index fd4201e5625218e01deb2224c40c959ef7ebca60..1e23f597b0384eb4f30ff2e98b4c1617e011c59f 100644 (file)
@@ -122,11 +122,17 @@ static int interface_state_up(int command, struct zclient *zclient,
 
        ifp = zebra_interface_if_lookup(zclient->ibuf);
 
-       if (ifp && if_is_vrf(ifp)) {
-               struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id);
+       if (ifp) {
+               if (if_is_vrf(ifp)) {
+                       struct static_vrf *svrf =
+                                       static_vrf_lookup_by_id(vrf_id);
 
-               static_fixup_vrf_ids(svrf);
-               static_config_install_delayed_routes(svrf);
+                       static_fixup_vrf_ids(svrf);
+                       static_config_install_delayed_routes(svrf);
+               }
+
+               /* Install any static reliant on this interface coming up */
+               static_install_intf_nh(ifp);
        }
 
        return 0;
index 22354c1e882b72478a5e31ce6db1dac89fa22794..547a4b21370e4ca01157eb49855545b1045d5b4f 100755 (executable)
@@ -6367,6 +6367,13 @@ sub process {
                        ERROR("NONSTANDARD_INTEGRAL_TYPES",
                              "Please, no nonstandard integer types in new code.\n" . $herecurr)
                }
+
+# check for usage of non-32 bit atomics
+               if ($line =~ /_Atomic [u]?int(?!32)[0-9]+_t/) {
+                       WARN("NON_32BIT_ATOMIC",
+                            "Please, only use 32 bit atomics.\n" . $herecurr);
+               }
+
        }
 
        # If we have no input at all, then there is nothing to report on
index cd78551cb40bca861ef30b16553db02a78aafb10..f57a4d9ddf0aee1e36b3ae5b2d6c7e49b835f0a7 100644 (file)
@@ -577,7 +577,7 @@ static int vtysh_execute_func(const char *line, int pager)
                                    && (cmd->daemon == vtysh_client[i].flag)) {
                                        for (vc = &vtysh_client[i]; vc;
                                             vc = vc->next)
-                                               if (vc->fd < 0)
+                                               if (vc->fd == VTYSH_WAS_ACTIVE)
                                                        vtysh_reconnect(vc);
                                }
                                if (vtysh_client[i].fd < 0
diff --git a/yang/.gitignore b/yang/.gitignore
new file mode 100644 (file)
index 0000000..f43a1c3
--- /dev/null
@@ -0,0 +1,2 @@
+*.yang.c
+*.yin
diff --git a/yang/embedmodel.py b/yang/embedmodel.py
new file mode 100644 (file)
index 0000000..52671f9
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/python3
+#
+# YANG module to C wrapper
+# written 2018 by David Lamparter, placed in Public Domain.
+
+import sys, string, re
+
+inname = sys.argv[1]
+outname = sys.argv[2]
+
+# these are regexes to avoid a compile-time/host dependency on yang-tools
+# or python-yang.  Cross-compiling FRR is already somewhat involved, no need
+# to make it even harder.
+
+re_name = re.compile(r'\bmodule\s+([^\s]+)\s+\{')
+re_rev = re.compile(r'\brevision\s+([\d-]+)\s+\{')
+
+
+template = '''/* autogenerated by embedmodel.py.  DO NOT EDIT */
+
+#include <zebra.h>
+#include "yang.h"
+
+static const char model[] =
+\t"%s";
+
+static struct yang_module_embed embed = {
+\t.mod_name = "%s",
+\t.mod_rev = "%s",
+\t.data = model,
+\t.format = %s,
+};
+
+static void embed_register(void) __attribute__((_CONSTRUCTOR(2000)));
+static void embed_register(void)
+{
+\tyang_module_embed(&embed);
+}
+'''
+
+passchars = set(string.printable) - set('\\\'"%\r\n\t\x0b\x0c')
+def escapech(char):
+    if char in passchars:
+        return char
+    if char == '\n':
+        return '\\n'
+    if char == '\t':
+        return '\\t'
+    if char in '"\\\'':
+        return '\\' + char
+    return '\\x%02x' % (ord(char))
+def escape(line):
+    return ''.join([escapech(i) for i in line])
+
+with open(inname, 'r') as fd:
+    data = fd.read()
+
+# XML support isn't actively used currently, but it's here in case the need
+# arises.  It does avoid the regex'ing.
+if '<?xml' in data:
+    from xml.etree import ElementTree
+    xml = ElementTree.fromstring(data)
+    name = xml.get('name')
+    rev = xml.find('{urn:ietf:params:xml:ns:yang:yin:1}revision').get('date')
+    fmt = 'LYS_YIN'
+else:
+    name = re_name.search(data).group(1)
+    rev = re_rev.search(data).group(1)
+    fmt = 'LYS_YANG'
+
+if name is None or rev is None:
+    raise ValueError('cannot determine YANG module name and revision')
+
+lines = [escape(row) for row in data.split('\n')]
+text = '\\n"\n\t"'.join(lines)
+
+with open(outname, 'w') as fd:
+    fd.write(template % (text, escape(name), escape(rev), fmt))
index d68a341a9faeac0a508cdf1922b56a0c0e04d98d..ee6fbc181d1cd4e1596703a0745c7b5741117174 100644 (file)
@@ -1,3 +1,24 @@
+SUFFIXES += .yang .yang.c .yin .yin.c
+EXTRA_DIST += yang/embedmodel.py
+
+.yang.yang.c:
+       $(AM_V_GEN)$(PYTHON) $(top_srcdir)/yang/embedmodel.py $^ $@
+.yin.yin.c:
+       $(AM_V_GEN)$(PYTHON) $(top_srcdir)/yang/embedmodel.py $^ $@
+
+# use .yang.c files like this:
+#
+# ripd_ripd_SOURCES = \
+#      ...
+# nodist_ripd_ripd_SOURCES = \
+#      yang/frr-ripd.yang.c \
+#      # end
+#
+# Note that putting the .yang.c file into a static library.a will NOT work
+# because the entire file is "optimized out" since it does not contain any
+# global symbols :(.  Just put it in the daemon.  Dynamic libraries.so work
+# without problems, as seen in libfrr.
+
 dist_yangmodels_DATA += yang/frr-module-translator.yang
 dist_yangmodels_DATA += yang/frr-interface.yang
 dist_yangmodels_DATA += yang/frr-route-types.yang
index b93911bee78f9f49577293fa807d3dca1bc97dd8..9b84a6e58a5c5f0ca0f8b7edcabe41f9109dc921 100644 (file)
@@ -2443,6 +2443,7 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_REMOTE_VTEP_DEL] = zebra_vxlan_remote_vtep_del,
        [ZEBRA_REMOTE_MACIP_ADD] = zebra_vxlan_remote_macip_add,
        [ZEBRA_REMOTE_MACIP_DEL] = zebra_vxlan_remote_macip_del,
+       [ZEBRA_DUPLICATE_ADDR_DETECTION] = zebra_vxlan_dup_addr_detection,
        [ZEBRA_INTERFACE_SET_MASTER] = zread_interface_set_master,
        [ZEBRA_PW_ADD] = zread_pseudowire,
        [ZEBRA_PW_DELETE] = zread_pseudowire,
index 61eba92c98f59b235e0e1f7ddc9918d91425712f..3e61418b6486638c834c21869147b49b39a24dab 100644 (file)
@@ -135,8 +135,8 @@ struct zebra_dplane_provider {
 
        dplane_provider_fini_fp dp_fini;
 
-       _Atomic uint64_t dp_in_counter;
-       _Atomic uint64_t dp_error_counter;
+       _Atomic uint32_t dp_in_counter;
+       _Atomic uint32_t dp_error_counter;
 
        /* Embedded list linkage */
        TAILQ_ENTRY(zebra_dplane_provider) dp_q_providers;
@@ -171,10 +171,10 @@ static struct zebra_dplane_globals {
        /* Limit number of pending, unprocessed updates */
        _Atomic uint32_t dg_max_queued_updates;
 
-       _Atomic uint64_t dg_routes_in;
+       _Atomic uint32_t dg_routes_in;
        _Atomic uint32_t dg_routes_queued;
        _Atomic uint32_t dg_routes_queued_max;
-       _Atomic uint64_t dg_route_errors;
+       _Atomic uint32_t dg_route_errors;
 
        /* Event-delivery context 'master' for the dplane */
        struct thread_master *dg_master;
index 17163e2182889670aeb7da6e43d5d7e9f76ac8a8..32f665383245268855546e4fb35703fd6e1066d8 100644 (file)
@@ -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,
        }
index 43e37c6e5b568a1c42e7fc2f925167bb0693f0e2..cf2d6a7cf51ef0f5df5440041e1c56d165d9ebf3 100644 (file)
@@ -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);
index ef02ca63e5269170f878ee27336f823b95815b3e..c28025403b48fbb184269e200b58a2588af251fa 100644 (file)
@@ -125,6 +125,13 @@ struct zebra_vrf {
        /* l3-vni info */
        vni_t l3vni;
 
+       bool dup_addr_detect;
+
+       int dad_time;
+       uint32_t dad_max_moves;
+       bool dad_freeze;
+       uint32_t dad_freeze_time;
+
        /*
         * Flooding mechanism for BUM packets for VxLAN-EVPN.
         */
index 263cb3d22c7aeded7e541624909f28775896ab6c..536fdabcbc1dd894973be6ee14d63d5b28808254 100644 (file)
@@ -1970,7 +1970,7 @@ DEFUN (show_evpn_mac_vni_all,
        bool uj = use_json(argc, argv);
 
        zvrf = vrf_info_lookup(VRF_DEFAULT);
-       zebra_vxlan_print_macs_all_vni(vty, zvrf, uj);
+       zebra_vxlan_print_macs_all_vni(vty, zvrf, false, uj);
        return CMD_SUCCESS;
 }
 
@@ -2059,6 +2059,90 @@ DEFUN (show_evpn_mac_vni_vtep,
        return CMD_SUCCESS;
 }
 
+DEFPY (show_evpn_mac_vni_all_dad,
+       show_evpn_mac_vni_all_dad_cmd,
+       "show evpn mac vni all duplicate [json]",
+       SHOW_STR
+       "EVPN\n"
+       "MAC addresses\n"
+       "VxLAN Network Identifier\n"
+       "All VNIs\n"
+       "Duplicate address list\n"
+       JSON_STR)
+{
+       struct zebra_vrf *zvrf;
+       bool uj = use_json(argc, argv);
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       zebra_vxlan_print_macs_all_vni(vty, zvrf, true, uj);
+       return CMD_SUCCESS;
+}
+
+
+DEFPY (show_evpn_mac_vni_dad,
+       show_evpn_mac_vni_dad_cmd,
+       "show evpn mac vni " CMD_VNI_RANGE " duplicate" "[json]",
+       SHOW_STR
+       "EVPN\n"
+       "MAC addresses\n"
+       "VxLAN Network Identifier\n"
+       "VNI number\n"
+       "Duplicate address list\n"
+       JSON_STR)
+{
+       struct zebra_vrf *zvrf;
+       vni_t vni;
+       bool uj = use_json(argc, argv);
+
+       vni = strtoul(argv[4]->arg, NULL, 10);
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+
+       zebra_vxlan_print_macs_vni_dad(vty, zvrf, vni, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (show_evpn_neigh_vni_dad,
+       show_evpn_neigh_vni_dad_cmd,
+       "show evpn arp-cache vni " CMD_VNI_RANGE "duplicate" "[json]",
+       SHOW_STR
+       "EVPN\n"
+       "ARP and ND cache\n"
+       "VxLAN Network Identifier\n"
+       "VNI number\n"
+       "Duplicate address list\n"
+       JSON_STR)
+{
+       struct zebra_vrf *zvrf;
+       vni_t vni;
+       bool uj = use_json(argc, argv);
+
+       vni = strtoul(argv[4]->arg, NULL, 10);
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       zebra_vxlan_print_neigh_vni_dad(vty, zvrf, vni, uj);
+       return CMD_SUCCESS;
+}
+
+DEFPY (show_evpn_neigh_vni_all_dad,
+       show_evpn_neigh_vni_all_dad_cmd,
+       "show evpn arp-cache vni all duplicate [json]",
+       SHOW_STR
+       "EVPN\n"
+       "ARP and ND cache\n"
+       "VxLAN Network Identifier\n"
+       "All VNIs\n"
+       "Duplicate address list\n"
+       JSON_STR)
+{
+       struct zebra_vrf *zvrf;
+       bool uj = use_json(argc, argv);
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       zebra_vxlan_print_neigh_all_vni(vty, zvrf, true, uj);
+       return CMD_SUCCESS;
+}
+
+
 DEFUN (show_evpn_neigh_vni,
        show_evpn_neigh_vni_cmd,
        "show evpn arp-cache vni " CMD_VNI_RANGE "[json]",
@@ -2093,7 +2177,7 @@ DEFUN (show_evpn_neigh_vni_all,
        bool uj = use_json(argc, argv);
 
        zvrf = vrf_info_lookup(VRF_DEFAULT);
-       zebra_vxlan_print_neigh_all_vni(vty, zvrf, uj);
+       zebra_vxlan_print_neigh_all_vni(vty, zvrf, false, uj);
        return CMD_SUCCESS;
 }
 
@@ -2193,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 <all$vni_all |" CMD_VNI_RANGE"$vni_val [mac M:A:C$mac_val | ip <A.B.C.D|X:X::X:X>]>",
+       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)
 {
@@ -2755,10 +2888,15 @@ void zebra_vty_init(void)
        install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_mac_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_vtep_cmd);
+       install_element(VIEW_NODE, &show_evpn_mac_vni_dad_cmd);
+       install_element(VIEW_NODE, &show_evpn_mac_vni_all_dad_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_all_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
        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);
index d372d3e832b639173b20bbd4e183ff150bc382fe..86f6961118a04670f7da1c02fd87b365fc61b59a 100644 (file)
@@ -66,6 +66,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
                                    uint16_t cmd);
 static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
 static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
+static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt);
 static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
                                          void **args);
 static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
@@ -178,8 +179,26 @@ 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);
+static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t);
+static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t);
+static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
+                                                 zebra_neigh_t *nbr,
+                                                 struct in_addr vtep_ip,
+                                                 bool do_dad,
+                                                 bool *is_dup_detect,
+                                                 bool is_local);
+static void zebra_vxlan_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);
 
 /* Private functions */
 static int host_rb_entry_compare(const struct host_rb_entry *hle1,
@@ -255,6 +274,50 @@ static uint32_t num_valid_macs(zebra_vni_t *zvni)
        return num_macs;
 }
 
+static uint32_t num_dup_detected_macs(zebra_vni_t *zvni)
+{
+       unsigned int i;
+       uint32_t num_macs = 0;
+       struct hash *hash;
+       struct hash_backet *hb;
+       zebra_mac_t *mac;
+
+       hash = zvni->mac_table;
+       if (!hash)
+               return num_macs;
+       for (i = 0; i < hash->size; i++) {
+               for (hb = hash->index[i]; hb; hb = hb->next) {
+                       mac = (zebra_mac_t *)hb->data;
+                       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+                               num_macs++;
+               }
+       }
+
+       return num_macs;
+}
+
+static uint32_t num_dup_detected_neighs(zebra_vni_t *zvni)
+{
+       unsigned int i;
+       uint32_t num_neighs = 0;
+       struct hash *hash;
+       struct hash_backet *hb;
+       zebra_neigh_t *nbr;
+
+       hash = zvni->neigh_table;
+       if (!hash)
+               return num_neighs;
+       for (i = 0; i < hash->size; i++) {
+               for (hb = hash->index[i]; hb; hb = hb->next) {
+                       nbr = (zebra_neigh_t *)hb->data;
+                       if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
+                               num_neighs++;
+               }
+       }
+
+       return num_neighs;
+}
+
 static int advertise_gw_macip_enabled(zebra_vni_t *zvni)
 {
        struct zebra_vrf *zvrf;
@@ -269,6 +332,331 @@ 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 inherit duplicate flag
+ * from MAC.
+ */
+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;
+}
+
+static void zebra_vxlan_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;
+       struct timeval elapsed = {0, 0};
+       char buf[ETHER_ADDR_STRLEN];
+       char buf1[INET6_ADDRSTRLEN];
+       bool reset_params = false;
+
+       if (!(zvrf->dup_addr_detect && do_dad))
+               return;
+
+       /* MAC is detected as duplicate,
+        * Local MAC event -> hold on advertising to BGP.
+        * Remote MAC event -> hold on installing it.
+        */
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                                  "%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u",
+                                  __PRETTY_FUNCTION__,
+                                  prefix_mac2str(&mac->macaddr, buf,
+                                                 sizeof(buf)),
+                                  mac->flags, 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)
+                       *is_dup_detect = false;
+
+               return;
+       }
+
+       /* Check if detection time (M-secs) expired.
+        * Reset learn count and detection start time.
+        */
+       monotime_since(&mac->detect_start_time, &elapsed);
+       reset_params = (elapsed.tv_sec > zvrf->dad_time);
+       if (is_local && !reset_params) {
+               /* RFC-7432: A PE/VTEP that detects a MAC mobility
+                * event via LOCAL learning starts an M-second timer.
+                *
+                * NOTE: This is the START of the probe with count is
+                * 0 during LOCAL learn event.
+                * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
+                */
+               reset_params = !mac->dad_count;
+       }
+
+       if (reset_params) {
+               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(&mac->macaddr, buf,
+                                                 sizeof(buf)),
+                                  mac->flags, mac->dad_count);
+
+               mac->dad_count = 0;
+               /* Start dup. addr detection (DAD) start time,
+                * ONLY during LOCAL learn.
+                */
+               if (is_local)
+                       monotime(&mac->detect_start_time);
+
+       } else if (!is_local) {
+               /* For REMOTE MAC, increment detection count
+                * ONLY while in probe window, once window passed,
+                * next local learn event should trigger DAD.
+                */
+               mac->dad_count++;
+       }
+
+       /* For LOCAL MAC learn event, once count is reset above via either
+        * initial/start detection time or passed the probe time, the count
+        * needs to be incremented.
+        */
+       if (is_local)
+               mac->dad_count++;
+
+       zlog_debug("%s: MAC DAD %s dad_count %u ",
+                  __PRETTY_FUNCTION__,
+                  prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+                  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 %s VTEP %s",
+                         mac->zvni->vni,
+                         prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+                         is_local ? "local update, last" :
+                         "remote update, from", 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, nbr)) {
+
+                       /* Ony Mark IPs which are Local */
+                       if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
+                               continue;
+
+                       SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+
+                       nbr->dad_dup_detect_time = monotime(NULL);
+
+                       flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
+                                 "VNI %u: MAC %s IP %s detected as duplicate during %s update, inherit duplicate from MAC",
+                                 mac->zvni->vni,
+                                 prefix_mac2str(&mac->macaddr,
+                                                buf, sizeof(buf)),
+                                 ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+                                 is_local ? "local" : "remote");
+               }
+
+               /* Start auto recovery timer for this MAC */
+               THREAD_OFF(mac->dad_mac_auto_recovery_timer);
+               if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_debug(
+                                       "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start"
+                                       , __PRETTY_FUNCTION__,
+                                       prefix_mac2str(&mac->macaddr, buf,
+                                                      sizeof(buf)),
+                                       mac->flags, zvrf->dad_freeze_time);
+
+                       thread_add_timer(zebrad.master,
+                                        zebra_vxlan_dad_mac_auto_recovery_exp,
+                                        mac, zvrf->dad_freeze_time,
+                                        &mac->dad_mac_auto_recovery_timer);
+               }
+
+               /* Do not inform to client (BGPd),
+                * upd_neigh for neigh sequence change.
+                */
+               if (zvrf->dad_freeze)
+                       *is_dup_detect = false;
+       }
+}
+
+static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
+                                                 zebra_neigh_t *nbr,
+                                                 struct in_addr vtep_ip,
+                                                 bool do_dad,
+                                                 bool *is_dup_detect,
+                                                 bool is_local)
+{
+
+       struct timeval elapsed = {0, 0};
+       char buf[ETHER_ADDR_STRLEN];
+       char buf1[INET6_ADDRSTRLEN];
+       bool reset_params = false;
+
+       if (!zvrf->dup_addr_detect)
+               return;
+
+       /* IP is detected as duplicate or inherit dup
+        * state, hold on to install as remote entry
+        * only if freeze is enabled.
+        */
+       if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                                  "%s: duplicate addr MAC %s IP %s flags 0x%x skip installing, learn count %u recover time %u",
+                                          __PRETTY_FUNCTION__,
+                               prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
+                               ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+                               nbr->flags, nbr->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.
+                */
+               return;
+       }
+
+       if (!do_dad)
+               return;
+
+       /* 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(&nbr->detect_start_time, &elapsed);
+       reset_params = (elapsed.tv_sec > zvrf->dad_time);
+
+       if (is_local && !reset_params) {
+               /* RFC-7432: A PE/VTEP that detects a MAC mobility
+                * event via LOCAL learning starts an M-second timer.
+                *
+                * NOTE: This is the START of the probe with count is
+                * 0 during LOCAL learn event.
+                */
+               reset_params = !nbr->dad_count;
+       }
+
+       if (reset_params) {
+               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(&nbr->emac, buf, sizeof(buf)),
+                               ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+                               nbr->flags, nbr->dad_count);
+               /* Reset learn count but do not start detection
+                * during REMOTE learn event.
+                */
+               nbr->dad_count = 0;
+               /* Start dup. addr detection (DAD) start time,
+                * ONLY during LOCAL learn.
+                */
+               if (is_local)
+                       monotime(&nbr->detect_start_time);
+
+       } else if (!is_local) {
+               /* For REMOTE IP/Neigh, increment detection count
+                * ONLY while in probe window, once window passed,
+                * next local learn event should trigger DAD.
+                */
+               nbr->dad_count++;
+       }
+
+       /* For LOCAL IP/Neigh learn event, once count is reset above via either
+        * initial/start detection time or passed the probe time, the count
+        * needs to be incremented.
+        */
+       if (is_local)
+               nbr->dad_count++;
+
+       if (nbr->dad_count >= zvrf->dad_max_moves) {
+               flog_warn(EC_ZEBRA_DUP_IP_DETECTED,
+                         "VNI %u: MAC %s IP %s detected as duplicate during %s VTEP %s",
+                         nbr->zvni->vni,
+                         prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
+                         ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+                         is_local ? "local update, last" :
+                         "remote update, from",
+                         inet_ntoa(vtep_ip));
+
+               SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+
+               /* Capture Duplicate detection time */
+               nbr->dad_dup_detect_time = monotime(NULL);
+
+               /* Start auto recovery timer for this IP */
+               THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
+               if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_debug(
+                                       "%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start",
+                                  __PRETTY_FUNCTION__,
+                                  prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
+                                  ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+                                  nbr->flags, zvrf->dad_freeze_time);
+
+                       thread_add_timer(zebrad.master,
+                               zebra_vxlan_dad_ip_auto_recovery_exp,
+                               nbr, zvrf->dad_freeze_time,
+                               &nbr->dad_ip_auto_recovery_timer);
+               }
+               if (zvrf->dad_freeze)
+                       *is_dup_detect = true;
+       }
+}
+
 /*
  * Helper function to determine maximum width of neighbor IP address for
  * display - just because we're dealing with IPv6 addresses that can
@@ -301,6 +689,12 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
        const char *type_str;
        const char *state_str;
        bool flags_present = false;
+       struct zebra_vrf *zvrf = NULL;
+       struct timeval detect_start_time = {0, 0};
+
+       zvrf = zebra_vrf_lookup_by_id(n->zvni->vrf_id);
+       if (!zvrf)
+               return;
 
        ipaddr2str(&n->ip, buf2, sizeof(buf2));
        prefix_mac2str(&n->emac, buf1, sizeof(buf1));
@@ -348,9 +742,36 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
                        vty_out(vty, "\n");
                vty_out(vty, " Local Seq: %u Remote Seq: %u\n",
                        n->loc_seq, n->rem_seq);
+
+               if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
+                       vty_out(vty, " Duplicate, detected at %s",
+                               time_to_string(n->dad_dup_detect_time));
+               } else if (n->dad_count) {
+                       monotime_since(&n->detect_start_time,
+                                      &detect_start_time);
+                       if (detect_start_time.tv_sec <= zvrf->dad_time) {
+                               char *buf = time_to_string(
+                                               n->detect_start_time.tv_sec);
+                               char tmp_buf[30];
+
+                               memset(tmp_buf, 0, 30);
+                               strncpy(tmp_buf, buf, strlen(buf) - 1);
+                               vty_out(vty,
+                                       " Duplicate detection started at %s, detection count %u\n",
+                                       tmp_buf, n->dad_count);
+                       }
+               }
        } else {
                json_object_int_add(json, "localSequence", n->loc_seq);
                json_object_int_add(json, "remoteSequence", n->rem_seq);
+               json_object_int_add(json, "detectionCount",
+                                   n->dad_count);
+               if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+                       json_object_boolean_true_add(json, "isDuplicate");
+               else
+                       json_object_boolean_false_add(json, "isDuplicate");
+
+
        }
 }
 
@@ -396,6 +817,14 @@ static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt)
                                            n->loc_seq);
                        json_object_int_add(json_row, "remoteSequence",
                                            n->rem_seq);
+                       json_object_int_add(json_row, "detectionCount",
+                                           n->dad_count);
+                       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+                               json_object_boolean_true_add(json_row,
+                                                            "isDuplicate");
+                       else
+                               json_object_boolean_false_add(json_row,
+                                                             "isDuplicate");
                }
                wctx->count++;
        } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
@@ -426,6 +855,14 @@ static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt)
                                            n->loc_seq);
                        json_object_int_add(json_row, "remoteSequence",
                                            n->rem_seq);
+                       json_object_int_add(json_row, "detectionCount",
+                                           n->dad_count);
+                       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+                               json_object_boolean_true_add(json_row,
+                                                            "isDuplicate");
+                       else
+                               json_object_boolean_false_add(json_row,
+                                                             "isDuplicate");
                }
                wctx->count++;
        }
@@ -446,13 +883,19 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
        uint32_t num_neigh;
        struct neigh_walk_ctx wctx;
        char vni_str[VNI_STR_LEN];
+       uint32_t print_dup;
 
        vty = (struct vty *)args[0];
        json = (json_object *)args[1];
+       print_dup = (uint32_t)(uintptr_t)args[2];
 
        zvni = (zebra_vni_t *)backet->data;
 
        num_neigh = hashcount(zvni->neigh_table);
+
+       if (print_dup)
+               num_neigh = num_dup_detected_neighs(zvni);
+
        if (json == NULL) {
                vty_out(vty,
                        "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
@@ -462,6 +905,7 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
                json_object_int_add(json_vni, "numArpNd", num_neigh);
                snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
        }
+
        if (!num_neigh) {
                if (json)
                        json_object_object_add(json, vni_str, json_vni);
@@ -484,12 +928,28 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
                        -wctx.addr_width, "IP", "Type",
                        "State", "MAC", "Remote VTEP");
        }
-       hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+       if (print_dup)
+               hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash,
+                            &wctx);
+       else
+               hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
 
        if (json)
                json_object_object_add(json, vni_str, json_vni);
 }
 
+static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt)
+{
+       zebra_neigh_t *nbr;
+
+       nbr = (zebra_neigh_t *)backet->data;
+       if (!nbr)
+               return;
+
+       if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
+               zvni_print_neigh_hash(backet, ctxt);
+}
+
 /* print a specific next hop for an l3vni */
 static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
                            json_object *json)
@@ -576,6 +1036,10 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
        struct listnode *node = NULL;
        char buf1[20];
        char buf2[INET6_ADDRSTRLEN];
+       struct zebra_vrf *zvrf;
+       struct timeval detect_start_time = {0, 0};
+
+       zvrf = zebra_vrf_lookup_by_id(mac->zvni->vrf_id);
 
        vty = (struct vty *)ctxt;
        prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
@@ -621,6 +1085,12 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
                json_object_int_add(json_mac, "localSequence", mac->loc_seq);
                json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
 
+               json_object_int_add(json_mac, "detectionCount", mac->dad_count);
+               if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+                       json_object_boolean_true_add(json_mac, "isDuplicate");
+               else
+                       json_object_boolean_false_add(json_mac, "isDuplicate");
+
                /* print all the associated neigh */
                if (!listcount(mac->neigh_list))
                        json_object_string_add(json_mac, "neighbors", "none");
@@ -698,6 +1168,25 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
                        mac->rem_seq);
                vty_out(vty, "\n");
 
+               if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
+                       vty_out(vty, " Duplicate, detected at %s",
+                               time_to_string(mac->dad_dup_detect_time));
+               } else if (mac->dad_count) {
+                       monotime_since(&mac->detect_start_time,
+                              &detect_start_time);
+                       if (detect_start_time.tv_sec <= zvrf->dad_time) {
+                               char *buf = time_to_string(
+                                               mac->detect_start_time.tv_sec);
+                               char tmp_buf[30];
+
+                               memset(tmp_buf, 0, 30);
+                               strncpy(tmp_buf, buf, strlen(buf) - 1);
+                               vty_out(vty,
+                                       " Duplicate detection started at %s, detection count %u\n",
+                                       tmp_buf, mac->dad_count);
+                       }
+               }
+
                /* print all the associated neigh */
                vty_out(vty, " Neighbors:\n");
                if (!listcount(mac->neigh_list))
@@ -771,6 +1260,14 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
                                            mac->loc_seq);
                        json_object_int_add(json_mac, "remoteSequence",
                                            mac->rem_seq);
+                       json_object_int_add(json_mac, "detectionCount",
+                                           mac->dad_count);
+                       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+                               json_object_boolean_true_add(json_mac,
+                                                            "isDuplicate");
+                       else
+                               json_object_boolean_false_add(json_mac,
+                                                            "isDuplicate");
                        json_object_object_add(json_mac_hdr, buf1, json_mac);
                }
 
@@ -801,12 +1298,34 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
                                            mac->loc_seq);
                        json_object_int_add(json_mac, "remoteSequence",
                                            mac->rem_seq);
+                       json_object_int_add(json_mac, "detectionCount",
+                                           mac->dad_count);
+                       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+                               json_object_boolean_true_add(json_mac,
+                                                            "isDuplicate");
+                       else
+                               json_object_boolean_false_add(json_mac,
+                                                             "isDuplicate");
+
                }
 
                wctx->count++;
        }
 }
 
+/* Print Duplicate MAC */
+static void zvni_print_dad_mac_hash(struct hash_backet *backet, void *ctxt)
+{
+       zebra_mac_t *mac;
+
+       mac = (zebra_mac_t *)backet->data;
+       if (!mac)
+               return;
+
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+               zvni_print_mac_hash(backet, ctxt);
+}
+
 /*
  * Print MACs for all VNI.
  */
@@ -833,6 +1352,9 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt)
        if (!num_macs)
                return;
 
+       if (wctx->print_dup)
+               num_macs = num_dup_detected_macs(zvni);
+
        if (json) {
                json_vni = json_object_new_object();
                json_mac = json_object_new_object();
@@ -848,12 +1370,24 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt)
                } else
                        json_object_int_add(json_vni, "numMacs", num_macs);
        }
+
+       if (!num_macs) {
+               if (json) {
+                       json_object_int_add(json_vni, "numMacs", num_macs);
+                       json_object_object_add(json, vni_str, json_vni);
+               }
+               return;
+       }
+
        /* assign per-vni to wctx->json object to fill macs
         * under the vni. Re-assign primary json object to fill
         * next vni information.
         */
        wctx->json = json_mac;
-       hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx);
+       if (wctx->print_dup)
+               hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, wctx);
+       else
+               hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx);
        wctx->json = json;
        if (json) {
                if (wctx->count)
@@ -1512,8 +2046,11 @@ static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
 {
        zebra_neigh_t *n = NULL;
        struct listnode *node = NULL;
+       struct zebra_vrf *zvrf = NULL;
        char buf[ETHER_ADDR_STRLEN];
 
+       zvrf = vrf_info_lookup(zvni->vrf_id);
+
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
                           prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
@@ -1530,9 +2067,12 @@ static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
                        if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change) {
                                ZEBRA_NEIGH_SET_ACTIVE(n);
                                n->loc_seq = zmac->loc_seq;
-                               zvni_neigh_send_add_to_client(
-                                       zvni->vni, &n->ip, &n->emac,
-                                       n->flags, n->loc_seq);
+                               if (!(zvrf->dup_addr_detect &&
+                                     zvrf->dad_freeze && !!CHECK_FLAG(n->flags,
+                                               ZEBRA_NEIGH_DUPLICATE)))
+                                       zvni_neigh_send_add_to_client(
+                                               zvni->vni, &n->ip, &n->emac,
+                                               n->flags, n->loc_seq);
                        }
                }
        }
@@ -2059,12 +2599,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;
+       bool do_dad = false;
+       struct in_addr vtep_ip = {.s_addr = 0};
 
        /* Check if the MAC exists. */
        zmac = zvni_mac_lookup(zvni, macaddr);
@@ -2100,6 +2644,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 +2665,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 +2681,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 +2691,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 +2756,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 +2783,34 @@ 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)));
+       }
+
+       /* For IP Duplicate Address Detection (DAD) is trigger,
+        * when the event is extended mobility based on scenario-B
+        * from the draft, IP/Neigh's MAC binding changed and
+        * neigh's previous state was remote.
+        */
+       if (neigh_mac_change && neigh_was_remote)
+               do_dad = true;
+
+       zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n, vtep_ip, do_dad,
+                                             &neigh_on_hold, true);
+
        /* 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 +2821,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 +2841,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 +4750,20 @@ 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;
 
        /* Locate VNI hash entry - expected to exist. */
        zvni = zvni_lookup(vni);
@@ -4235,6 +4821,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 +4886,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 +4919,16 @@ static void process_remote_macip_add(vni_t vni,
                else
                        UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
 
+               zebra_vxlan_dup_addr_detect_for_mac(zvrf, mac,
+                                                   mac->fwd_info.r_vtep_ip,
+                                                   do_dad, &is_dup_detect,
+                                                   false);
+
                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 +4940,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 +5017,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 +5050,27 @@ 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)));
+               }
+
+               /* Check duplicate address detection for IP */
+               zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n,
+                                                     n->r_vtep_ip,
+                                                     do_dad,
+                                                     &is_dup_detect,
+                                                     false);
                /* Install the entry. */
-               zvni_neigh_install(zvni, n);
+               if (!is_dup_detect)
+                       zvni_neigh_install(zvni, n);
        }
 
        /* Update seq number. */
@@ -4991,10 +5640,10 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
  * Display neighbors across all VNIs (VTY command handler).
  */
 void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
-                                    bool use_json)
+                                    bool print_dup, bool use_json)
 {
        json_object *json = NULL;
-       void *args[2];
+       void *args[3];
 
        if (!is_evpn_enabled())
                return;
@@ -5004,6 +5653,8 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
 
        args[0] = vty;
        args[1] = json;
+       args[2] = (void *)(ptrdiff_t)print_dup;
+
        hash_iterate(zvrf->vni_table,
                     (void (*)(struct hash_backet *,
                               void *))zvni_print_neigh_hash_all_vni,
@@ -5101,38 +5752,102 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
 }
 
 /*
- * Display MACs for a VNI (VTY command handler).
+ * Display Duplicate detected Neighbors for a VNI
+ * (VTY command handler).
  */
-void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
-                               vni_t vni, bool use_json)
+void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
+                                    struct zebra_vrf *zvrf,
+                                    vni_t vni,
+                                    bool use_json)
 {
        zebra_vni_t *zvni;
-       uint32_t num_macs;
-       struct mac_walk_ctx wctx;
+       uint32_t num_neigh;
+       struct neigh_walk_ctx wctx;
        json_object *json = NULL;
-       json_object *json_mac = NULL;
 
        if (!is_evpn_enabled())
                return;
+
        zvni = zvni_lookup(vni);
        if (!zvni) {
-               if (use_json)
-                       vty_out(vty, "{}\n");
-               else
-                       vty_out(vty, "%% VNI %u does not exist\n", vni);
+               vty_out(vty, "%% VNI %u does not exist\n", vni);
                return;
        }
-       num_macs = num_valid_macs(zvni);
-       if (!num_macs)
+
+       num_neigh = hashcount(zvni->neigh_table);
+       if (!num_neigh)
                return;
 
-       if (use_json) {
+       num_neigh = num_dup_detected_neighs(zvni);
+       if (!num_neigh)
+               return;
+
+       if (use_json)
                json = json_object_new_object();
-               json_mac = json_object_new_object();
-       }
 
-       memset(&wctx, 0, sizeof(struct mac_walk_ctx));
-       wctx.zvni = zvni;
+       /* Since we have IPv6 addresses to deal with which can vary widely in
+        * size, we try to be a bit more elegant in display by first computing
+        * the maximum width.
+        */
+       memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
+       wctx.zvni = zvni;
+       wctx.vty = vty;
+       wctx.addr_width = 15;
+       wctx.json = json;
+       hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+
+       if (!use_json) {
+               vty_out(vty,
+                       "Number of ARPs (local and remote) known for this VNI: %u\n",
+                       num_neigh);
+               vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+                       -wctx.addr_width, "IP", "Type",
+                       "State", "MAC", "Remote VTEP");
+       } else
+               json_object_int_add(json, "numArpNd", num_neigh);
+
+       hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash, &wctx);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+/*
+ * Display MACs for a VNI (VTY command handler).
+ */
+void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
+                               vni_t vni, bool use_json)
+{
+       zebra_vni_t *zvni;
+       uint32_t num_macs;
+       struct mac_walk_ctx wctx;
+       json_object *json = NULL;
+       json_object *json_mac = NULL;
+
+       if (!is_evpn_enabled())
+               return;
+       zvni = zvni_lookup(vni);
+       if (!zvni) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "%% VNI %u does not exist\n", vni);
+               return;
+       }
+       num_macs = num_valid_macs(zvni);
+       if (!num_macs)
+               return;
+
+       if (use_json) {
+               json = json_object_new_object();
+               json_mac = json_object_new_object();
+       }
+
+       memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+       wctx.zvni = zvni;
        wctx.vty = vty;
        wctx.json = json_mac;
 
@@ -5159,7 +5874,7 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
  * Display MACs for all VNIs (VTY command handler).
  */
 void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
-                                   bool use_json)
+                                   bool print_dup, bool use_json)
 {
        struct mac_walk_ctx wctx;
        json_object *json = NULL;
@@ -5175,6 +5890,7 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
        memset(&wctx, 0, sizeof(struct mac_walk_ctx));
        wctx.vty = vty;
        wctx.json = json;
+       wctx.print_dup = print_dup;
        hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
 
        if (use_json) {
@@ -5253,6 +5969,393 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
        zvni_print_mac(mac, vty, json);
 }
 
+/* Print Duplicate MACs per VNI */
+void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
+                                   struct zebra_vrf *zvrf,
+                                   vni_t vni, bool use_json)
+{
+       zebra_vni_t *zvni;
+       struct mac_walk_ctx wctx;
+       uint32_t num_macs;
+       json_object *json = NULL;
+       json_object *json_mac = NULL;
+
+       if (!is_evpn_enabled())
+               return;
+
+       zvni = zvni_lookup(vni);
+       if (!zvni) {
+               vty_out(vty, "%% VNI %u does not exist\n", vni);
+               return;
+       }
+
+       num_macs = num_valid_macs(zvni);
+       if (!num_macs)
+               return;
+
+       num_macs = num_dup_detected_macs(zvni);
+       if (!num_macs)
+               return;
+
+       if (use_json) {
+               json = json_object_new_object();
+               json_mac = json_object_new_object();
+       }
+
+       memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+       wctx.zvni = zvni;
+       wctx.vty = vty;
+       wctx.json = json_mac;
+
+       if (!use_json) {
+               vty_out(vty,
+               "Number of MACs (local and remote) known for this VNI: %u\n",
+                       num_macs);
+               vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
+                       "Intf/Remote VTEP", "VLAN");
+       } else
+               json_object_int_add(json, "numMacs", num_macs);
+
+       hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, &wctx);
+
+       if (use_json) {
+               json_object_object_add(json, "macs", json_mac);
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+}
+
+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).
  */
@@ -5373,11 +6476,34 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
                json_object_int_add(json, "numVnis", num_vnis);
                json_object_int_add(json, "numL2Vnis", num_l2vnis);
                json_object_int_add(json, "numL3Vnis", num_l3vnis);
+               if (zvrf->dup_addr_detect)
+                       json_object_boolean_true_add(json,
+                                               "isDuplicateAddrDetection");
+               else
+                       json_object_boolean_false_add(json,
+                                               "isDuplicateAddrDetection");
+               json_object_int_add(json, "maxMoves", zvrf->dad_max_moves);
+               json_object_int_add(json, "detectionTime", zvrf->dad_time);
+               json_object_int_add(json, "detectionFreezeTime",
+                                   zvrf->dad_freeze_time);
+
        } else {
                vty_out(vty, "L2 VNIs: %u\n", num_l2vnis);
                vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
                vty_out(vty, "Advertise gateway mac-ip: %s\n",
                        zvrf->advertise_gw_macip ? "Yes" : "No");
+               vty_out(vty, "Duplicate address detection: %s\n",
+                       zvrf->dup_addr_detect ? "Enable" : "Disable");
+               vty_out(vty, "  Detection max-moves %u, time %d\n",
+                       zvrf->dad_max_moves, zvrf->dad_time);
+               if (zvrf->dad_freeze) {
+                       if (zvrf->dad_freeze_time)
+                               vty_out(vty, "  Detection freeze %u\n",
+                                       zvrf->dad_freeze_time);
+                       else
+                               vty_out(vty, "  Detection freeze %s\n",
+                                       "permanent");
+               }
        }
 
        if (uj) {
@@ -5426,6 +6552,48 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
        }
 }
 
+void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
+{
+       struct stream *s;
+       int time = 0;
+       uint32_t max_moves = 0;
+       uint32_t freeze_time = 0;
+       bool dup_addr_detect = false;
+       bool freeze = false;
+
+       s = msg;
+       STREAM_GETL(s, dup_addr_detect);
+       STREAM_GETL(s, time);
+       STREAM_GETL(s, max_moves);
+       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;
+       zvrf->dad_freeze = freeze;
+       zvrf->dad_freeze_time = freeze_time;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                       "%s: duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
+                       __PRETTY_FUNCTION__,
+                       zvrf->dup_addr_detect ? "enable" : "disable",
+                       zvrf->dad_max_moves,
+                       zvrf->dad_time,
+                       zvrf->dad_freeze ? "enable" : "disable",
+                       zvrf->dad_freeze_time);
+
+stream_failure:
+       return;
+}
+
 /*
  * Handle neighbor delete notification from the kernel (on a VLAN device
  * / L3 interface). This may result in either the neighbor getting deleted
@@ -5871,10 +7039,12 @@ 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;
+       struct in_addr vtep_ip = {.s_addr = 0};
 
        /* We are interested in MACs only on ports or (port, VLAN) that
         * map to a VNI.
@@ -5897,6 +7067,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) {
@@ -5970,6 +7144,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
@@ -5989,9 +7164,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);
@@ -6008,6 +7188,11 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
                         */
                        inform_client = true;
                        upd_neigh = true;
+
+                       zebra_vxlan_dup_addr_detect_for_mac(zvrf, mac, vtep_ip,
+                                                           do_dad,
+                                                           &inform_client,
+                                                           true);
                }
        }
 
@@ -7334,3 +8519,125 @@ ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
 
        return zl3vni->svi_if->ifindex;
 }
+
+static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t)
+{
+       struct zebra_vrf *zvrf = NULL;
+       zebra_neigh_t *nbr = NULL;
+       zebra_vni_t *zvni = NULL;
+       char buf1[INET6_ADDRSTRLEN];
+       char buf2[ETHER_ADDR_STRLEN];
+
+       nbr = THREAD_ARG(t);
+
+       /* since this is asynchronous we need sanity checks*/
+       zvrf = vrf_info_lookup(nbr->zvni->vrf_id);
+       if (!zvrf)
+               return 0;
+
+       zvni = zvni_lookup(nbr->zvni->vni);
+       if (!zvni)
+               return 0;
+
+       nbr = zvni_neigh_lookup(zvni, &nbr->ip);
+       if (!nbr)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired",
+                         __PRETTY_FUNCTION__,
+                         prefix_mac2str(&nbr->emac, buf1, sizeof(buf1)),
+                         ipaddr2str(&nbr->ip, buf2, sizeof(buf2)),
+                         nbr->flags,
+                         nbr->dad_count, zvni->vni);
+
+       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;
+       nbr->dad_ip_auto_recovery_timer = NULL;
+
+       /* Send to BGP */
+       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);
+       }
+
+       return 0;
+}
+
+static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
+{
+       struct zebra_vrf *zvrf = NULL;
+       zebra_mac_t *mac = NULL;
+       zebra_vni_t *zvni = NULL;
+       struct listnode *node = NULL;
+       zebra_neigh_t *nbr = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+
+       mac = THREAD_ARG(t);
+
+       /* since this is asynchronous we need sanity checks*/
+       zvrf = vrf_info_lookup(mac->zvni->vrf_id);
+       if (!zvrf)
+               return 0;
+
+       zvni = zvni_lookup(mac->zvni->vni);
+       if (!zvni)
+               return 0;
+
+       mac = zvni_mac_lookup(zvni, &mac->macaddr);
+       if (!mac)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired",
+                           __PRETTY_FUNCTION__,
+                           prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+                           mac->flags,
+                           mac->dad_count,
+                           listcount(mac->neigh_list));
+
+       /* Remove all IPs as duplicate associcated with this MAC */
+       for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
+               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;
+       mac->dad_mac_auto_recovery_timer = NULL;
+
+       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 -1;
+
+               /* 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);
+       }
+
+       return 0;
+}
index 1c394e9effad895bcd6643a67ab7a5e3c6e91474..bf6e4290dc946e7e95c8a90b0991ad760438ea68 100644 (file)
@@ -70,6 +70,7 @@ extern void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS);
 extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS);
 extern void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS);
 extern void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS);
+extern void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS);
 
 extern int is_l3vni_for_prefix_routes_only(vni_t vni);
 extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
@@ -87,6 +88,7 @@ extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
                                       vni_t vni, bool use_json);
 extern void zebra_vxlan_print_macs_all_vni(struct vty *vty,
                                           struct zebra_vrf *zvrf,
+                                          bool print_dup,
                                           bool use_json);
 extern void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
                                                struct zebra_vrf *zvrf,
@@ -100,10 +102,14 @@ extern void zebra_vxlan_print_macs_vni_vtep(struct vty *vty,
                                            struct zebra_vrf *zvrf, vni_t vni,
                                            struct in_addr vtep_ip,
                                            bool use_json);
+extern void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
+                                          struct zebra_vrf *zvrf, vni_t vni,
+                                          bool use_json);
 extern void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
                                        vni_t vni, bool use_json);
 extern void zebra_vxlan_print_neigh_all_vni(struct vty *vty,
                                            struct zebra_vrf *zvrf,
+                                           bool print_dup,
                                            bool use_json);
 extern void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
                                                 struct zebra_vrf *zvrf,
@@ -113,6 +119,9 @@ extern void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty,
                                             struct zebra_vrf *zvrf, vni_t vni,
                                             struct in_addr vtep_ip,
                                             bool use_json);
+extern void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
+                                       struct zebra_vrf *zvrf, vni_t vni,
+                                       bool use_json);
 extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf,
                                  vni_t vni, bool use_json);
 extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
@@ -172,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 */
index 44163eb331b6eae20de1a72405a971e49da41096..3be7dc012ac2839bb4939f258c25a84c4e0e2495 100644 (file)
@@ -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;
 };
 
 /*
@@ -292,6 +305,7 @@ struct mac_walk_ctx {
        struct vty *vty;          /* Used by VTY handlers */
        uint32_t count;           /* Used by VTY handlers */
        struct json_object *json; /* Used for JSON Output */
+       bool print_dup; /* Used to print dup addr list */
 };
 
 struct rmac_walk_ctx {
@@ -330,12 +344,15 @@ struct zebra_neigh_t_ {
        /* Underlying interface. */
        ifindex_t ifindex;
 
+       zebra_vni_t *zvni;
+
        uint32_t flags;
 #define ZEBRA_NEIGH_LOCAL     0x01
 #define ZEBRA_NEIGH_REMOTE    0x02
 #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 +371,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;
 };
 
 /*
index 3c3bf4077b745bb8a41f2f51a61406625fd7ca9f..b40e9e2af51fff8688d09ba9a7fd3bd2e5d68f0a 100644 (file)
@@ -875,7 +875,7 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
        char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
        char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
        time_t connect_time, last_read_time, last_write_time;
-       uint16_t last_read_cmd, last_write_cmd;
+       uint32_t last_read_cmd, last_write_cmd;
 
        vty_out(vty, "Client: %s", zebra_route_string(client->proto));
        if (client->instance)
index f21ea17fe884d1fe3d63b5afd4f54b489d7bc611..f7967f54f00b18e6afa5da7b5e4db12950ad21bd 100644 (file)
@@ -157,9 +157,9 @@ struct zserv {
        /* monotime of last message sent */
        _Atomic uint32_t last_write_time;
        /* command code of last message read */
-       _Atomic uint16_t last_read_cmd;
+       _Atomic uint32_t last_read_cmd;
        /* command code of last message written */
-       _Atomic uint16_t last_write_cmd;
+       _Atomic uint32_t last_write_cmd;
 };
 
 #define ZAPI_HANDLER_ARGS                                                      \