tech-net archive

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

Re: IPv6 "is unreachable" route flapping



On 22/08/2019 14:31, Roy Marples wrote:
On 22/08/2019 13:46, Paul Ripke wrote:
Does this attached patch help any?

This is for the client (dhcpcd running) side? And/or the server (rtadvd) side? I'll test it on a few machines and see what I see (I need to figure out a nice
way of upgrading the Pi).

It's for the client.

OK, while that patch is of use, it doesn't really solve the problem and it's probably of limited use, but it does restore prior behaviour.

There are two problems in play - firstly I broke dhcpcd, patch attached to solve that. Secondly, it seems we no longer announce route changes when reachabilty is lost or gained since nd6.c 1.188.
Attached is a patch to fix that as well.

Let me know how it works for you!

Roy
diff --git a/src/if-bsd.c b/src/if-bsd.c
index 6d5531cb..c1a010be 100644
--- a/src/if-bsd.c
+++ b/src/if-bsd.c
@@ -674,10 +674,18 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
 		if (rt->rt_netmask.sa_family == 255) /* Why? */
 			rt->rt_netmask.sa_family = rt->rt_dest.sa_family;
 	}
-	/* dhcpcd likes an unspecified gateway to indicate via the link. */
-	if (rt->rt_flags & RTF_GATEWAY &&
-	    rti_info[RTAX_GATEWAY]->sa_family != AF_LINK)
-		if_copysa(&rt->rt_gateway, rti_info[RTAX_GATEWAY]);
+	/* dhcpcd likes an unspecified gateway to indicate via the link.
+	 * However we need to know if gateway was a link with an address. */
+	if (rt->rt_flags & RTF_GATEWAY) {
+		if (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) {
+			const struct sockaddr_dl *sdl;
+
+			sdl = (const struct sockaddr_dl*)rti_info[RTAX_GATEWAY];
+			if (sdl->sdl_alen != 0)
+				rt->rt_dflags |= RTDF_GATELINK;
+		} else
+			if_copysa(&rt->rt_gateway, rti_info[RTAX_GATEWAY]);
+	}
 	if (rtm->rtm_addrs & RTA_IFA)
 		if_copysa(&rt->rt_ifa, rti_info[RTAX_IFA]);
 	rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
@@ -1079,17 +1087,9 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
 	 * existance with a hardware address.
 	 */
 	if (rt.rt_dest.sa_family == AF_INET6 && rt.rt_flags & RTF_HOST) {
-		struct sockaddr_in6 dest;
-		struct sockaddr_dl sdl;
-
-		memcpy(&dest, &rt.rt_dest, rt.rt_dest.sa_len);
-		if (rt.rt_gateway.sa_family == AF_LINK)
-			memcpy(&sdl, &rt.rt_gateway, rt.rt_gateway.sa_len);
-		else
-			sdl.sdl_alen = 0;
-		ipv6nd_neighbour(ctx, &dest.sin6_addr,
-		    rtm->rtm_type != RTM_DELETE && sdl.sdl_alen ?
-		    IPV6ND_REACHABLE : 0);
+		ipv6nd_neighbour(ctx, &rt.rt_ss_dest.sin6.sin6_addr,
+		    rtm->rtm_type != RTM_DELETE && rt.rt_dflags & RTDF_GATELINK
+		    ? IPV6ND_REACHABLE : 0);
 	}
 #endif
 
diff --git a/src/route.h b/src/route.h
index d1613943..74570fa7 100644
--- a/src/route.h
+++ b/src/route.h
@@ -92,6 +92,7 @@ struct rt {
 #define	RTDF_RA			0x08		/* Router Advertisement */
 #define	RTDF_DHCP		0x10		/* DHCP route */
 #define	RTDF_STATIC		0x20		/* Configured in dhcpcd */
+#define	RTDF_GATELINK		0x40		/* Gateway is on link */
 	size_t			rt_order;
 	rb_node_t		rt_tree;
 };
