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));
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",
write++;
}
+ if (IS_ZEBRA_DEBUG_NEIGH) {
+ vty_out(vty, "debug zebra neigh\n");
+ write++;
+ }
+
return write;
}
zebra_debug_nht = 0;
zebra_debug_nexthop = 0;
zebra_debug_pbr = 0;
+ zebra_debug_neigh = 0;
install_node(&debug_node);
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);
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);
#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
} 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));
*/
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)
/* 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)
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */