Module Name:    src
Committed By:   knakahara
Date:           Tue Sep 20 02:23:38 UTC 2022

Modified Files:
        src/sys/net: if.c route.c route.h
        src/sys/netinet: in.c
        src/sys/netinet6: in6.c
        src/sys/nfs: nfs_boot.c

Log Message:
Remove routes on an address removal if the routes referencing to the address.  
Implemented by ozaki-r@n.o.

A route that has a gateway is on a connected route can be invalid if the
connected route is deleted, i.e., an associated address is removed.
Traditionally NetBSD doesn't sweep such a route on the address removal.  Sending
packets over the route fails with "No route to host".  Also the route holds an
orphan ifaddr as rt_ifa that is destructed say by in_purgeaddr.

If the same address is assgined again in such a state, there can be two
different ifaddr objects with the same address.  Until recently it's not a
big problem because we can send packets anyway.  However after MP-ification
of the network stack, we can't send packets because we strictly check if rt_ifa
(i.e., the (old) ifaddr) is valid.

This change automatically removes such routes on a removal of an associated
address to avoid keeping inconsistent routes.


To generate a diff of this commit:
cvs rdiff -u -r1.525 -r1.526 src/sys/net/if.c
cvs rdiff -u -r1.233 -r1.234 src/sys/net/route.c
cvs rdiff -u -r1.131 -r1.132 src/sys/net/route.h
cvs rdiff -u -r1.242 -r1.243 src/sys/netinet/in.c
cvs rdiff -u -r1.285 -r1.286 src/sys/netinet6/in6.c
cvs rdiff -u -r1.88 -r1.89 src/sys/nfs/nfs_boot.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.525 src/sys/net/if.c:1.526
--- src/sys/net/if.c:1.525	Sat Sep  3 02:53:18 2022
+++ src/sys/net/if.c	Tue Sep 20 02:23:37 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.525 2022/09/03 02:53:18 thorpej Exp $	*/
+/*	$NetBSD: if.c,v 1.526 2022/09/20 02:23:37 knakahara Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.525 2022/09/03 02:53:18 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.526 2022/09/20 02:23:37 knakahara Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -1479,7 +1479,7 @@ restart:
 
 	/* Delete stray routes from the routing table. */
 	for (i = 0; i <= AF_MAX; i++)
