summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Stapp <mjs@voltanet.io>2021-04-13 14:02:56 +0200
committerGitHub <noreply@github.com>2021-04-13 14:02:56 +0200
commitf3dbd9d3efe7f2d4c0e83bf0890c6dd0eaa6b806 (patch)
tree05b18d72d1927fbcb9c01ea379422f0397eb9186
parentMerge pull request #8389 from idryzhov/route-map-optimization-nb (diff)
parentzebra, lib: replace ZEBRA_ROUTE_NEIGH with simplified version (diff)
downloadfrr-f3dbd9d3efe7f2d4c0e83bf0890c6dd0eaa6b806.tar.xz
frr-f3dbd9d3efe7f2d4c0e83bf0890c6dd0eaa6b806.zip
Merge pull request #8145 from pguibert6WIND/nhrp_use_zebra
nhrp: use zebra
-rw-r--r--lib/log.c10
-rw-r--r--lib/zclient.c71
-rw-r--r--lib/zclient.h33
-rw-r--r--nhrpd/linux.c1
-rw-r--r--nhrpd/netlink_arp.c211
-rw-r--r--nhrpd/nhrp_interface.c1
-rw-r--r--nhrpd/nhrp_peer.c9
-rw-r--r--nhrpd/nhrp_route.c63
-rw-r--r--nhrpd/nhrpd.h8
-rw-r--r--nhrpd/vici.c39
-rw-r--r--nhrpd/zbuf.c2
-rw-r--r--tests/topotests/nhrp-topo/r1/nhrp4_cache.json29
-rw-r--r--tests/topotests/nhrp-topo/r1/nhrp_route4.json25
-rw-r--r--tests/topotests/nhrp-topo/r1/nhrpd.conf10
-rw-r--r--tests/topotests/nhrp-topo/r1/zebra.conf12
-rw-r--r--tests/topotests/nhrp-topo/r2/nhrp4_cache.json29
-rw-r--r--tests/topotests/nhrp-topo/r2/nhrp_route4.json25
-rw-r--r--tests/topotests/nhrp-topo/r2/nhrpd.conf10
-rw-r--r--tests/topotests/nhrp-topo/r2/zebra.conf12
-rw-r--r--tests/topotests/nhrp-topo/r3/zebra.conf11
-rw-r--r--tests/topotests/nhrp-topo/test_nhrp_topo.dot73
-rw-r--r--tests/topotests/nhrp-topo/test_nhrp_topo.py221
-rw-r--r--zebra/interface.c7
-rw-r--r--zebra/kernel_netlink.c3
-rw-r--r--zebra/rt.h10
-rw-r--r--zebra/rt_netlink.c214
-rw-r--r--zebra/rt_socket.c16
-rw-r--r--zebra/zapi_msg.c128
-rw-r--r--zebra/zapi_msg.h3
-rw-r--r--zebra/zebra_dplane.c268
-rw-r--r--zebra/zebra_dplane.h39
-rw-r--r--zebra/zebra_nhg.c3
-rw-r--r--zebra/zebra_rib.c3
-rw-r--r--zebra/zserv.c2
-rw-r--r--zebra/zserv.h3
35 files changed, 1365 insertions, 239 deletions
diff --git a/lib/log.c b/lib/log.c
index e078d8e2a..ca2f50168 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -464,7 +464,15 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST),
DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY),
DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_ADD),
- DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL)};
+ DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_ADDED),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_REGISTER),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER),
+ DESC_ENTRY(ZEBRA_NEIGH_IP_ADD),
+ DESC_ENTRY(ZEBRA_NEIGH_IP_DEL),
+ DESC_ENTRY(ZEBRA_CONFIGURE_ARP)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
diff --git a/lib/zclient.c b/lib/zclient.c
index c78937c1e..d613906d8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -3916,6 +3916,21 @@ static int zclient_read(struct thread *thread)
(*zclient->zebra_client_close_notify)(command, zclient,
length, vrf_id);
break;
+ case ZEBRA_NHRP_NEIGH_ADDED:
+ if (zclient->neighbor_added)
+ (*zclient->neighbor_added)(command, zclient, length,
+ vrf_id);
+ break;
+ case ZEBRA_NHRP_NEIGH_REMOVED:
+ if (zclient->neighbor_removed)
+ (*zclient->neighbor_removed)(command, zclient, length,
+ vrf_id);
+ break;
+ case ZEBRA_NHRP_NEIGH_GET:
+ if (zclient->neighbor_get)
+ (*zclient->neighbor_get)(command, zclient, length,
+ vrf_id);
+ break;
default:
break;
}
@@ -4181,3 +4196,59 @@ char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len)
return buf;
}
+
+static int zclient_neigh_ip_read_entry(struct stream *s, struct ipaddr *add)
+{
+ uint8_t family;
+
+ STREAM_GETC(s, family);
+ if (family != AF_INET && family != AF_INET6)
+ return -1;
+
+ STREAM_GET(&add->ip.addr, s, family2addrsize(family));
+ add->ipa_type = family;
+ return 0;
+ stream_failure:
+ return -1;
+}
+
+int zclient_neigh_ip_encode(struct stream *s,
+ uint16_t cmd,
+ union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp)
+{
+ int ret = 0;
+
+ zclient_create_header(s, cmd, ifp->vrf_id);
+ stream_putc(s, sockunion_family(in));
+ stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in));
+ if (out && sockunion_family(out) != AF_UNSPEC) {
+ stream_putc(s, sockunion_family(out));
+ stream_write(s, sockunion_get_addr(out),
+ sockunion_get_addrlen(out));
+ } else
+ stream_putc(s, AF_UNSPEC);
+ stream_putl(s, ifp->ifindex);
+ if (out)
+ stream_putl(s, ZEBRA_NEIGH_STATE_REACHABLE);
+ else
+ stream_putl(s, ZEBRA_NEIGH_STATE_FAILED);
+ return ret;
+}
+
+int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api)
+{
+ int ret;
+
+ ret = zclient_neigh_ip_read_entry(s, &api->ip_in);
+ if (ret < 0)
+ return -1;
+ zclient_neigh_ip_read_entry(s, &api->ip_out);
+
+ STREAM_GETL(s, api->index);
+ STREAM_GETL(s, api->ndm_state);
+ return 0;
+ stream_failure:
+ return -1;
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index bd952ea1e..90240e40b 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -23,6 +23,7 @@
/* For struct zapi_route. */
#include "prefix.h"
+#include "ipaddr.h"
/* For struct interface and struct connected. */
#include "if.h"
@@ -223,6 +224,14 @@ typedef enum {
ZEBRA_NEIGH_DISCOVER,
ZEBRA_ROUTE_NOTIFY_REQUEST,
ZEBRA_CLIENT_CLOSE_NOTIFY,
+ ZEBRA_NHRP_NEIGH_ADDED,
+ ZEBRA_NHRP_NEIGH_REMOVED,
+ ZEBRA_NHRP_NEIGH_GET,
+ ZEBRA_NHRP_NEIGH_REGISTER,
+ ZEBRA_NHRP_NEIGH_UNREGISTER,
+ ZEBRA_NEIGH_IP_ADD,
+ ZEBRA_NEIGH_IP_DEL,
+ ZEBRA_CONFIGURE_ARP,
} zebra_message_types_t;
enum zebra_error_types {
@@ -381,6 +390,9 @@ struct zclient {
int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS);
int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS);
int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS);
+ void (*neighbor_added)(ZAPI_CALLBACK_ARGS);
+ void (*neighbor_removed)(ZAPI_CALLBACK_ARGS);
+ void (*neighbor_get)(ZAPI_CALLBACK_ARGS);
};
/* Zebra API message flag. */
@@ -794,6 +806,27 @@ struct zclient_options {
extern struct zclient_options zclient_options_default;
+/* link layer representation for GRE like interfaces
+ * ip_in is the underlay IP, ip_out is the tunnel dest
+ * index stands for the index of the interface
+ * ndm state stands for the NDM value in netlink
+ */
+#define ZEBRA_NEIGH_STATE_REACHABLE (0x02)
+#define ZEBRA_NEIGH_STATE_FAILED (0x20)
+struct zapi_neigh_ip {
+ int cmd;
+ struct ipaddr ip_in;
+ struct ipaddr ip_out;
+ ifindex_t index;
+ uint32_t ndm_state;
+};
+int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api);
+int zclient_neigh_ip_encode(struct stream *s,
+ uint16_t cmd,
+ union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp);
+
/*
* We reserve the top 4 bits for l2-NHG, everything else
* is for zebra/proto l3-NHG.
diff --git a/nhrpd/linux.c b/nhrpd/linux.c
index 59c82b1c5..9cabdbf06 100644
--- a/nhrpd/linux.c
+++ b/nhrpd/linux.c
@@ -154,7 +154,6 @@ int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af)
break;
}
ret |= linux_configure_arp(ifname, 1);
- ret |= netlink_configure_arp(ifindex, af);
return ret;
}
diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c
index dc4697cda..ecea0a9ec 100644
--- a/nhrpd/netlink_arp.c
+++ b/nhrpd/netlink_arp.c
@@ -19,6 +19,8 @@
#include <linux/netfilter/nfnetlink_log.h>
#include "thread.h"
+#include "stream.h"
+#include "prefix.h"
#include "nhrpd.h"
#include "netlink.h"
#include "znl.h"
@@ -27,129 +29,11 @@ int netlink_req_fd = -1;
int netlink_nflog_group;
static int netlink_log_fd = -1;
static struct thread *netlink_log_thread;
-static int netlink_listen_fd = -1;
-
-typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb);
void netlink_update_binding(struct interface *ifp, union sockunion *proto,
union sockunion *nbma)
{
- struct nlmsghdr *n;
- struct ndmsg *ndm;
- struct zbuf *zb = zbuf_alloc(512);
-
- n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH,
- NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
- ndm = znl_push(zb, sizeof(*ndm));
- *ndm = (struct ndmsg){
- .ndm_family = sockunion_family(proto),
- .ndm_ifindex = ifp->ifindex,
- .ndm_type = RTN_UNICAST,
- .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED,
- };
- znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto),
- family2addrsize(sockunion_family(proto)));
- if (nbma)
- znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma),
- family2addrsize(sockunion_family(nbma)));
- znl_nlmsg_complete(zb, n);
- zbuf_send(zb, netlink_req_fd);
- zbuf_recv(zb, netlink_req_fd);
- zbuf_free(zb);
-}
-
-static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb)
-{
- struct ndmsg *ndm;
- struct rtattr *rta;
- struct nhrp_cache *c;
- struct interface *ifp;
- struct zbuf payload;
- union sockunion addr, lladdr;
- size_t len;
- int state;
-
- memset(&lladdr, 0, sizeof(lladdr));
- ndm = znl_pull(zb, sizeof(*ndm));
- if (!ndm)
- return;
-
- sockunion_family(&addr) = AF_UNSPEC;
- while ((rta = znl_rta_pull(zb, &payload)) != NULL) {
- len = zbuf_used(&payload);
- switch (rta->rta_type) {
- case NDA_DST:
- sockunion_set(&addr, ndm->ndm_family,
- zbuf_pulln(&payload, len), len);
- break;
- case NDA_LLADDR:
- sockunion_set(&lladdr, ndm->ndm_family,
- zbuf_pulln(&payload, len), len);
- break;
- }
- }
-
- ifp = if_lookup_by_index(ndm->ndm_ifindex, VRF_DEFAULT);
- if (!ifp || sockunion_family(&addr) == AF_UNSPEC)
- return;
-
- c = nhrp_cache_get(ifp, &addr, 0);
- if (!c)
- return;
-
- debugf(NHRP_DEBUG_KERNEL,
- "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
- (msg->nlmsg_type == RTM_GETNEIGH)
- ? "who-has"
- : (msg->nlmsg_type == RTM_NEWNEIGH) ? "new-neigh"
- : "del-neigh",
- &addr, ifp->name, &lladdr, ndm->ndm_state, c->used, c->cur.type);
-
- if (msg->nlmsg_type == RTM_GETNEIGH) {
- if (c->cur.type >= NHRP_CACHE_CACHED) {
- nhrp_cache_set_used(c, 1);
- debugf(NHRP_DEBUG_KERNEL,
- "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
- &addr, ifp->name, &c->cur.remote_nbma_natoa,
- &c->cur.peer->vc->remote.nbma, &lladdr);
- /* In case of shortcuts, nbma is given by lladdr, not
- * vc->remote.nbma.
- */
- netlink_update_binding(ifp, &addr, &lladdr);
- }
- } else {
- state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state
- : NUD_FAILED;
- nhrp_cache_set_used(c, state == NUD_REACHABLE);
- }
-}
-
-static int netlink_route_recv(struct thread *t)
-{
- uint8_t buf[ZNL_BUFFER_SIZE];
- int fd = THREAD_FD(t);
- struct zbuf payload, zb;
- struct nlmsghdr *n;
-
- zbuf_init(&zb, buf, sizeof(buf), 0);
- while (zbuf_recv(&zb, fd) > 0) {
- while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
- debugf(NHRP_DEBUG_KERNEL,
- "Netlink: Received msg_type %u, msg_flags %u",
- n->nlmsg_type, n->nlmsg_flags);
- switch (n->nlmsg_type) {
- case RTM_GETNEIGH:
- case RTM_NEWNEIGH:
- case RTM_DELNEIGH:
- netlink_neigh_msg(n, &payload);
- break;
- }
- }
- }
-
- thread_add_read(master, netlink_route_recv, 0, fd, NULL);
-
- return 0;
+ nhrp_send_zebra_nbr(proto, nbma, ifp);
}
static void netlink_log_register(int fd, int group)
@@ -265,47 +149,64 @@ void netlink_set_nflog_group(int nlgroup)
}
}
-void netlink_init(void)
+void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
{
- netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
- if (netlink_req_fd < 0)
- return;
+ union sockunion addr = {}, lladdr = {};
+ struct interface *ifp;
+ int state, ndm_state;
+ struct nhrp_cache *c;
+ struct zapi_neigh_ip api = {};
- netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH);
- if (netlink_listen_fd < 0)
+ zclient_neigh_ip_decode(zclient->ibuf, &api);
+ if (api.ip_in.ipa_type == AF_UNSPEC)
return;
+ sockunion_family(&addr) = api.ip_in.ipa_type;
+ memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr,
+ family2addrsize(api.ip_in.ipa_type));
- thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd, NULL);
-}
+ sockunion_family(&lladdr) = api.ip_out.ipa_type;
+ if (api.ip_out.ipa_type != AF_UNSPEC)
+ memcpy((uint8_t *)sockunion_get_addr(&lladdr),
+ &api.ip_out.ip.addr,
+ family2addrsize(api.ip_out.ipa_type));
-int netlink_configure_arp(unsigned int ifindex, int pf)
-{
- struct nlmsghdr *n;
- struct ndtmsg *ndtm;
- struct rtattr *rta;
- struct zbuf *zb = zbuf_alloc(512);
- int r;
-
- n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE);
- ndtm = znl_push(zb, sizeof(*ndtm));
- *ndtm = (struct ndtmsg){
- .ndtm_family = pf,
- };
+ ifp = if_lookup_by_index(api.index, vrf_id);
+ ndm_state = api.ndm_state;
- znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache",
- 10);
-
- rta = znl_rta_nested_push(zb, NDTA_PARMS);
- znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex);
- znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1);
- znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0);
- znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0);
- znl_rta_nested_complete(zb, rta);
-
- znl_nlmsg_complete(zb, n);
- r = zbuf_send(zb, netlink_req_fd);
- zbuf_recv(zb, netlink_req_fd);
- zbuf_free(zb);
+ if (!ifp)
+ return;
+ c = nhrp_cache_get(ifp, &addr, 0);
+ if (!c)
+ return;
+ debugf(NHRP_DEBUG_KERNEL,
+ "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
+ (cmd == ZEBRA_NHRP_NEIGH_GET)
+ ? "who-has"
+ : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh"
+ : "del-neigh",
+ &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type);
+ if (cmd == ZEBRA_NHRP_NEIGH_GET) {
+ if (c->cur.type >= NHRP_CACHE_CACHED) {
+ nhrp_cache_set_used(c, 1);
+ debugf(NHRP_DEBUG_KERNEL,
+ "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
+ &addr, ifp->name, &c->cur.remote_nbma_natoa,
+ &c->cur.peer->vc->remote.nbma, &lladdr);
+ /* In case of shortcuts, nbma is given by lladdr, not
+ * vc->remote.nbma.
+ */
+ netlink_update_binding(ifp, &addr, &lladdr);
+ }
+ } else {
+ state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state
+ : ZEBRA_NEIGH_STATE_FAILED;
+ nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE);
+ }
+}
- return r;
+void netlink_init(void)
+{
+ netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
+ if (netlink_req_fd < 0)
+ return;
}
diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c
index a6880054f..f6d89b141 100644
--- a/nhrpd/nhrp_interface.c
+++ b/nhrpd/nhrp_interface.c
@@ -298,6 +298,7 @@ void nhrp_interface_update(struct interface *ifp)
if (!if_ad->configured) {
os_configure_dmvpn(ifp->ifindex, ifp->name,
afi2family(afi));
+ nhrp_send_zebra_configure_arp(ifp, afi2family(afi));
if_ad->configured = 1;
nhrp_interface_update_address(ifp, afi, 1);
}
diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c
index c1f615d0a..a44190d29 100644
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
@@ -192,10 +192,10 @@ static void *nhrp_peer_create(void *data)
return p;
}
-static void do_peer_hash_free(struct hash_bucket *hb,
- void *arg __attribute__((__unused__)))
+static void do_peer_hash_free(void *hb_data)
{
- struct nhrp_peer *p = hb->data;
+ struct nhrp_peer *p = (struct nhrp_peer *)hb_data;
+
nhrp_peer_check_delete(p);
}
@@ -207,9 +207,10 @@ void nhrp_peer_interface_del(struct interface *ifp)
nifp->peer_hash ? nifp->peer_hash->count : 0);
if (nifp->peer_hash) {
- hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL);
+ hash_clean(nifp->peer_hash, do_peer_hash_free);
assert(nifp->peer_hash->count == 0);
hash_free(nifp->peer_hash);
+ nifp->peer_hash = NULL;
}
}
diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c
index 7a4c57b5d..23fa0771e 100644
--- a/nhrpd/nhrp_route.c
+++ b/nhrpd/nhrp_route.c
@@ -79,6 +79,24 @@ static void nhrp_route_update_zebra(const struct prefix *p,
}
}
+static void nhrp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, reg ? ZEBRA_NHRP_NEIGH_REGISTER :
+ ZEBRA_NHRP_NEIGH_UNREGISTER,
+ vrf_id);
+ stream_putw(s, afi);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(zclient);
+}
+
void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp)
{
struct route_node *rn;
@@ -344,6 +362,8 @@ static void nhrp_zebra_connected(struct zclient *zclient)
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true);
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true);
}
void nhrp_zebra_init(void)
@@ -357,7 +377,9 @@ void nhrp_zebra_init(void)
zclient->interface_address_delete = nhrp_interface_address_delete;
zclient->redistribute_route_add = nhrp_route_read;
zclient->redistribute_route_del = nhrp_route_read;
-
+ zclient->neighbor_added = nhrp_neighbor_operation;
+ zclient->neighbor_removed = nhrp_neighbor_operation;
+ zclient->neighbor_get = nhrp_neighbor_operation;
zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
}
@@ -370,8 +392,47 @@ static void nhrp_table_node_cleanup(struct route_table *table,
XFREE(MTYPE_NHRP_ROUTE, node->info);
}
+void nhrp_send_zebra_configure_arp(struct interface *ifp, int family)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0) {
+ debugf(NHRP_DEBUG_COMMON, "%s() : zclient not ready",
+ __func__);
+ return;
+ }
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s,
+ ZEBRA_CONFIGURE_ARP,
+ ifp->vrf_id);
+ stream_putc(s, family);
+ stream_putl(s, ifp->ifindex);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(zclient);
+}
+
+void nhrp_send_zebra_nbr(union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0)
+ return;
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD :
+ ZEBRA_NEIGH_IP_DEL, in, out,
+ ifp);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(zclient);
+}
+
void nhrp_zebra_terminate(void)
{
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false);
zclient_stop(zclient);
zclient_free(zclient);
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index e4afb22f8..136f855df 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -88,7 +88,12 @@ static inline int notifier_active(struct notifier_list *l)
void nhrp_zebra_init(void);
void nhrp_zebra_terminate(void);
-
+void nhrp_send_zebra_configure_arp(struct interface *ifp, int family);
+void nhrp_send_zebra_nbr(union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp);
+void nhrp_send_zebra_configure_arp(struct interface *ifp,
+ int family);
struct zbuf;
struct nhrp_vc;
struct nhrp_cache;
@@ -326,6 +331,7 @@ int nhrp_interface_up(ZAPI_CALLBACK_ARGS);
int nhrp_interface_down(ZAPI_CALLBACK_ARGS);
int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS);
int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
+void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS);
void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n,
notifier_fn_t fn);
diff --git a/nhrpd/vici.c b/nhrpd/vici.c
index 9b117ddf0..c21e01601 100644
--- a/nhrpd/vici.c
+++ b/nhrpd/vici.c
@@ -470,10 +470,44 @@ static void vici_register_event(struct vici_conn *vici, const char *name)
vici_submit(vici, obuf);
}
+static bool vici_charon_filepath_done;
+static bool vici_charon_not_found;
+
+static char *vici_get_charon_filepath(void)
+{
+ static char buff[1200];
+ FILE *fp;
+ char *ptr;
+ char line[1024];
+
+ if (vici_charon_filepath_done)
+ return (char *)buff;
+ fp = popen("ipsec --piddir", "r");
+ if (!fp) {
+ if (!vici_charon_not_found) {
+ flog_err(EC_NHRP_SWAN,
+ "VICI: Failed to retrieve charon file path");
+ vici_charon_not_found = true;
+ }
+ return NULL;
+ }
+ /* last line of output is used to get vici path */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ ptr = strchr(line, '\n');
+ if (ptr)
+ *ptr = '\0';
+ snprintf(buff, sizeof(buff), "%s/charon.vici", line);
+ }
+ pclose(fp);
+ vici_charon_filepath_done = true;
+ return buff;
+}
+
static int vici_reconnect(struct thread *t)
{
struct vici_conn *vici = THREAD_ARG(t);
int fd;
+ char *file_path;
vici->t_reconnect = NULL;
if (vici->fd >= 0)
@@ -481,6 +515,11 @@ static int vici_reconnect(struct thread *t)
fd = sock_open_unix(VICI_SOCKET);
if (fd < 0) {
+ file_path = vici_get_charon_filepath();
+ if (file_path)
+ fd = sock_open_unix(file_path);
+ }
+ if (fd < 0) {
debugf(NHRP_DEBUG_VICI,
"%s: failure connecting VICI socket: %s", __func__,
strerror(errno));
diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c
index a23526af4..43ce97481 100644
--- a/nhrpd/zbuf.c
+++ b/nhrpd/zbuf.c
@@ -27,7 +27,7 @@ struct zbuf *zbuf_alloc(size_t size)
{
struct zbuf *zb;
- zb = XMALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size);
+ zb = XCALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size);
zbuf_init(zb, zb + 1, size, 0);
zb->allocated = 1;
diff --git a/tests/topotests/nhrp-topo/r1/nhrp4_cache.json b/tests/topotests/nhrp-topo/r1/nhrp4_cache.json
new file mode 100644
index 000000000..6426a939b
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r1/nhrp4_cache.json
@@ -0,0 +1,29 @@
+{
+ "attr":{
+ "entriesCount":2
+ },
+ "table":[
+ {
+ "interface":"r1-gre0",
+ "type":"nhs",
+ "protocol":"10.255.255.2",
+ "nbma":"10.2.1.2",
+ "claimed_nbma":"10.2.1.2",
+ "used":false,
+ "timeout":true,
+ "auth":false,
+ "identity":""
+ },
+ {
+ "interface":"r1-gre0",
+ "type":"local",
+ "protocol":"10.255.255.1",
+ "nbma":"10.1.1.1",
+ "claimed_nbma":"10.1.1.1",
+ "used":false,
+ "timeout":false,
+ "auth":false,
+ "identity":"-"
+ }
+ ]
+}
diff --git a/tests/topotests/nhrp-topo/r1/nhrp_route4.json b/tests/topotests/nhrp-topo/r1/nhrp_route4.json
new file mode 100644
index 000000000..68b5a6ece
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r1/nhrp_route4.json
@@ -0,0 +1,25 @@
+{
+ "10.255.255.2\/32":[
+ {
+ "prefix":"10.255.255.2\/32",
+ "protocol":"nhrp",
+ "vrfId":0,
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":10,
+ "metric":0,
+ "installed":true,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-gre0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/nhrp-topo/r1/nhrpd.conf b/tests/topotests/nhrp-topo/r1/nhrpd.conf
new file mode 100644
index 000000000..04114bdbe
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r1/nhrpd.conf
@@ -0,0 +1,10 @@
+log stdout debugging
+debug nhrp all
+interface r1-gre0
+ ip nhrp holdtime 500
+ ip nhrp shortcut
+ ip nhrp network-id 42
+ ip nhrp nhs dynamic nbma 10.2.1.2
+ ip nhrp registration no-unique
+ tunnel source r1-eth0
+exit
diff --git a/tests/topotests/nhrp-topo/r1/zebra.conf b/tests/topotests/nhrp-topo/r1/zebra.conf
new file mode 100644
index 000000000..b45670fcb
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r1/zebra.conf
@@ -0,0 +1,12 @@
+interface r1-eth0
+ ip address 10.1.1.1/24
+!
+ip route 10.2.1.0/24 10.1.1.3
+interface r1-gre0
+ ip address 10.255.255.1/32
+ no link-detect
+ ipv6 nd suppress-ra
+exit
+interface r1-eth1
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/nhrp-topo/r2/nhrp4_cache.json b/tests/topotests/nhrp-topo/r2/nhrp4_cache.json
new file mode 100644
index 000000000..34558e0c2
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r2/nhrp4_cache.json
@@ -0,0 +1,29 @@
+{
+ "attr":{
+ "entriesCount":2
+ },
+ "table":[
+ {
+ "interface":"r2-gre0",
+ "type":"local",
+ "protocol":"10.255.255.2",
+ "nbma":"10.2.1.2",
+ "claimed_nbma":"10.2.1.2",
+ "used":false,
+ "timeout":false,
+ "auth":false,
+ "identity":"-"
+ },
+ {
+ "interface":"r2-gre0",
+ "type":"dynamic",
+ "protocol":"10.255.255.1",
+ "nbma":"10.1.1.1",
+ "claimed_nbma":"10.1.1.1",
+ "used":false,
+ "timeout":true,
+ "auth":false,
+ "identity":""
+ }
+ ]
+}
diff --git a/tests/topotests/nhrp-topo/r2/nhrp_route4.json b/tests/topotests/nhrp-topo/r2/nhrp_route4.json
new file mode 100644
index 000000000..7393cba89
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r2/nhrp_route4.json
@@ -0,0 +1,25 @@
+{
+ "10.255.255.1\/32":[
+ {
+ "prefix":"10.255.255.1\/32",
+ "protocol":"nhrp",
+ "vrfId":0,
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":10,
+ "metric":0,
+ "installed":true,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r2-gre0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/nhrp-topo/r2/nhrpd.conf b/tests/topotests/nhrp-topo/r2/nhrpd.conf
new file mode 100644
index 000000000..e4f6fb744
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r2/nhrpd.conf
@@ -0,0 +1,10 @@
+debug nhrp all
+log stdout debugging
+nhrp nflog-group 1
+interface r2-gre0
+ ip nhrp holdtime 500
+ ip nhrp redirect
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ tunnel source r2-eth0
+exit
diff --git a/tests/topotests/nhrp-topo/r2/zebra.conf b/tests/topotests/nhrp-topo/r2/zebra.conf
new file mode 100644
index 000000000..9f40d4d72
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r2/zebra.conf
@@ -0,0 +1,12 @@
+interface r2-eth0
+ ip address 10.2.1.2/24
+!
+ip route 10.1.1.0/24 10.2.1.3
+interface r2-gre0
+ ip address 10.255.255.2/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/nhrp-topo/r3/zebra.conf b/tests/topotests/nhrp-topo/r3/zebra.conf
new file mode 100644
index 000000000..6d3d26797
--- /dev/null
+++ b/tests/topotests/nhrp-topo/r3/zebra.conf
@@ -0,0 +1,11 @@
+debug zebra kernel
+debug zebra rib
+debug zebra events
+debug zebra packet
+ip forwarding
+interface r3-eth0
+ ip address 10.1.1.3/24
+!
+interface r3-eth1
+ ip address 10.2.1.3/24
+exit
diff --git a/tests/topotests/nhrp-topo/test_nhrp_topo.dot b/tests/topotests/nhrp-topo/test_nhrp_topo.dot
new file mode 100644
index 000000000..6b68fb398
--- /dev/null
+++ b/tests/topotests/nhrp-topo/test_nhrp_topo.dot
@@ -0,0 +1,73 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n2001:db8:4::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0"];
+ r2 -- sw1 [label="eth0"];
+
+ r2 -- sw2 [label="eth1"];
+ r3 -- sw2 [label="eth0"];
+
+ r2 -- sw3 [label="eth2"];
+ r4 -- sw3 [label="eth0"];
+}
diff --git a/tests/topotests/nhrp-topo/test_nhrp_topo.py b/tests/topotests/nhrp-topo/test_nhrp_topo.py
new file mode 100644
index 000000000..1687961f3
--- /dev/null
+++ b/tests/topotests/nhrp-topo/test_nhrp_topo.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+
+#
+# test_nhrp_topo.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_nhrp_topo.py: Test the FRR/Quagga NHRP daemon
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class NHRPTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 3 routers.
+ for routern in range(1, 4):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r3'])
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r3'])
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r2'])
+ switch = tgen.add_switch('s4')
+ switch.add_link(tgen.gears['r1'])
+
+
+def _populate_iface():
+ tgen = get_topogen()
+ cmds_tot_hub = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.2.1.{1} remote 0.0.0.0',
+ 'ip link set dev {0}-gre0 up',
+ 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6']
+
+ cmds_tot = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.1.1.{1} remote 0.0.0.0',
+ 'ip link set dev {0}-gre0 up',
+ 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6']
+
+ for cmd in cmds_tot_hub:
+ input = cmd.format('r2', '2')
+ logger.info('input: '+cmd)
+ output = tgen.net['r2'].cmd(cmd.format('r2', '2'))
+ logger.info('output: '+output);
+
+ for cmd in cmds_tot:
+ input = cmd.format('r1', '1')
+ logger.info('input: '+cmd)
+ output = tgen.net['r1'].cmd(cmd.format('r1', '1'))
+ logger.info('output: '+output);
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(NHRPTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ _populate_iface()
+
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+ )
+ if rname in ('r1', 'r2'):
+ router.load_config(
+ TopoRouter.RD_NHRP,
+ os.path.join(CWD, '{}/nhrpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ logger.info('Launching BGP, NHRP')
+ for name in router_list:
+ router = tgen.gears[name]
+ router.start()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged before checking for the NHRP
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 routing tables.
+ logger.info("Checking NHRP cache and IPv4 routes for convergence")
+ router_list = tgen.routers()
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r3':
+ continue
+
+ json_file = '{}/{}/nhrp4_cache.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip nhrp cache json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=40,
+ wait=0.5)
+
+ output = router.vtysh_cmd('show ip nhrp cache')
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r3':
+ continue
+
+ json_file = '{}/{}/nhrp_route4.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip route nhrp json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=40,
+ wait=0.5)
+
+ output = router.vtysh_cmd('show ip route nhrp')
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r3':
+ continue
+ logger.info('Dump neighbor information on {}-gre0'.format(rname))
+ output = router.run('ip neigh show')
+ logger.info(output)
+
+
+def test_nhrp_connection():
+ "Assert that the NHRP peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pingrouter = tgen.gears['r1']
+ logger.info('Check Ping IPv4 from R1 to R2 = 10.255.255.2)')
+ output = pingrouter.run('ping 10.255.255.2 -f -c 1000')
+ logger.info(output)
+ if '1000 packets transmitted, 1000 received' not in output:
+ assertmsg = 'expected ping IPv4 from R1 to R2 should be ok'
+ assert 0, assertmsg
+ else:
+ logger.info('Check Ping IPv4 from R1 to R2 OK')
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/zebra/interface.c b/zebra/interface.c
index 3eeed9ac9..4b708496a 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -898,7 +898,8 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp,
* Remove and re-add any existing neighbor entry for this address,
* since Netlink doesn't currently offer update message types.
*/
- kernel_neigh_update(0, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id);
+ kernel_neigh_update(0, ifp->ifindex, (void *)&ipv4_ll.s_addr, mac, 6,
+ ns_id, AF_INET, true);
/* Add new neighbor entry.
*
@@ -910,8 +911,8 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp,
* they'll be useless to us.
*/
if (add)
- kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6,
- ns_id);
+ kernel_neigh_update(add, ifp->ifindex, (void *)&ipv4_ll.s_addr,
+ mac, 6, ns_id, AF_INET, true);
memcpy(&zif->neigh_mac[0], &mac[0], 6);
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index e71e66245..adb61023c 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -1335,6 +1335,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
return netlink_put_neigh_update_msg(bth, ctx);
case DPLANE_OP_RULE_ADD:
diff --git a/zebra/rt.h b/zebra/rt.h
index 48f1df286..daaa926a7 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -68,8 +68,11 @@ kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx);
#endif /* !HAVE_NETLINK */
-extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id);
+extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla,
+ int llalen, ns_id_t ns_id, uint8_t family,
+ bool permanent);
+extern int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client,
+ bool reg);
extern int kernel_interface_set_master(struct interface *master,
struct interface *slave);
@@ -78,6 +81,9 @@ extern int mpls_kernel_init(void);
extern uint32_t kernel_get_speed(struct interface *ifp, int *error);
extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute);
+extern int kernel_configure_if_link(struct interface *ifp,
+ struct interface *link_ifp, ns_id_t ns_id);
+
/*
* Southbound Initialization routines to get initial starting
* state.
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 55e0775a8..d2ec7da57 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -185,6 +185,10 @@ static uint16_t neigh_state_to_netlink(uint16_t dplane_state)
state |= NUD_PROBE;
if (dplane_state & DPLANE_NUD_INCOMPLETE)
state |= NUD_INCOMPLETE;
+ if (dplane_state & DPLANE_NUD_PERMANENT)
+ state |= NUD_PERMANENT;
+ if (dplane_state & DPLANE_NUD_FAILED)
+ state |= NUD_FAILED;
return state;
}
@@ -1537,10 +1541,10 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
routedesc, nl_msg_type_to_str(cmd), label);
}
-static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id)
+static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla,
+ int llalen, ns_id_t ns_id, uint8_t family,
+ bool permanent, uint8_t protocol)
{
- uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
@@ -1556,15 +1560,24 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH
req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
- req.ndm.ndm_family = AF_INET;
- req.ndm.ndm_state = NUD_PERMANENT;
+ req.ndm.ndm_family = family;
req.ndm.ndm_ifindex = ifindex;
req.ndm.ndm_type = RTN_UNICAST;
+ if (cmd == RTM_NEWNEIGH) {
+ if (!permanent)
+ req.ndm.ndm_state = NUD_REACHABLE;
+ else
+ req.ndm.ndm_state = NUD_PERMANENT;
+ } else
+ req.ndm.ndm_state = NUD_FAILED;
nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol,
sizeof(protocol));
- nl_attr_put32(&req.n, sizeof(req), NDA_DST, addr);
- nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
+ req.ndm.ndm_type = RTN_UNICAST;
+ nl_attr_put(&req.n, sizeof(req), NDA_DST, addr,
+ family2addrsize(family));
+ if (lla)
+ nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
0);
@@ -2679,11 +2692,12 @@ int netlink_nexthop_read(struct zebra_ns *zns)
}
-int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id)
+int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
+ ns_id_t ns_id, uint8_t family, bool permanent)
{
return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex,
- addr, lla, llalen, ns_id);
+ addr, lla, llalen, ns_id, family, permanent,
+ RTPROT_ZEBRA);
}
/**
@@ -2694,7 +2708,9 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
* entry.
* @ctx: Dataplane context
* @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
- * @mac: A neighbor cache link layer address
+ * @lla: A pointer to neighbor cache link layer address
+ * @llalen: Length of the pointer to neighbor cache link layer
+ * address
* @ip: A neighbor cache n/w layer destination address
* In the case of bridge FDB, this represnts the remote
* VTEP IP.
@@ -2706,18 +2722,18 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
* @state: NUD_* states
* @data: data buffer pointer
* @datalen: total amount of data buffer space
+ * @protocol: protocol information
*
* Return: 0 when the msg doesn't fit entirely in the buffer
* otherwise the number of bytes written to buf.
*/
static ssize_t netlink_neigh_update_msg_encode(
- const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac,
- const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type,
- uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
+ const struct zebra_dplane_ctx *ctx, int cmd, const void *lla,
+ int llalen, const struct ipaddr *ip, bool replace_obj, uint8_t family,
+ uint8_t type, uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
uint8_t nfy_flags, bool ext, uint32_t ext_flags, void *data,
- size_t datalen)
+ size_t datalen, uint8_t protocol)
{
- uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
@@ -2749,8 +2765,8 @@ static ssize_t netlink_neigh_update_msg_encode(
sizeof(protocol)))
return 0;
- if (mac) {
- if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6))
+ if (lla) {
+ if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, lla, llalen))
return 0;
}
@@ -2814,12 +2830,17 @@ netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd,
void *buf, size_t buflen)
{
struct ethaddr dst_mac = {.octet = {0}};
+ int proto = RTPROT_ZEBRA;
+
+ if (dplane_ctx_get_type(ctx) != 0)
+ proto = zebra2proto(dplane_ctx_get_type(ctx));
return netlink_neigh_update_msg_encode(
- ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
- PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/,
- false /*nfy*/, 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/,
- buf, buflen);
+ ctx, cmd, (const void *)&dst_mac, ETH_ALEN,
+ dplane_ctx_neigh_get_ipaddr(ctx), false, PF_BRIDGE, 0, NTF_SELF,
+ (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, false /*nfy*/,
+ 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/, buf, buflen,
+ proto);
}
#ifndef NDA_RTA
@@ -3185,6 +3206,10 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
uint32_t update_flags;
bool nfy = false;
uint8_t nfy_flags = 0;
+ int proto = RTPROT_ZEBRA;
+
+ if (dplane_ctx_get_type(ctx) != 0)
+ proto = zebra2proto(dplane_ctx_get_type(ctx));
cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
? RTM_NEWNEIGH : RTM_DELNEIGH;
@@ -3251,9 +3276,10 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
}
total = netlink_neigh_update_msg_encode(
- ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true,
- AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags,
- false /*ext*/, 0 /*ext_flags*/, data, datalen);
+ ctx, cmd, (const void *)dplane_ctx_mac_get_addr(ctx), ETH_ALEN,
+ &vtep_ip, true, AF_BRIDGE, 0, flags, state, nhg_id, nfy,
+ nfy_flags, false /*ext*/, 0 /*ext_flags*/, data, datalen,
+ proto);
return total;
}
@@ -3307,6 +3333,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
bool local_inactive;
uint32_t ext_flags = 0;
bool dp_static = false;
+ int l2_len = 0;
+ int cmd;
ndm = NLMSG_DATA(h);
@@ -3348,6 +3376,43 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID))
netlink_handle_5549(ndm, zif, ifp, &ip, true);
+ /* we send link layer information to client:
+ * - nlmsg_type = RTM_DELNEIGH|NEWNEIGH|GETNEIGH
+ * - struct ipaddr ( for DEL and GET)
+ * - struct ethaddr mac; (for NEW)
+ */
+ if (h->nlmsg_type == RTM_NEWNEIGH)
+ cmd = ZEBRA_NHRP_NEIGH_ADDED;
+ else if (h->nlmsg_type == RTM_GETNEIGH)
+ cmd = ZEBRA_NHRP_NEIGH_GET;
+ else if (h->nlmsg_type == RTM_DELNEIGH)
+ cmd = ZEBRA_NHRP_NEIGH_REMOVED;
+ else {
+ zlog_debug("%s(): unknown nlmsg type %u", __func__,
+ h->nlmsg_type);
+ return 0;
+ }
+ if (tb[NDA_LLADDR]) {
+ /* copy LLADDR information */
+ l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
+ memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), l2_len);
+ }
+ if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) {
+ union sockunion link_layer_ipv4;
+
+ if (l2_len) {
+ sockunion_family(&link_layer_ipv4) = AF_INET;
+ memcpy((void *)sockunion_get_addr(&link_layer_ipv4),
+ &mac, l2_len);
+ } else
+ sockunion_family(&link_layer_ipv4) = AF_UNSPEC;
+ zsend_nhrp_neighbor_notify(cmd, ifp, &ip, ndm->ndm_state,
+ &link_layer_ipv4);
+ }
+
+ if (h->nlmsg_type == RTM_GETNEIGH)
+ return 0;
+
/* The neighbor is present on an SVI. From this, we locate the
* underlying
* bridge because we're only interested in neighbors on a VxLAN bridge.
@@ -3615,7 +3680,8 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
int len;
struct ndmsg *ndm;
- if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH))
+ if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH
+ || h->nlmsg_type == RTM_GETNEIGH))
return 0;
/* Length validity. */
@@ -3656,19 +3722,42 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
int cmd, void *buf, size_t buflen)
{
const struct ipaddr *ip;
- const struct ethaddr *mac;
+ const struct ethaddr *mac = NULL;
+ const struct ipaddr *link_ip = NULL;
+ const void *link_ptr = NULL;
+ char buf2[ETHER_ADDR_STRLEN];
+
+ int llalen;
uint8_t flags;
uint16_t state;
uint8_t family;
uint32_t update_flags;
uint32_t ext_flags = 0;
bool ext = false;
+ int proto = RTPROT_ZEBRA;
+
+ if (dplane_ctx_get_type(ctx) != 0)
+ proto = zebra2proto(dplane_ctx_get_type(ctx));
ip = dplane_ctx_neigh_get_ipaddr(ctx);
- mac = dplane_ctx_neigh_get_mac(ctx);
- if (is_zero_mac(mac))
- mac = NULL;
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_INSTALL
+ || dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_DELETE) {
+ link_ip = dplane_ctx_neigh_get_link_ip(ctx);
+ llalen = IPADDRSZ(link_ip);
+ link_ptr = (const void *)&(link_ip->ip.addr);
+ ipaddr2str(link_ip, buf2, sizeof(buf2));
+ } else {
+ mac = dplane_ctx_neigh_get_mac(ctx);
+ llalen = ETH_ALEN;
+ link_ptr = (const void *)mac;
+ if (is_zero_mac(mac))
+ mac = NULL;
+ if (mac)
+ prefix_mac2str(mac, buf2, sizeof(buf2));
+ else
+ snprintf(buf2, sizeof(buf2), "null");
+ }
update_flags = dplane_ctx_neigh_get_update_flags(ctx);
flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
@@ -3682,7 +3771,7 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
*/
if (update_flags & DPLANE_NEIGH_WAS_STATIC)
ext = true;
- } else {
+ } else if (!(update_flags & DPLANE_NEIGH_NO_EXTENSION)) {
ext = true;
/* local neigh */
if (update_flags & DPLANE_NEIGH_SET_STATIC)
@@ -3690,15 +3779,63 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Tx %s family %s IF %s(%u) Neigh %pIA MAC %pEA flags 0x%x state 0x%x %sext_flags 0x%x",
+ "Tx %s family %s IF %s(%u) Neigh %pIA %s %s flags 0x%x state 0x%x %sext_flags 0x%x",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
- ip, mac, flags, state, ext ? "ext " : "", ext_flags);
+ ip, link_ip ? "Link " : "MAC ", buf2, flags, state,
+ ext ? "ext " : "", ext_flags);
return netlink_neigh_update_msg_encode(
- ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state,
- 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext, ext_flags, buf,
- buflen);
+ ctx, cmd, link_ptr, llalen, ip, true, family, RTN_UNICAST,
+ flags, state, 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext,
+ ext_flags, buf, buflen, proto);
+}
+
+static int netlink_neigh_table_update_ctx(const struct zebra_dplane_ctx *ctx,
+ void *data, size_t datalen)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ndtmsg ndtm;
+ char buf[];
+ } *req = data;
+ struct rtattr *nest;
+ uint8_t family;
+ ifindex_t idx;
+ uint32_t val;
+
+ if (datalen < sizeof(*req))
+ return 0;
+ memset(req, 0, sizeof(*req));
+ family = dplane_ctx_neightable_get_family(ctx);
+ idx = dplane_ctx_get_ifindex(ctx);
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE;
+ req->n.nlmsg_type = RTM_SETNEIGHTBL;
+ req->ndtm.ndtm_family = family;
+
+ nl_attr_put(&req->n, datalen, NDTA_NAME,
+ family == AF_INET ? "arp_cache" : "ndisc_cache", 10);
+ nest = nl_attr_nest(&req->n, datalen, NDTA_PARMS);
+ if (nest == NULL)
+ return 0;
+ if (!nl_attr_put(&req->n, datalen, NDTPA_IFINDEX, &idx, sizeof(idx)))
+ return 0;
+ val = dplane_ctx_neightable_get_app_probes(ctx);
+ if (!nl_attr_put(&req->n, datalen, NDTPA_APP_PROBES, &val, sizeof(val)))
+ return 0;
+ val = dplane_ctx_neightable_get_mcast_probes(ctx);
+ if (!nl_attr_put(&req->n, datalen, NDTPA_MCAST_PROBES, &val,
+ sizeof(val)))
+ return 0;
+ val = dplane_ctx_neightable_get_ucast_probes(ctx);
+ if (!nl_attr_put(&req->n, datalen, NDTPA_UCAST_PROBES, &val,
+ sizeof(val)))
+ return 0;
+ nl_attr_nest_end(&req->n, nest);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
@@ -3710,9 +3847,11 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
break;
case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_DELETE:
ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen);
break;
case DPLANE_OP_VTEP_ADD:
@@ -3723,6 +3862,9 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf,
buflen);
break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ ret = netlink_neigh_table_update_ctx(ctx, buf, buflen);
+ break;
default:
ret = -1;
}
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index a0f401c33..ada828d01 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -362,8 +362,14 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
-int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id)
+int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg)
+{
+ /* TODO */
+ return 0;
+}
+
+int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
+ ns_id_t ns_id, uint8_t family, bool permanent)
{
/* TODO */
return 0;
@@ -388,6 +394,12 @@ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
+int kernel_configure_if_link(struct interface *ifp, struct interface *link_ifp,
+ ns_id_t ns_id)
+{
+ return 0;
+}
+
extern int kernel_interface_set_master(struct interface *master,
struct interface *slave)
{
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index b48291441..e854d7ff3 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -974,6 +974,37 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx,
zserv_send_message(client, s);
}
+void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp,
+ struct ipaddr *ipaddr, int ndm_state,
+ union sockunion *link_layer_ipv4)
+{
+ struct stream *s;
+ struct listnode *node, *nnode;
+ struct zserv *client;
+ afi_t afi;
+ union sockunion ip;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Notifying Neighbor entry (%u)",
+ __PRETTY_FUNCTION__, cmd);
+
+ sockunion_family(&ip) = ipaddr_family(ipaddr);
+ afi = family2afi(sockunion_family(&ip));
+ memcpy((char *)sockunion_get_addr(&ip), &ipaddr->ip.addr,
+ family2addrsize(sockunion_family(&ip)));
+
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], ifp->vrf_id))
+ continue;
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ zclient_neigh_ip_encode(s, cmd, &ip, link_layer_ipv4, ifp);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zserv_send_message(client, s);
+ }
+}
+
+
/* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */
int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p,
vrf_id_t vrf_id)
@@ -2277,6 +2308,7 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS)
vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf));
vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf));
vrf_bitmap_unset(client->ridinfo[afi], zvrf_id(zvrf));
+ vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
}
}
@@ -3167,6 +3199,97 @@ stream_failure:
return;
}
+
+static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS)
+{
+ afi_t afi;
+
+ STREAM_GETW(msg, afi);
+ if (afi <= AFI_UNSPEC || afi >= AFI_MAX) {
+ zlog_warn(
+ "Invalid AFI %u while registering for neighbors notifications",
+ afi);
+ goto stream_failure;
+ }
+ vrf_bitmap_set(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
+stream_failure:
+ return;
+}
+
+static inline void zebra_neigh_unregister(ZAPI_HANDLER_ARGS)
+{
+ afi_t afi;
+
+ STREAM_GETW(msg, afi);
+ if (afi <= AFI_UNSPEC || afi >= AFI_MAX) {
+ zlog_warn(
+ "Invalid AFI %u while unregistering from neighbor notifications",
+ afi);
+ goto stream_failure;
+ }
+ vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
+stream_failure:
+ return;
+}
+
+static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ uint8_t fam;
+ ifindex_t idx;
+ struct interface *ifp;
+
+ s = msg;
+ STREAM_GETC(s, fam);
+ if (fam != AF_INET && fam != AF_INET6)
+ return;
+ STREAM_GETL(s, idx);
+ ifp = if_lookup_by_index_per_ns(zvrf->zns, idx);
+ if (!ifp)
+ return;
+ dplane_neigh_table_update(ifp, fam, 1, 0, 0);
+stream_failure:
+ return;
+}
+
+static inline void zebra_neigh_ip_add(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_neigh_ip api = {};
+ int ret;
+ const struct interface *ifp;
+
+ s = msg;
+ ret = zclient_neigh_ip_decode(s, &api);
+ if (ret < 0)
+ return;
+ ifp = if_lookup_by_index(api.index, zvrf_id(zvrf));
+ if (!ifp)
+ return;
+ dplane_neigh_ip_update(DPLANE_OP_NEIGH_IP_INSTALL, ifp, &api.ip_out,
+ &api.ip_in, api.ndm_state, client->proto);
+}
+
+
+static inline void zebra_neigh_ip_del(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_neigh_ip api = {};
+ int ret;
+ struct interface *ifp;
+
+ s = msg;
+ ret = zclient_neigh_ip_decode(s, &api);
+ if (ret < 0)
+ return;
+ ifp = if_lookup_by_index(api.index, zvrf_id(zvrf));
+ if (!ifp)
+ return;
+ dplane_neigh_ip_update(DPLANE_OP_NEIGH_IP_DELETE, ifp, &api.ip_out,
+ &api.ip_in, api.ndm_state, client->proto);
+}
+
+
static inline void zread_iptable(ZAPI_HANDLER_ARGS)
{
struct zebra_pbr_iptable *zpi =
@@ -3352,6 +3475,11 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_ROUTE_NOTIFY_REQUEST] = zread_route_notify_request,
[ZEBRA_EVPN_REMOTE_NH_ADD] = zebra_evpn_proc_remote_nh,
[ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh,
+ [ZEBRA_NEIGH_IP_ADD] = zebra_neigh_ip_add,
+ [ZEBRA_NEIGH_IP_DEL] = zebra_neigh_ip_del,
+ [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register,
+ [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister,
+ [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp,
};
/*
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index ca471f8d9..0beb3cc10 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -104,6 +104,9 @@ extern int zsend_label_manager_connect_response(struct zserv *client,
extern int zsend_sr_policy_notify_status(uint32_t color,
struct ipaddr *endpoint, char *name,
int status);
+extern void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp,
+ struct ipaddr *ipaddr, int ndm_state,
+ union sockunion *link_layer_ipv4);
extern int zsend_client_close_notify(struct zserv *client,
struct zserv *closed_client);
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 18fe0a7e8..c8ee8f905 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -220,13 +220,26 @@ struct dplane_mac_info {
*/
struct dplane_neigh_info {
struct ipaddr ip_addr;
- struct ethaddr mac;
+ union {
+ struct ethaddr mac;
+ struct ipaddr ip_addr;
+ } link;
uint32_t flags;
uint16_t state;
uint32_t update_flags;
};
/*
+ * Neighbor Table
+ */
+struct dplane_neigh_table {
+ uint8_t family;
+ uint32_t app_probes;
+ uint32_t ucast_probes;
+ uint32_t mcast_probes;
+};
+
+/*
* Policy based routing rule info for the dataplane
*/
struct dplane_ctx_rule {
@@ -313,6 +326,7 @@ struct zebra_dplane_ctx {
struct zebra_pbr_ipset_entry entry;
struct zebra_pbr_ipset_info info;
} ipset_entry;
+ struct dplane_neigh_table neightable;
} u;
/* Namespace info, used especially for netlink kernel communication */
@@ -452,6 +466,9 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_ipset_entry_in;
_Atomic uint32_t dg_ipset_entry_errors;
+ _Atomic uint32_t dg_neightable_in;
+ _Atomic uint32_t dg_neightable_errors;
+
/* Dataplane pthread */
struct frr_pthread *dg_pthread;
@@ -496,12 +513,11 @@ static enum zebra_dplane_result mac_update_common(
vlanid_t vid, const struct ethaddr *mac,
struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
uint32_t update_flags);
-static enum zebra_dplane_result neigh_update_internal(
- enum dplane_op_e op,
- const struct interface *ifp,
- const struct ethaddr *mac,
- const struct ipaddr *ip,
- uint32_t flags, uint16_t state, uint32_t update_flags);
+static enum zebra_dplane_result
+neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
+ const void *link, int link_family,
+ const struct ipaddr *ip, uint32_t flags, uint16_t state,
+ uint32_t update_flags, int protocol);
/*
* Public APIs
@@ -669,6 +685,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_RULE_UPDATE:
case DPLANE_OP_NEIGH_DISCOVER:
case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_NONE:
case DPLANE_OP_IPSET_ADD:
case DPLANE_OP_IPSET_DELETE:
@@ -677,6 +695,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ break;
case DPLANE_OP_IPTABLE_ADD:
case DPLANE_OP_IPTABLE_DELETE:
if (ctx->u.iptable.interface_name_list) {
@@ -950,6 +970,15 @@ const char *dplane_op2str(enum dplane_op_e op)
case DPLANE_OP_IPSET_ENTRY_DELETE:
ret = "IPSET_ENTRY_DELETE";
break;
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ ret = "NEIGH_IP_INSTALL";
+ break;
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ ret = "NEIGH_IP_DELETE";
+ break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ ret = "NEIGH_TABLE_UPDATE";
+ break;
}
return ret;
@@ -1711,11 +1740,18 @@ const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
return &(ctx->u.neigh.ip_addr);
}
+const struct ipaddr *
+dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return &(ctx->u.neigh.link.ip_addr);
+}
+
const struct ethaddr *dplane_ctx_neigh_get_mac(
const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->u.neigh.mac);
+ return &(ctx->u.neigh.link.mac);
}
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
@@ -1978,6 +2014,37 @@ uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr)
return ptr->status;
}
+uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.family;
+}
+
+uint32_t
+dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.app_probes;
+}
+
+uint32_t
+dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.ucast_probes;
+}
+
+uint32_t
+dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.mcast_probes;
+}
+
/*
* End of interface extra info accessors
*/
@@ -3436,6 +3503,41 @@ enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
}
/*
+ * API to configure link local with either MAC address or IP information
+ */
+enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
+ const struct interface *ifp,
+ struct ipaddr *link_ip,
+ struct ipaddr *ip,
+ uint32_t ndm_state, int protocol)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ uint16_t state = 0;
+ uint32_t update_flags;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[PREFIX_STRLEN], buf2[PREFIX_STRLEN];
+
+ ipaddr2str(link_ip, buf1, sizeof(buf1));
+ ipaddr2str(ip, buf2, sizeof(buf2));
+ zlog_debug("init link ctx %s: ifp %s, ip %s link %s",
+ dplane_op2str(op), ifp->name, buf1, buf2);
+ }
+ if (ndm_state == ZEBRA_NEIGH_STATE_REACHABLE)
+ state = DPLANE_NUD_REACHABLE;
+ else if (ndm_state == ZEBRA_NEIGH_STATE_FAILED)
+ state = DPLANE_NUD_FAILED;
+
+ update_flags = DPLANE_NEIGH_NO_EXTENSION;
+
+ result = neigh_update_internal(op, ifp, (const void *)link_ip,
+ ipaddr_family(link_ip), ip, 0, state,
+ update_flags, protocol);
+
+ return result;
+}
+
+/*
* Enqueue local mac add (or update).
*/
enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
@@ -3584,9 +3686,9 @@ enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp,
if (was_static)
update_flags |= DPLANE_NEIGH_WAS_STATIC;
- result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
- ifp, mac, ip, flags, DPLANE_NUD_NOARP,
- update_flags);
+ result = neigh_update_internal(
+ DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET,
+ ip, flags, DPLANE_NUD_NOARP, update_flags, 0);
return result;
}
@@ -3618,9 +3720,9 @@ enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
if (set_router)
ntf |= DPLANE_NTF_ROUTER;
- result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
- ifp, mac, ip, ntf,
- state, update_flags);
+ result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp,
+ (const void *)mac, AF_ETHERNET, ip, ntf,
+ state, update_flags, 0);
return result;
}
@@ -3636,8 +3738,8 @@ enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
update_flags |= DPLANE_NEIGH_REMOTE;
- result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE,
- ifp, NULL, ip, 0, 0, update_flags);
+ result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL,
+ AF_ETHERNET, ip, 0, 0, update_flags, 0);
return result;
}
@@ -3660,8 +3762,8 @@ enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
SET_IPADDR_V4(&addr);
addr.ipaddr_v4 = *ip;
- result = neigh_update_internal(DPLANE_OP_VTEP_ADD,
- ifp, &mac, &addr, 0, 0, 0);
+ result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac,
+ AF_ETHERNET, &addr, 0, 0, 0, 0);
return result;
}
@@ -3685,8 +3787,9 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
SET_IPADDR_V4(&addr);
addr.ipaddr_v4 = *ip;
- result = neigh_update_internal(DPLANE_OP_VTEP_DELETE,
- ifp, &mac, &addr, 0, 0, 0);
+ result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp,
+ (const void *)&mac, AF_ETHERNET, &addr,
+ 0, 0, 0, 0);
return result;
}
@@ -3696,8 +3799,65 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
{
enum zebra_dplane_result result;
- result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL, ip,
- DPLANE_NTF_USE, DPLANE_NUD_INCOMPLETE, 0);
+ result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL,
+ AF_ETHERNET, ip, DPLANE_NTF_USE,
+ DPLANE_NUD_INCOMPLETE, 0, 0);
+
+ return result;
+}
+
+enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
+ const uint8_t family,
+ const uint32_t app_probes,
+ const uint32_t ucast_probes,
+ const uint32_t mcast_probes)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+ struct zebra_ns *zns;
+ enum dplane_op_e op = DPLANE_OP_NEIGH_TABLE_UPDATE;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ zlog_debug("set neigh ctx %s: ifp %s, family %s",
+ dplane_op2str(op), ifp->name, family2str(family));
+ }
+
+ ctx = dplane_ctx_alloc();
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_vrf_id = ifp->vrf_id;
+
+ zns = zebra_ns_lookup(ifp->vrf_id);
+ dplane_ctx_ns_init(ctx, zns, false);
+
+ strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
+ ctx->zd_ifindex = ifp->ifindex;
+
+ /* Init the neighbor-specific data area */
+ memset(&ctx->u.neightable, 0, sizeof(ctx->u.neightable));
+
+ ctx->u.neightable.family = family;
+ ctx->u.neightable.app_probes = app_probes;
+ ctx->u.neightable.ucast_probes = ucast_probes;
+ ctx->u.neightable.mcast_probes = mcast_probes;
+
+ /* Enqueue for processing on the dplane pthread */
+ ret = dplane_update_enqueue(ctx);
+
+ /* Increment counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_neightable_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ /* Error counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_neightable_errors, 1,
+ memory_order_relaxed);
+ dplane_ctx_free(&ctx);
+ }
return result;
}
@@ -3706,27 +3866,43 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
* Common helper api for neighbor updates
*/
static enum zebra_dplane_result
-neigh_update_internal(enum dplane_op_e op,
- const struct interface *ifp,
- const struct ethaddr *mac,
- const struct ipaddr *ip,
- uint32_t flags, uint16_t state,
- uint32_t update_flags)
+neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
+ const void *link, const int link_family,
+ const struct ipaddr *ip, uint32_t flags, uint16_t state,
+ uint32_t update_flags, int protocol)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
struct zebra_dplane_ctx *ctx = NULL;
struct zebra_ns *zns;
+ const struct ethaddr *mac = NULL;
+ const struct ipaddr *link_ip = NULL;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("init neigh ctx %s: ifp %s, mac %pEA, ip %pIA",
- dplane_op2str(op), ifp->name, mac, ip);
+ if (link_family == AF_ETHERNET)
+ mac = (const struct ethaddr *)link;
+ else
+ link_ip = (const struct ipaddr *)link;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[PREFIX_STRLEN];
+
+ buf1[0] = '\0';
+ if (link_family == AF_ETHERNET)
+ prefix_mac2str(mac, buf1, sizeof(buf1));
+ else
+ ipaddr2str(link_ip, buf1, sizeof(buf1));
+ zlog_debug("init neigh ctx %s: ifp %s, %s %s, ip %pIA",
+ dplane_op2str(op), ifp->name,
+ link_family == AF_ETHERNET ? "mac " : "link ",
+ buf1, ip);
+ }
ctx = dplane_ctx_alloc();
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
ctx->zd_vrf_id = ifp->vrf_id;
+ dplane_ctx_set_type(ctx, protocol);
zns = zebra_ns_lookup(ifp->vrf_id);
dplane_ctx_ns_init(ctx, zns, false);
@@ -3739,7 +3915,10 @@ neigh_update_internal(enum dplane_op_e op,
ctx->u.neigh.ip_addr = *ip;
if (mac)
- ctx->u.neigh.mac = *mac;
+ ctx->u.neigh.link.mac = *mac;
+ else if (link_ip)
+ ctx->u.neigh.link.ip_addr = *link_ip;
+
ctx->u.neigh.flags = flags;
ctx->u.neigh.state = state;
ctx->u.neigh.update_flags = update_flags;
@@ -4048,6 +4227,13 @@ int dplane_show_helper(struct vty *vty, bool detailed)
memory_order_relaxed);
vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming);
vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs);
+
+ incoming = atomic_load_explicit(&zdplane_info.dg_neightable_in,
+ memory_order_relaxed);
+ errs = atomic_load_explicit(&zdplane_info.dg_neightable_errors,
+ memory_order_relaxed);
+ vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming);
+ vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs);
return CMD_SUCCESS;
}
@@ -4433,6 +4619,8 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
sizeof(buf));
@@ -4485,6 +4673,13 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
dplane_op2str(dplane_ctx_get_op(ctx)),
ipent.unique, ctx);
} break;
+
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ zlog_debug("Dplane neigh table op %s, ifp %s, family %s",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_ifname(ctx),
+ family2str(dplane_ctx_neightable_get_family(ctx)));
+ break;
}
}
@@ -4568,6 +4763,8 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
1, memory_order_relaxed);
@@ -4604,6 +4801,13 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
memory_order_relaxed);
break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_neightable_errors, 1,
+ memory_order_relaxed);
+ break;
+
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 4913ca251..8d51d93cd 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -165,6 +165,12 @@ enum dplane_op_e {
DPLANE_OP_IPSET_DELETE,
DPLANE_OP_IPSET_ENTRY_ADD,
DPLANE_OP_IPSET_ENTRY_DELETE,
+
+ /* LINK LAYER IP address update */
+ DPLANE_OP_NEIGH_IP_INSTALL,
+ DPLANE_OP_NEIGH_IP_DELETE,
+
+ DPLANE_OP_NEIGH_TABLE_UPDATE,
};
/*
@@ -184,6 +190,8 @@ enum dplane_op_e {
#define DPLANE_NUD_NOARP 0x04
#define DPLANE_NUD_PROBE 0x08
#define DPLANE_NUD_INCOMPLETE 0x10
+#define DPLANE_NUD_PERMANENT 0x20
+#define DPLANE_NUD_FAILED 0x40
/* MAC update flags - dplane_mac_info.update_flags */
#define DPLANE_MAC_REMOTE (1 << 0)
@@ -196,6 +204,7 @@ enum dplane_op_e {
#define DPLANE_NEIGH_WAS_STATIC (1 << 1)
#define DPLANE_NEIGH_SET_STATIC (1 << 2)
#define DPLANE_NEIGH_SET_INACTIVE (1 << 3)
+#define DPLANE_NEIGH_NO_EXTENSION (1 << 4)
#define DPLANE_BR_PORT_NON_DF (1 << 0)
@@ -458,6 +467,8 @@ const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
const struct zebra_dplane_ctx *ctx);
const struct ethaddr *dplane_ctx_neigh_get_mac(
const struct zebra_dplane_ctx *ctx);
+const struct ipaddr *
+dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx);
uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx);
@@ -507,6 +518,15 @@ dplane_ctx_get_br_port_sph_filters(const struct zebra_dplane_ctx *ctx);
uint32_t
dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx);
+/* Accessors for neighbor table information */
+uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx);
+uint32_t
+dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx);
+uint32_t
+dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx);
+uint32_t
+dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx);
+
/* Namespace info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx);
@@ -585,6 +605,16 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
const struct connected *ifc);
/*
+ * Link layer operations for the dataplane.
+ */
+enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
+ const struct interface *ifp,
+ struct ipaddr *link_ip,
+ struct ipaddr *ip,
+ uint32_t ndm_state,
+ int protocol);
+
+/*
* Enqueue evpn mac operations for the dataplane.
*/
enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
@@ -656,6 +686,15 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
const struct ipaddr *ip);
+/*
+ * Enqueue a neighbor table parameter set
+ */
+enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
+ const uint8_t family,
+ const uint32_t app_probes,
+ const uint32_t ucast_probes,
+ const uint32_t mcast_probes);
+
/* Forward ref of zebra_pbr_rule */
struct zebra_pbr_rule;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 12ed024a6..7edf02289 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2898,6 +2898,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_RULE_ADD:
@@ -2912,6 +2914,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_IPSET_DELETE:
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
break;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index ffe4be855..82a0e6d01 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3924,10 +3924,13 @@ static int rib_process_dplane_results(struct thread *thread)
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_NONE:
/* Don't expect this: just return the struct? */
dplane_ctx_fini(&ctx);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 6c5eebe6f..f89b6fe47 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -638,6 +638,7 @@ static void zserv_client_free(struct zserv *client)
vrf_bitmap_free(client->redist_default[afi]);
vrf_bitmap_free(client->ridinfo[afi]);
+ vrf_bitmap_free(client->nhrp_neighinfo[afi]);
}
/*
@@ -760,6 +761,7 @@ static struct zserv *zserv_client_create(int sock)
client->redist[afi][i] = vrf_bitmap_init();
client->redist_default[afi] = vrf_bitmap_init();
client->ridinfo[afi] = vrf_bitmap_init();
+ client->nhrp_neighinfo[afi] = vrf_bitmap_init();
}
/* Add this client to linked list. */
diff --git a/zebra/zserv.h b/zebra/zserv.h
index c60799b8b..203670ac1 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -137,6 +137,9 @@ struct zserv {
/* Router-id information. */
vrf_bitmap_t ridinfo[AFI_MAX];
+ /* Router-id information. */
+ vrf_bitmap_t nhrp_neighinfo[AFI_MAX];
+
bool notify_owner;
/* Indicates if client is synchronous. */