diff options
| -rw-r--r-- | nhrpd/netlink_arp.c | 167 | ||||
| -rw-r--r-- | nhrpd/nhrp_route.c | 26 | ||||
| -rw-r--r-- | nhrpd/nhrpd.h | 1 | 
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);  | 