Index: sys/net/route.h
===================================================================
RCS file: /cvsroot/src/sys/net/route.h,v
retrieving revision 1.123
diff -u -p -r1.123 route.h
--- sys/net/route.h	29 Apr 2019 16:12:30 -0000	1.123
+++ sys/net/route.h	22 Aug 2019 17:57:13 -0000
@@ -521,8 +521,8 @@ void	rt_addrmsg_rt(int, struct ifaddr *,
 void	route_enqueue(struct mbuf *, int);
 
 struct llentry;
-void	rt_clonedmsg(const struct sockaddr *, const struct ifnet *,
-	    const struct rtentry *);
+void	rt_clonedmsg(int, const struct sockaddr *, const uint8_t *,
+            const struct ifnet *);
 
 void	rt_setmetrics(void *, struct rtentry *);
 
Index: sys/net/rtsock.c
===================================================================
RCS file: /cvsroot/src/sys/net/rtsock.c,v
retrieving revision 1.250
diff -u -p -r1.250 rtsock.c
--- sys/net/rtsock.c	27 May 2019 05:33:48 -0000	1.250
+++ sys/net/rtsock.c	22 Aug 2019 17:57:13 -0000
@@ -145,14 +145,14 @@ if_addrflags(struct ifaddr *ifa)
  * Send a routing message as mimicing that a cloned route is added.
  */
 void
-rt_clonedmsg(const struct sockaddr *dst, const struct ifnet *ifp,
-    const struct rtentry *rt)
+rt_clonedmsg(int type, const struct sockaddr *dst, const uint8_t *lladdr,
+    const struct ifnet *ifp)
 {
 	struct rt_addrinfo info;
 	/* Mimic flags exactly */
 #define RTF_LLINFO	0x400
 #define RTF_CLONED	0x2000
-	int flags = RTF_UP | RTF_HOST | RTF_DONE | RTF_LLINFO | RTF_CLONED;
+	int flags = RTF_HOST | RTF_DONE | RTF_LLINFO | RTF_CLONED;
 	union {
 		struct sockaddr sa;
 		struct sockaddr_storage ss;
@@ -161,16 +161,15 @@ rt_clonedmsg(const struct sockaddr *dst,
 	uint8_t namelen = strlen(ifp->if_xname);
 	uint8_t addrlen = ifp->if_addrlen;
 
-	if (rt == NULL)
-		return; /* XXX */
-
+	if (type != RTM_DELETE)
+		flags |= RTF_UP;
 	memset(&info, 0, sizeof(info));
 	info.rti_info[RTAX_DST] = dst;
 	sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type,
-	    NULL, namelen, NULL, addrlen);
+	    NULL, namelen, lladdr, addrlen);
 	info.rti_info[RTAX_GATEWAY] = &u.sa;
 
-	rt_missmsg(RTM_ADD, &info, flags, 0);
+	rt_missmsg(type, &info, flags, 0);
 #undef RTF_LLINFO
 #undef RTF_CLONED
 }
Index: sys/netinet6/nd6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6.c,v
retrieving revision 1.257
diff -u -p -r1.257 nd6.c
--- sys/netinet6/nd6.c	14 Aug 2019 08:34:44 -0000	1.257
+++ sys/netinet6/nd6.c	22 Aug 2019 17:57:14 -0000
@@ -1189,29 +1189,26 @@ nd6_is_addr_neighbor(const struct sockad
 static void
 nd6_free(struct llentry *ln, int gc)
 {
-	struct nd_defrouter *dr;
 	struct ifnet *ifp;
 	struct in6_addr *in6;
+	struct sockaddr_in6 sin6;
 
 	KASSERT(ln != NULL);
 	LLE_WLOCK_ASSERT(ln);
 
 	ifp = ln->lle_tbl->llt_ifp;
 	in6 = &ln->r_l3addr.addr6;
+	sockaddr_in6_init(&sin6, in6, 0, 0, 0);
 	/*
 	 * we used to have pfctlinput(PRC_HOSTDEAD) here.
 	 * even though it is not harmful, it was not really necessary.
 	 */
 
 	if (!ip6_forwarding) {
-		ND6_WLOCK();
-		dr = nd6_defrouter_lookup(in6, ifp);
-
-		if (dr != NULL && dr->expire &&
-		    ln->ln_state == ND6_LLINFO_STALE && gc) {
+		if (ln->ln_router && ln->ln_state == ND6_LLINFO_STALE && gc) {
 			/*
 			 * If the reason for the deletion is just garbage
-			 * collection, and the neighbor is an active default
+			 * collection, and the neighbor is an active
 			 * router, do not delete it.  Instead, reset the GC
 			 * timer using the router's lifetime.
 			 * Simply deleting the entry would affect default
@@ -1221,17 +1218,16 @@ nd6_free(struct llentry *ln, int gc)
 			 * XXX: the check for ln_state would be redundant,
 			 *      but we intentionally keep it just in case.
 			 */
-			if (dr->expire > time_uptime)
+			if (ln->ln_expire > time_uptime)
 				nd6_llinfo_settimer(ln,
-				    (dr->expire - time_uptime) * hz);
+				    (ln->ln_expire - time_uptime) * hz);
 			else
 				nd6_llinfo_settimer(ln, nd6_gctimer * hz);
-			ND6_UNLOCK();
 			LLE_WUNLOCK(ln);
 			return;
 		}
 
-		if (ln->ln_router || dr) {
+		if (ln->ln_router) {
 			/*
 			 * We need to unlock to avoid a LOR with nd6_rt_flush()
 			 * with the rnh and for the calls to
@@ -1247,9 +1243,7 @@ nd6_free(struct llentry *ln, int gc)
 			 * See a corresponding comment in nd6_na_input().
 			 */
 			nd6_rt_flush(in6, ifp);
-		}
 
-		if (dr) {
 			/*
 			 * Unreachablity of a router might affect the default
 			 * router selection and on-link detection of advertised
@@ -1263,7 +1257,9 @@ nd6_free(struct llentry *ln, int gc)
 			 * Below the state will be set correctly,
 			 * or the entry itself will be deleted.
 			 */
+			LLE_WLOCK(ln);
 			ln->ln_state = ND6_LLINFO_INCOMPLETE;
+			LLE_WUNLOCK(ln);
 
 			/*
 			 * Since nd6_defrouter_select() does not affect the
@@ -1287,12 +1283,13 @@ nd6_free(struct llentry *ln, int gc)
 		if (ln->la_flags & LLE_REDIRECT)
 			nd6_free_redirect(ln);
 #endif
-		ND6_UNLOCK();
-
-		if (ln->ln_router || dr)
+		if (ln->ln_router)
 			LLE_WLOCK(ln);
 	}
 
+	rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6),
+	    (const uint8_t *)&ln->ll_addr, ifp);
+
 	/*
 	 * Save to unlock. We still hold an extra reference and will not
 	 * free(9) in llentry_free() if someone else holds one as well.
@@ -2225,11 +2222,13 @@ nd6_cache_lladdr(
 		break;
 	}
 
-#if 0
-	/* XXX should we send rtmsg as it used to be? */
-	if (do_update)
-		rt_newmsg(RTM_CHANGE, rt);  /* tell user process */
-#endif
+	if (do_update) {
+		struct sockaddr_in6 sin6;
+
+		sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0);
+		rt_clonedmsg(is_newentry ? RTM_ADD : RTM_CHANGE,
+		    sin6tosa(&sin6), lladdr, ifp);
+	}
 
 	if (ln != NULL) {
 		router = ln->ln_router;
@@ -2357,7 +2356,8 @@ nd6_resolve(struct ifnet *ifp, const str
 		}
 
 		sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0);
-		rt_clonedmsg(sin6tosa(&sin6), ifp, rt);
+		if (rt != NULL)
+			rt_clonedmsg(RTM_ADD, sin6tosa(&sin6), NULL, ifp);
 
 		created = true;
 	}
Index: sys/netinet6/nd6_nbr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.166
diff -u -p -r1.166 nd6_nbr.c
--- sys/netinet6/nd6_nbr.c	29 Apr 2019 16:12:30 -0000	1.166
+++ sys/netinet6/nd6_nbr.c	22 Aug 2019 17:57:14 -0000
@@ -883,11 +883,13 @@ nd6_na_input(struct mbuf *m, int off, in
 	 */
 	ln->ln_asked = 0;
 	nd6_llinfo_release_pkts(ln, ifp);
-	/* FIXME */
-#if 0
-	if (rt_announce) /* tell user process about any new lladdr */
-		rt_newmsg(RTM_CHANGE, rt);
-#endif
+
+	if (rt_announce) {
+		struct sockaddr_in6 sin6;
+
+		sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0);
+		rt_clonedmsg(RTM_CHANGE, sin6tosa(&sin6), lladdr, ifp);
+	}
 
  freeit:
 	if (ln != NULL)


Home | Main Index | Thread Index | Old Index