]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: add support for maintaining local neigh entries
authorAnuradha Karuppiah <anuradhak@nvidia.com>
Sat, 18 Dec 2021 19:28:49 +0000 (11:28 -0800)
committerDonald Sharp <sharpd@nvidia.com>
Mon, 27 Jun 2022 11:56:55 +0000 (07:56 -0400)
Currently specific local neighbors (attached to SVIs) are maintatined
in an EVPN specific database. There is a need to maintain L3 neighbors
for other purposes including MAC resolution for PBR nexthops.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
   Cleanup compile and fix crash
Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
zebra/debug.c
zebra/debug.h
zebra/rt_netlink.c
zebra/subdir.am
zebra/zebra_neigh.c [new file with mode: 0644]
zebra/zebra_neigh.h [new file with mode: 0644]
zebra/zebra_pbr.h
zebra/zebra_router.c
zebra/zebra_router.h
zebra/zebra_vty.c

index 525180d4eecf4ffd4c6a773d93c545c881c350fc..98e25af8577a582fbe7b9b30d72c56a9cb73b21a 100644 (file)
@@ -42,6 +42,7 @@ unsigned long zebra_debug_mlag;
 unsigned long zebra_debug_nexthop;
 unsigned long zebra_debug_evpn_mh;
 unsigned long zebra_debug_pbr;
+unsigned long zebra_debug_neigh;
 
 DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
 
@@ -327,6 +328,22 @@ DEFUN (debug_zebra_pbr,
        return CMD_SUCCESS;
 }
 
+DEFPY (debug_zebra_neigh,
+       debug_zebra_neigh_cmd,
+       "[no$no] debug zebra neigh",
+       NO_STR
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug zebra neigh events\n")
+{
+       if (no)
+               UNSET_FLAG(zebra_debug_neigh, ZEBRA_DEBUG_NEIGH);
+       else
+               SET_FLAG(zebra_debug_neigh, ZEBRA_DEBUG_NEIGH);
+
+       return CMD_SUCCESS;
+}
+
 DEFPY (debug_zebra_mlag,
        debug_zebra_mlag_cmd,
        "[no$no] debug zebra mlag",
@@ -694,6 +711,11 @@ static int config_write_debug(struct vty *vty)
                write++;
        }
 
+       if (IS_ZEBRA_DEBUG_NEIGH) {
+               vty_out(vty, "debug zebra neigh\n");
+               write++;
+       }
+
        return write;
 }
 
@@ -713,6 +735,7 @@ void zebra_debug_init(void)
        zebra_debug_nht = 0;
        zebra_debug_nexthop = 0;
        zebra_debug_pbr = 0;
+       zebra_debug_neigh = 0;
 
        install_node(&debug_node);
 
@@ -734,6 +757,7 @@ void zebra_debug_init(void)
        install_element(ENABLE_NODE, &debug_zebra_mlag_cmd);
        install_element(ENABLE_NODE, &debug_zebra_nexthop_cmd);
        install_element(ENABLE_NODE, &debug_zebra_pbr_cmd);
+       install_element(ENABLE_NODE, &debug_zebra_neigh_cmd);
        install_element(ENABLE_NODE, &no_debug_zebra_events_cmd);
        install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd);
        install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd);
@@ -764,6 +788,7 @@ void zebra_debug_init(void)
        install_element(CONFIG_NODE, &debug_zebra_dplane_cmd);
        install_element(CONFIG_NODE, &debug_zebra_nexthop_cmd);
        install_element(CONFIG_NODE, &debug_zebra_pbr_cmd);
+       install_element(CONFIG_NODE, &debug_zebra_neigh_cmd);
 
        install_element(CONFIG_NODE, &no_debug_zebra_events_cmd);
        install_element(CONFIG_NODE, &no_debug_zebra_nht_cmd);
