summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nhrpd/netlink_arp.c167
-rw-r--r--nhrpd/nhrp_route.c26
-rw-r--r--nhrpd/nhrpd.h1
3 files changed, 91 insertions, 103 deletions
diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c
index dc4697cda0..bb8e73ab1e 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,8 +29,6 @@ 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,
@@ -58,100 +58,6 @@ void netlink_update_binding(struct interface *ifp, union sockunion *proto,
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;
-}
-
static void netlink_log_register(int fd, int group)
{
struct nlmsghdr *n;
@@ -265,17 +171,74 @@ void netlink_set_nflog_group(int nlgroup)
}
}
+void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
+{
+ union sockunion addr = {}, lladdr = {};
+ struct interface *ifp;
+ ifindex_t idx;
+ struct ethaddr mac;
+ int state, ndm_state;
+ struct nhrp_cache *c;
+ unsigned short l2_len;
+
+ STREAM_GETL(zclient->ibuf, idx);
+ ifp = if_lookup_by_index(idx, vrf_id);
+ STREAM_GETW(zclient->ibuf, addr.sa.sa_family);
+ if (addr.sa.sa_family == AF_INET) {
+ STREAM_GET(&addr.sin.sin_addr.s_addr,
+ zclient->ibuf, IPV4_MAX_BYTELEN);
+ } else {
+ STREAM_GET(&addr.sin6.sin6_addr.s6_addr,
+ zclient->ibuf, IPV6_MAX_BYTELEN);
+ }
+ STREAM_GETL(zclient->ibuf, ndm_state);
+
+ STREAM_GETL(zclient->ibuf, l2_len);
+ if (l2_len) {
+ STREAM_GET(&mac, zclient->ibuf, l2_len);
+ if (l2_len == IPV4_MAX_BYTELEN)
+ sockunion_set(&lladdr, AF_INET, (const uint8_t *)&mac,
+ l2_len);
+ }
+ 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
+ : NUD_FAILED;
+ nhrp_cache_set_used(c, state == NUD_REACHABLE);
+ }
+ return;
+ stream_failure:
+ return;
+}
+
void netlink_init(void)
{
netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
if (netlink_req_fd < 0)
return;
-
- netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH);
- if (netlink_listen_fd < 0)
- return;
-
- thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd, NULL);
}
int netlink_configure_arp(unsigned int ifindex, int pf)
diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c
index 7a4c57b5d4..746b585ede 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);
}
@@ -372,6 +394,8 @@ static void nhrp_table_node_cleanup(struct route_table *table,
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 e4afb22f80..6e7ddda18d 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -326,6 +326,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);