-		rt_delete_matched_entries(i, if_delroute_matcher, ifp);
+		rt_delete_matched_entries(i, if_delroute_matcher, ifp, false);
 
 	DOMAIN_FOREACH(dp) {
 		if (dp->dom_ifdetach != NULL && ifp->if_afdata[dp->dom_family])

Index: src/sys/net/route.c
diff -u src/sys/net/route.c:1.233 src/sys/net/route.c:1.234
--- src/sys/net/route.c:1.233	Mon Aug 29 23:48:18 2022
+++ src/sys/net/route.c	Tue Sep 20 02:23:37 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.c,v 1.233 2022/08/29 23:48:18 knakahara Exp $	*/
+/*	$NetBSD: route.c,v 1.234 2022/09/20 02:23:37 knakahara Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.233 2022/08/29 23:48:18 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.234 2022/09/20 02:23:37 knakahara Exp $");
 
 #include <sys/param.h>
 #ifdef RTFLUSH_DEBUG
@@ -2291,7 +2291,7 @@ rt_check_reject_route(const struct rtent
 
 void
 rt_delete_matched_entries(sa_family_t family, int (*f)(struct rtentry *, void *),
-    void *v)
+    void *v, bool notify)
 {
 
 	for (;;) {
@@ -2308,6 +2308,7 @@ rt_delete_matched_entries(sa_family_t fa
 			return;
 		}
 		rt_ref(rt);
+		RT_REFCNT_TRACE(rt);
 		splx(s);
 		RT_UNLOCK();
 
@@ -2316,12 +2317,16 @@ rt_delete_matched_entries(sa_family_t fa
 		if (error == 0) {
 			KASSERT(retrt == rt);
 			KASSERT((retrt->rt_flags & RTF_UP) == 0);
+			if (notify)
+				rt_newmsg(RTM_DELETE, retrt);
 			retrt->rt_ifp = NULL;
 			rt_unref(rt);
+			RT_REFCNT_TRACE(rt);
 			rt_free(retrt);
 		} else if (error == ESRCH) {
 			/* Someone deleted the entry already. */
 			rt_unref(rt);
+			RT_REFCNT_TRACE(rt);
 		} else {
 			log(LOG_ERR, "%s: unable to delete rtentry @ %p, "
 			    "error = %d\n", rt->rt_ifp->if_xname, rt, error);
@@ -2338,6 +2343,53 @@ rt_walktree_locked(sa_family_t family, i
 	return rtbl_walktree(family, f, v);
 }
 
+void
+rt_replace_ifa_matched_entries(sa_family_t family,
+    int (*f)(struct rtentry *, void *), void *v, struct ifaddr *ifa)
+{
+
+	for (;;) {
+		int s;
+#ifdef NET_MPSAFE
+		int error;
+#endif
+		struct rtentry *rt;
+
+		RT_RLOCK();
+		s = splsoftnet();
+		rt = rtbl_search_matched_entry(family, f, v);
+		if (rt == NULL) {
+			splx(s);
+			RT_UNLOCK();
+			return;
+		}
+		rt_ref(rt);
+		RT_REFCNT_TRACE(rt);
+		splx(s);
+		RT_UNLOCK();
+
+#ifdef NET_MPSAFE
+		error = rt_update_prepare(rt);
+		if (error == 0) {
+			rt_replace_ifa(rt, ifa);
+			rt_update_finish(rt);
+			rt_newmsg(RTM_CHANGE, rt);
+		} else {
+			/*
+			 * If error != 0, the rtentry is being
+			 * destroyed, so doing nothing doesn't
+			 * matter.
+			 */
+		}
+#else
+		rt_replace_ifa(rt, ifa);
+		rt_newmsg(RTM_CHANGE, rt);
+#endif
+		rt_unref(rt);
+		RT_REFCNT_TRACE(rt);
+	}
+}
+
 int
 rt_walktree(sa_family_t family, int (*f)(struct rtentry *, void *), void *v)
 {

Index: src/sys/net/route.h
diff -u src/sys/net/route.h:1.131 src/sys/net/route.h:1.132
--- src/sys/net/route.h:1.131	Mon Aug 29 09:14:02 2022
+++ src/sys/net/route.h	Tue Sep 20 02:23:37 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.h,v 1.131 2022/08/29 09:14:02 knakahara Exp $	*/
+/*	$NetBSD: route.h,v 1.132 2022/09/20 02:23:37 knakahara Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -463,7 +463,9 @@ struct sockaddr *
 
 int	rt_check_reject_route(const struct rtentry *, const struct ifnet *);
 void	rt_delete_matched_entries(sa_family_t,
-	    int (*)(struct rtentry *, void *), void *);
+	    int (*)(struct rtentry *, void *), void *, bool);
+void	rt_replace_ifa_matched_entries(sa_family_t,
+	    int (*)(struct rtentry *, void *), void *, struct ifaddr *);
 int	rt_walktree(sa_family_t, int (*)(struct rtentry *, void *), void *);
 
 static __inline void

Index: src/sys/netinet/in.c
diff -u src/sys/netinet/in.c:1.242 src/sys/netinet/in.c:1.243
--- src/sys/netinet/in.c:1.242	Tue Sep 21 15:05:41 2021
+++ src/sys/netinet/in.c	Tue Sep 20 02:23:37 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: in.c,v 1.242 2021/09/21 15:05:41 christos Exp $	*/
+/*	$NetBSD: in.c,v 1.243 2022/09/20 02:23:37 knakahara Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.242 2021/09/21 15:05:41 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.243 2022/09/20 02:23:37 knakahara Exp $");
 
 #include "arp.h"
 
@@ -1347,6 +1347,17 @@ in_addprefix(struct in_ifaddr *target, i
 	return error;
 }
 
+static int
+in_rt_ifa_matcher(struct rtentry *rt, void *v)
+{
+	struct ifaddr *ifa = v;
+
+	if (rt->rt_ifa == ifa)
+		return 1;
+	else
+		return 0;
+}
+
 /*
  * remove a route to prefix ("connected route" in cisco terminology).
  * re-installs the route by using another interface address, if there's one
@@ -1403,6 +1414,16 @@ in_scrubprefix(struct in_ifaddr *target)
 			if (error == 0)
 				ia->ia_flags |= IFA_ROUTE;
 
+			if (!ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING))
+				goto skip;
+			/*
+			 * Replace rt_ifa of routes that have the removing address
+			 * with the new address.
+			 */
+			rt_replace_ifa_matched_entries(AF_INET,
+			    in_rt_ifa_matcher, &target->ia_ifa, &ia->ia_ifa);
+
+		skip:
 			ia4_release(ia, &psref);
 			curlwp_bindx(bound);
 
@@ -1416,6 +1437,13 @@ in_scrubprefix(struct in_ifaddr *target)
 	 */
 	rtinit(&target->ia_ifa, RTM_DELETE, rtinitflags(target));
 	target->ia_flags &= ~IFA_ROUTE;
+
+	if (ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING)) {
+		/* Remove routes that have the removing address as rt_ifa. */
+		rt_delete_matched_entries(AF_INET, in_rt_ifa_matcher,
+		    &target->ia_ifa, true);
+	}
+
 	return 0;
 }
 