index dc44367d01d06dad2718817120f5eb23d8e1d9b7..e761e5e3e314ab52ae427ae17011124c9adf2b37 100644 (file)
@@ -70,6 +70,8 @@ extern "C" {
 
 #define ZEBRA_DEBUG_PBR 0x01
 
+#define ZEBRA_DEBUG_NEIGH 0x01
+
 /* Debug related macro. */
 #define IS_ZEBRA_DEBUG_EVENT  (zebra_debug_event & ZEBRA_DEBUG_EVENT)
 
@@ -121,6 +123,8 @@ extern "C" {
 
 #define IS_ZEBRA_DEBUG_PBR (zebra_debug_pbr & ZEBRA_DEBUG_PBR)
 
+#define IS_ZEBRA_DEBUG_NEIGH (zebra_debug_neigh & ZEBRA_DEBUG_NEIGH)
+
 extern unsigned long zebra_debug_event;
 extern unsigned long zebra_debug_packet;
 extern unsigned long zebra_debug_kernel;
@@ -135,6 +139,7 @@ extern unsigned long zebra_debug_mlag;
 extern unsigned long zebra_debug_nexthop;
 extern unsigned long zebra_debug_evpn_mh;
 extern unsigned long zebra_debug_pbr;
+extern unsigned long zebra_debug_neigh;
 
 extern void zebra_debug_init(void);
 
index ad9e13a0f844c27de8d55b151d0817727ce82a49..21c991c7db2cfa307abd6824fb8978a0b80a0711 100644 (file)
@@ -80,6 +80,7 @@
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_evpn_mh.h"
 #include "zebra/zebra_trace.h"
+#include "zebra/zebra_neigh.h"
 
 #ifndef AF_MPLS
 #define AF_MPLS 28
@@ -3882,10 +3883,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        } else if (IS_ZEBRA_IF_BRIDGE(ifp))
                link_if = ifp;
        else {
+               link_if = NULL;
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug(
                                "    Neighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
-               return 0;
        }
 
        memset(&mac, 0, sizeof(mac));
@@ -3949,12 +3950,25 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                                 */
                                local_inactive = false;
 
-                       return zebra_vxlan_handle_kernel_neigh_update(
-                               ifp, link_if, &ip, &mac, ndm->ndm_state, is_ext,
-                               is_router, local_inactive, dp_static);
+                       /* Add local neighbors to the l3 interface database */
+                       if (is_ext)
+                               zebra_neigh_del(ifp, &ip);
+                       else
+                               zebra_neigh_add(ifp, &ip, &mac);
+
+                       if (link_if)
+                               zebra_vxlan_handle_kernel_neigh_update(
+                                       ifp, link_if, &ip, &mac, ndm->ndm_state,
+                                       is_ext, is_router, local_inactive,
+                                       dp_static);
+                       return 0;
                }
 
-               return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
+
+               zebra_neigh_del(ifp, &ip);
+               if (link_if)
+                       zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
+               return 0;
        }
 
        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -3967,7 +3981,11 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        /* Process the delete - it may result in re-adding the neighbor if it is
         * a valid "remote" neighbor.
         */
-       return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
+       zebra_neigh_del(ifp, &ip);
+       if (link_if)
+               zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
+
+       return 0;
 }
 
 static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
index a09b895cee289b9d20f26d7caad352e3aa6dd7bb..e895ffa65f2683b9f39ae5386695a8374f1baee8 100644 (file)
@@ -125,6 +125,7 @@ zebra_zebra_SOURCES = \
        zebra/zebra_vty.c \
        zebra/zebra_vxlan.c \
        zebra/zebra_evpn_mh.c \
+       zebra/zebra_neigh.c \
        zebra/zserv.c \
        # end
 
@@ -197,6 +198,7 @@ noinst_HEADERS += \
        zebra/zebra_vxlan.h \
        zebra/zebra_vxlan_private.h \
        zebra/zebra_evpn_mh.h \
+       zebra/zebra_neigh.h \
        zebra/zserv.h \
        # end
 
