tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: RTM_NEWNEIGH



On 14/12/2014 22:23, David Young wrote:
> On Thu, Dec 11, 2014 at 12:57:58PM -0500, Greg Troxel wrote:
>>> dhcpcd polls SIOCGNBRINFO_IN6 every second for every IPv6 router it
>>> knows about to test neighbour reach-ability.
>>> This isn't exactly optimal, hello battery drain.
>>>
>>> Attached is a patch to add RTM_NEWNEIGH so that userland can react to
>>> Neighbour Discovery changes, similar to the Linux equivalent.
>>> It's designed to be protocol agnostic, (ie could be used for ARP as
>>> well).
>>> Currently, it only raises RTM_NEWNEIGH on IPv6 neighbour state and
>>> flag (is it a router?) changes.
>>> There is little point in generating RTM_DELNEIGH or RTM_GETNEIGH as
>>> Linux does because our current
>>> implementation sends equivalent messages via RTM_DELETE or RTM_CHANGE.
>>
>> Why doesn't RTM_ADD get sent for ND entries in the table?  I don't see
>> why a new message is needed.  Or is this about some later state
>> transition from them just being added, because the later transition is
>> what matters.
> 
> I'd also like to know why RTM_ADD isn't sent for the new neighbors.

Because there is no code to notify userland!

Here is a new patch where all route changes are notified to userland:
  *  RTM_ADD for new neighbour cache entry
  *  RTM_CHANGE for an updated cache entry
  *  RTM_DEL for a deleted neighbour cache entry

Using this I can then detect host route additions/changes/deletions and
take action in dhcpcd accordingly. After all, I only care if I can reach
the router or not, I don't care about the neighbour state as such.

Would this patch be preferable? I'm guessing yes it would.
Comments welcome.

Roy
Index: netinet6/nd6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6.c,v
retrieving revision 1.155
diff -u -p -r1.155 nd6.c
--- netinet6/nd6.c	3 Dec 2014 01:32:11 -0000	1.155
+++ netinet6/nd6.c	15 Dec 2014 17:59:54 -0000
@@ -1037,6 +1037,7 @@ nd6_free(struct rtentry *rt, int gc)
 	struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;
 	struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr;
 	struct nd_defrouter *dr;
+	struct rtentry *ort;
 
 	/*
 	 * we used to have pfctlinput(PRC_HOSTDEAD) here.
@@ -1129,7 +1130,12 @@ nd6_free(struct rtentry *rt, int gc)
 	 * caches, and disable the route entry not to be used in already
 	 * cached routes.
 	 */
-	rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL);
+	ort = NULL;
+	rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, &ort);
+	if (ort) {
+		nd6_rtmsg(RTM_DELETE, rt); /* tell user process */
+		ort->rt_refcnt--;
+	}
 
 	return next;
 }
@@ -2059,6 +2065,9 @@ fail:
 		break;
 	}
 
+	if (do_update)
+		nd6_rtmsg(RTM_CHANGE, rt);  /* tell user process */
+
 	/*
 	 * When the link-layer address of a router changes, select the
 	 * best router again.  In particular, when the neighbor entry is newly
Index: netinet6/nd6.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6.h,v
retrieving revision 1.60
diff -u -p -r1.60 nd6.h
--- netinet6/nd6.h	5 Sep 2014 06:08:15 -0000	1.60
+++ netinet6/nd6.h	15 Dec 2014 17:59:54 -0000
@@ -413,6 +413,7 @@ void nd6_option_init(void *, int, union 
 struct nd_opt_hdr *nd6_option(union nd_opts *);
 int nd6_options(union nd_opts *);
 struct	rtentry *nd6_lookup(const struct in6_addr *, int, struct ifnet *);
+void nd6_rtmsg(int, struct rtentry *);
 void nd6_setmtu(struct ifnet *);
 void nd6_llinfo_settimer(struct llinfo_nd6 *, long);
 void nd6_timer(void *);
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.102
diff -u -p -r1.102 nd6_nbr.c
--- netinet6/nd6_nbr.c	12 Oct 2014 20:05:50 -0000	1.102
+++ netinet6/nd6_nbr.c	15 Dec 2014 17:59:54 -0000
@@ -567,6 +567,7 @@ nd6_na_input(struct mbuf *m, int off, in
 	struct sockaddr_dl *sdl;
 	union nd_opts ndopts;
 	struct sockaddr_in6 ssin6;
+	int rtannounce;
 
 	if (ip6->ip6_hlim != 255) {
 		nd6log((LOG_ERR,
@@ -669,6 +670,7 @@ nd6_na_input(struct mbuf *m, int off, in
 	   ((sdl = satosdl(rt->rt_gateway)) == NULL))
 		goto freeit;
 
+	rtannounce = 0;
 	if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
 		/*
 		 * If the link-layer has address, and no lladdr option came,
@@ -682,6 +684,7 @@ nd6_na_input(struct mbuf *m, int off, in
 		 */
 		(void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr,
 		    ifp->if_addrlen);
+		rtannounce = 1;
 		if (is_solicited) {
 			ln->ln_state = ND6_LLINFO_REACHABLE;
 			ln->ln_byhint = 0;
@@ -712,11 +715,11 @@ nd6_na_input(struct mbuf *m, int off, in
 		else {
 			if (sdl->sdl_alen) {
 				if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen))
-					llchange = 1;
+					llchange = rtannounce = 1;
 				else
 					llchange = 0;
 			} else
-				llchange = 1;
+				llchange = rtannounce = 1;
 		}
 
 		/*
@@ -819,6 +822,8 @@ nd6_na_input(struct mbuf *m, int off, in
 	rt->rt_flags &= ~RTF_REJECT;
 	ln->ln_asked = 0;
 	nd6_llinfo_release_pkts(ln, ifp, rt);
+	if (rtannounce) /* tell user process about any new lladdr */
+		nd6_rtmsg(RTM_CHANGE, rt);
 
  freeit:
 	m_freem(m);
Index: netinet6/nd6_rtr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.94
diff -u -p -r1.94 nd6_rtr.c
--- netinet6/nd6_rtr.c	5 Sep 2014 06:08:15 -0000	1.94
+++ netinet6/nd6_rtr.c	15 Dec 2014 17:59:54 -0000
@@ -76,7 +76,6 @@ static void pfxrtr_del(struct nd_pfxrout
 static struct nd_pfxrouter *find_pfxlist_reachable_router
 	(struct nd_prefix *);
 static void defrouter_delreq(struct nd_defrouter *);
-static void nd6_rtmsg(int, struct rtentry *);
 
 static int in6_init_prefix_ltimes(struct nd_prefix *);
 static void in6_init_address_ltimes(struct nd_prefix *,
@@ -416,7 +415,7 @@ nd6_ra_input(struct mbuf *m, int off, in
  */
 
 /* tell the change to user processes watching the routing socket. */
-static void
+void
 nd6_rtmsg(int cmd, struct rtentry *rt)
 {
 	struct rt_addrinfo info;


Home | Main Index | Thread Index | Old Index