Index: src/sys/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.285 src/sys/netinet6/in6.c:1.286
--- src/sys/netinet6/in6.c:1.285	Sun Dec  5 04:42:55 2021
+++ src/sys/netinet6/in6.c	Tue Sep 20 02:23:37 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.285 2021/12/05 04:42:55 msaitoh Exp $	*/
+/*	$NetBSD: in6.c,v 1.286 2022/09/20 02:23:37 knakahara Exp $	*/
 /*	$KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.285 2021/12/05 04:42:55 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.286 2022/09/20 02:23:37 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -279,6 +279,17 @@ in6_ifaddprefix(struct in6_ifaddr *ia)
 	return error;
 }
 
+static int
+in6_rt_ifa_matcher(struct rtentry *rt, void *v)
+{
+	struct ifaddr *ifa = v;
+
+	if (rt->rt_ifa == ifa)
+		return 1;
+	else
+		return 0;
+}
+
 /* Delete network prefix route if present.
  * Re-add it to another address if the prefix matches. */
 static int
@@ -319,6 +330,16 @@ in6_ifremprefix(struct in6_ifaddr *targe
 
 			error = in6_ifaddprefix(ia);
 
+			if (!ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING))
+				goto skip;
+			/*
+			 * Replace rt_ifa of routes that have the removing address
+			 * with the new address.
+			 */
+			rt_replace_ifa_matched_entries(AF_INET6,
+			    in6_rt_ifa_matcher, &target->ia_ifa, &ia->ia_ifa);
+
+		skip:
 			ia6_release(ia, &psref);
 			curlwp_bindx(bound);
 
@@ -332,6 +353,13 @@ in6_ifremprefix(struct in6_ifaddr *targe
 	 */
 	rtinit(&target->ia_ifa, RTM_DELETE, 0);
 	target->ia_flags &= ~IFA_ROUTE;
+
+	if (ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING)) {
+		/* Remove routes that have the removing address as rt_ifa. */
+		rt_delete_matched_entries(AF_INET6, in6_rt_ifa_matcher,
+		    &target->ia_ifa, true);
+	}
+
 	return 0;
 }
 

Index: src/sys/nfs/nfs_boot.c
diff -u src/sys/nfs/nfs_boot.c:1.88 src/sys/nfs/nfs_boot.c:1.89
--- src/sys/nfs/nfs_boot.c:1.88	Thu May 17 02:34:31 2018
+++ src/sys/nfs/nfs_boot.c	Tue Sep 20 02:23:37 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_boot.c,v 1.88 2018/05/17 02:34:31 thorpej Exp $	*/
+/*	$NetBSD: nfs_boot.c,v 1.89 2022/09/20 02:23:37 knakahara Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.88 2018/05/17 02:34:31 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.89 2022/09/20 02:23:37 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_nfs.h"
@@ -576,7 +576,7 @@ void
 nfs_boot_flushrt(struct ifnet *ifp)
 {
 
-	rt_delete_matched_entries(AF_INET, nfs_boot_delroute_matcher, ifp);
+	rt_delete_matched_entries(AF_INET, nfs_boot_delroute_matcher, ifp, false);
 }
 
 /*

Reply via email to