diff --git a/zebra/zebra_neigh.c b/zebra/zebra_neigh.c
new file mode 100644 (file)
index 0000000..2fca2a0
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Zebra neighbor table management
+ *
+ * Copyright (C) 2021 Nvidia
+ * Anuradha Karuppiah
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "hash.h"
+#include "if.h"
+#include "jhash.h"
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "stream.h"
+#include "table.h"
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_neigh.h"
+#include "zebra/zebra_pbr.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_INFO, "Zebra neigh table");
+DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_ENT, "Zebra neigh entry");
+
+static int zebra_neigh_rb_cmp(const struct zebra_neigh_ent *n1,
+                             const struct zebra_neigh_ent *n2)
+{
+       if (n1->ifindex < n2->ifindex)
+               return -1;
+
+       if (n1->ifindex > n2->ifindex)
+               return 1;
+
+       if (n1->ip.ipa_type < n2->ip.ipa_type)
+               return -1;
+
+       if (n1->ip.ipa_type > n2->ip.ipa_type)
+               return 1;
+
+       if (n1->ip.ipa_type == AF_INET) {
+               if (n1->ip.ipaddr_v4.s_addr < n2->ip.ipaddr_v4.s_addr)
+                       return -1;
+
+               if (n1->ip.ipaddr_v4.s_addr > n2->ip.ipaddr_v4.s_addr)
+                       return 1;
+
+               return 0;
+       }
+
+       return memcmp(&n1->ip.ipaddr_v6, &n2->ip.ipaddr_v6, IPV6_MAX_BYTELEN);
+}
+RB_GENERATE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_neigh_rb_cmp);
+
+static struct zebra_neigh_ent *zebra_neigh_find(ifindex_t ifindex,
+                                               struct ipaddr *ip)
+{
+       struct zebra_neigh_ent tmp;
+
+       tmp.ifindex = ifindex;
+       memcpy(&tmp.ip, ip, sizeof(*ip));
+       return RB_FIND(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, &tmp);
+}
+
+static struct zebra_neigh_ent *
+zebra_neigh_new(ifindex_t ifindex, struct ipaddr *ip, struct ethaddr *mac)
+{
+       struct zebra_neigh_ent *n;
+
+       n = XCALLOC(MTYPE_ZNEIGH_ENT, sizeof(struct zebra_neigh_ent));
+
+       memcpy(&n->ip, ip, sizeof(*ip));
+       n->ifindex = ifindex;
+       if (mac) {
+               memcpy(&n->mac, mac, sizeof(*mac));
+               n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
+       }
+
+       /* Add to rb_tree */
+       if (RB_INSERT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n)) {
+               XFREE(MTYPE_ZNEIGH_ENT, n);
+               return NULL;
+       }
+
+       /* Initialise the pbr rule list */
+       n->pbr_rule_list = list_new();
+       listset_app_node_mem(n->pbr_rule_list);
+
+       if (IS_ZEBRA_DEBUG_NEIGH)
+               zlog_debug("zebra neigh new if %d %pIA %pEA", n->ifindex,
+                          &n->ip, &n->mac);
+
+       return n;
+}
+
+static void zebra_neigh_pbr_rules_update(struct zebra_neigh_ent *n)
+{
+       struct zebra_pbr_rule *rule;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(n->pbr_rule_list, node, rule))
+               dplane_pbr_rule_update(rule, rule);
+}
+
+static void zebra_neigh_free(struct zebra_neigh_ent *n)
+{
+       if (listcount(n->pbr_rule_list)) {
+               /* if rules are still using the neigh mark it as inactive and
+                * update the dataplane
+                */
+               if (n->flags & ZEBRA_NEIGH_ENT_ACTIVE) {
+                       n->flags &= ~ZEBRA_NEIGH_ENT_ACTIVE;
+                       memset(&n->mac, 0, sizeof(n->mac));
+               }
+               zebra_neigh_pbr_rules_update(n);
+               return;
+       }
+       if (IS_ZEBRA_DEBUG_NEIGH)
+               zlog_debug("zebra neigh free if %d %pIA %pEA", n->ifindex,
+                          &n->ip, &n->mac);
+
+       /* cleanup resources maintained against the neigh */
+       list_delete(&n->pbr_rule_list);
+
+       RB_REMOVE(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n);
+
+       XFREE(MTYPE_ZNEIGH_ENT, n);
+}
+
+/* kernel neigh del */
+void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip)
+{
+       struct zebra_neigh_ent *n;
+
+       if (IS_ZEBRA_DEBUG_NEIGH)
+               zlog_debug("zebra neigh del if %s/%d %pIA", ifp->name,
+                          ifp->ifindex, ip);
+
+       n = zebra_neigh_find(ifp->ifindex, ip);
+       if (!n)
+               return;
+       zebra_neigh_free(n);
+}
+
+/* kernel neigh add */
+void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
+                    struct ethaddr *mac)
+{
+       struct zebra_neigh_ent *n;
+
+       if (IS_ZEBRA_DEBUG_NEIGH)
+               zlog_debug("zebra neigh add if %s/%d %pIA %pEA", ifp->name,
+                          ifp->ifindex, ip, mac);
+
+       n = zebra_neigh_find(ifp->ifindex, ip);
+       if (n) {
+               if (!memcmp(&n->mac, mac, sizeof(*mac)))
+                       return;
+
+               memcpy(&n->mac, mac, sizeof(*mac));
+               n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
+
+               /* update rules linked to the neigh */
+               zebra_neigh_pbr_rules_update(n);
+       } else {
+               zebra_neigh_new(ifp->ifindex, ip, mac);
+       }
+}
+
+void zebra_neigh_deref(struct zebra_pbr_rule *rule)
+{
+       struct zebra_neigh_ent *n = rule->action.neigh;
+
+       if (IS_ZEBRA_DEBUG_NEIGH)
+               zlog_debug("zebra neigh deref if %d %pIA by pbr rule %u",
+                          n->ifindex, &n->ip, rule->rule.seq);
+
+       rule->action.neigh = NULL;
+       /* remove rule from the list and free if it is inactive */
+       list_delete_node(n->pbr_rule_list, &rule->action.neigh_listnode);
+       if (!(n->flags & ZEBRA_NEIGH_ENT_ACTIVE))
+               zebra_neigh_free(n);
+}
+
+/* XXX - this needs to work with evpn's neigh read */
+static void zebra_neigh_read_on_first_ref(void)
+{
+       static bool neigh_read_done;
+
+       if (!neigh_read_done) {
+               neigh_read(zebra_ns_lookup(NS_DEFAULT));
+               neigh_read_done = true;
+       }
+}
+
+void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
+                    struct zebra_pbr_rule *rule)
+{
+       struct zebra_neigh_ent *n;
+
+       if (IS_ZEBRA_DEBUG_NEIGH)
+               zlog_debug("zebra neigh ref if %d %pIA by pbr rule %u", ifindex,
+                          ip, rule->rule.seq);
+
+       zebra_neigh_read_on_first_ref();
+       n = zebra_neigh_find(ifindex, ip);
+       if (!n)
+               n = zebra_neigh_new(ifindex, ip, NULL);
+
+       /* link the pbr entry to the neigh */
+       if (rule->action.neigh == n)
+               return;
+
+       if (rule->action.neigh)
+               zebra_neigh_deref(rule);
+
+       rule->action.neigh = n;
+       listnode_init(&rule->action.neigh_listnode, rule);
+       listnode_add(n->pbr_rule_list, &rule->action.neigh_listnode);
+}
+
+static void zebra_neigh_show_one(struct vty *vty, struct zebra_neigh_ent *n)
+{
+       char mac_buf[ETHER_ADDR_STRLEN];
+       char ip_buf[INET6_ADDRSTRLEN];
+       struct interface *ifp;
+
+       ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+                                       n->ifindex);
+       ipaddr2str(&n->ip, ip_buf, sizeof(ip_buf));
+       prefix_mac2str(&n->mac, mac_buf, sizeof(mac_buf));
+       vty_out(vty, "%-20s %-30s %-18s %u\n", ifp ? ifp->name : "-", ip_buf,
+               mac_buf, listcount(n->pbr_rule_list));
+}
+
+void zebra_neigh_show(struct vty *vty)
+{
+       struct zebra_neigh_ent *n;
+
+       vty_out(vty, "%-20s %-30s %-18s %s\n", "Interface", "Neighbor", "MAC",
+               "#Rules");
+       RB_FOREACH (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree)
+               zebra_neigh_show_one(vty, n);
+}
+
+void zebra_neigh_init(void)
+{
+       zneigh_info = XCALLOC(MTYPE_ZNEIGH_INFO, sizeof(*zrouter.neigh_info));
+       RB_INIT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree);
+}
+
+void zebra_neigh_terminate(void)
+{
+       if (!zrouter.neigh_info)
+               return;
+
+       XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
+}
diff --git a/zebra/zebra_neigh.h b/zebra/zebra_neigh.h
new file mode 100644 (file)
index 0000000..953f2e3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Zebra neighbor table management
+ *
+ * Copyright (C) 2021 Nvidia
+ * Anuradha Karuppiah
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ZEBRA_NEIGH_H
+#define _ZEBRA_NEIGH_H
+
+#include <zebra.h>
+
+#include "if.h"
+
+#define zneigh_info zrouter.neigh_info
+
+struct zebra_neigh_ent {
+       ifindex_t ifindex;
+       struct ipaddr ip;
+
+       struct ethaddr mac;
+
+       uint32_t flags;
+#define ZEBRA_NEIGH_ENT_ACTIVE (1 << 0) /* can be used for traffic */
+
+       /* memory used for adding the neigt entry to zneigh_info->es_rb_tree */
+       RB_ENTRY(zebra_neigh_ent) rb_node;
+
+       /* list of pbr rules associated with this neigh */
+       struct list *pbr_rule_list;
+};
+RB_HEAD(zebra_neigh_rb_head, zebra_neigh_ent);
+RB_PROTOTYPE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_es_rb_cmp);
+
+struct zebra_neigh_info {
+       /* RB tree of neighbor entries  */
+       struct zebra_neigh_rb_head neigh_rb_tree;
+};
+
+
+/****************************************************************************/
+extern void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
+                           struct ethaddr *mac);
+extern void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip);
+extern void zebra_neigh_show(struct vty *vty);
+extern void zebra_neigh_init(void);
+extern void zebra_neigh_terminate(void);
+extern void zebra_neigh_deref(struct zebra_pbr_rule *rule);
+extern void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
+                           struct zebra_pbr_rule *rule);
+
+#endif /* _ZEBRA_NEIGH_H */
index 33b8162a8867ee851363900f7aa175c984f24b89..64f0193876e1e4f6735ef567e9b133c052dd9667 100644 (file)
 extern "C" {
 #endif
 
+struct zebra_pbr_action {
+       afi_t afi;
+
+       /* currently only one nexthop is supported */
+       union g_addr gate;
+
+       /* dest-interface */
+       ifindex_t ifindex;
+
+       /* neigh */
+       struct zebra_neigh_ent *neigh;
+       /* zebr_pbr_rule is linked to neigh via neigh_listnode */
+       struct listnode neigh_listnode;
+};
+
 struct zebra_pbr_rule {
        int sock;
 
@@ -43,6 +58,8 @@ struct zebra_pbr_rule {
 
        char ifname[INTERFACE_NAMSIZ];
 
+       struct zebra_pbr_action action;
+
        vrf_id_t vrf_id;
 };
 
index 92d519bad1c354f3f6777373da50a7759c4c3a43..9fccda9e0896aec31f125486a1d46e4287799849 100644 (file)
@@ -29,6 +29,7 @@
 #include "zebra_vxlan.h"
 #include "zebra_mlag.h"
 #include "zebra_nhg.h"
+#include "zebra_neigh.h"
 #include "debug.h"
 #include "zebra_script.h"
 
@@ -242,6 +243,7 @@ void zebra_router_terminate(void)
 
        zebra_vxlan_disable();
        zebra_mlag_terminate();
+       zebra_neigh_terminate();
 
        /* Free NHE in ID table only since it has unhashable entries as well */
        hash_clean(zrouter.nhgs_id, zebra_nhg_hash_free);
@@ -282,6 +284,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
 
        zebra_vxlan_init();
        zebra_mlag_init();
+       zebra_neigh_init();
 
        zrouter.rules_hash = hash_create_size(8, zebra_pbr_rules_hash_key,
                                              zebra_pbr_rules_hash_equal,
index c96c8e5f46c203e3d99b35cc701830cc7f6e22e3..2ae2482487b6206ce3f7503141edf50d19721feb 100644 (file)
@@ -159,6 +159,8 @@ struct zebra_router {
        /* Tables and other global info maintained for EVPN multihoming */
        struct zebra_evpn_mh_info *mh_info;
 
+       struct zebra_neigh_info *neigh_info;
+
        /* EVPN MH broadcast domains indexed by the VID */
        struct hash *evpn_vlan_table;
 
index 011fa2a1e5d466bc4e09f604e16f118dffcf466e..0725d1967743694d7ae625ee0990e7234ccc2f04 100644 (file)
@@ -64,6 +64,7 @@
 #include "zebra/table_manager.h"
 #include "zebra/zebra_script.h"
 #include "zebra/rtadv.h"
+#include "zebra/zebra_neigh.h"
 
 extern int allow_delete;
 
@@ -3005,6 +3006,15 @@ DEFUN (show_evpn_global,
        return CMD_SUCCESS;
 }
 
+DEFPY(show_evpn_neigh, show_neigh_cmd, "show ip neigh",
+      SHOW_STR IP_STR "neighbors\n")
+
+{
+       zebra_neigh_show(vty);
+
+       return CMD_SUCCESS;
+}
+
 DEFPY(show_evpn_l2_nh,
       show_evpn_l2_nh_cmd,
       "show evpn l2-nh [json$json]",
@@ -4529,6 +4539,8 @@ void zebra_vty_init(void)
        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_neigh_cmd);
+
        install_element(VIEW_NODE, &show_pbr_ipset_cmd);
        install_element(VIEW_NODE, &show_pbr_iptable_cmd);
        install_element(VIEW_NODE, &show_route_zebra_dump_cmd);