Module Name:    src
Committed By:   martin
Date:           Tue Nov  6 14:38:58 UTC 2018

Modified Files:
        src/sys/net [netbsd-8]: if.c route.c route.h
        src/sys/netinet [netbsd-8]: if_arp.c
        src/sys/netinet6 [netbsd-8]: in6.c nd6.c

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #1080):

        sys/netinet6/nd6.c: revision 1.251
        sys/netinet/if_arp.c: revision 1.276
        sys/net/if.c: revision 1.438
        sys/net/if.c: revision 1.439
        sys/net/route.c: revision 1.214
        sys/net/route.c: revision 1.215
        sys/net/route.c: revision 1.216
        sys/netinet6/in6.c: revision 1.270
        sys/net/route.h: revision 1.120
        sys/net/if.c: revision 1.440

Remove a wrong assertion in ifaref

 -

Doing ifref on an ifa with IFA_DESTROYING is not a problem; the reference should
be dropped during the destruction of the ifa.

 -

Use atomic operations for ifa_refcnt

 -

Avoid a dangling pointer during rt_replace_ifa

 -

Avoid double rt_replace_ifa on rtrequest1(RTM_ADD)

Some callers of rtrequest1(RTM_ADD) adjust rt_ifa of an rtentry created by
rtrequest1 that may change rt_ifa (in ifa_rtrequest) with another ifa that is
different from requested one.  It's wasteful and even worse introduces a race
condition.  rtrequest1 should just use a passed ifa as is if a caller hopes so.

 -

Use rt_update framework on updating a rtentry


To generate a diff of this commit:
cvs rdiff -u -r1.394.2.14 -r1.394.2.15 src/sys/net/if.c
cvs rdiff -u -r1.194.6.11 -r1.194.6.12 src/sys/net/route.c
cvs rdiff -u -r1.112.4.4 -r1.112.4.5 src/sys/net/route.h
cvs rdiff -u -r1.250.2.8 -r1.250.2.9 src/sys/netinet/if_arp.c
cvs rdiff -u -r1.245.2.11 -r1.245.2.12 src/sys/netinet6/in6.c
cvs rdiff -u -r1.232.2.8 -r1.232.2.9 src/sys/netinet6/nd6.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.394.2.14 src/sys/net/if.c:1.394.2.15
--- src/sys/net/if.c:1.394.2.14	Mon Aug 27 07:49:11 2018
+++ src/sys/net/if.c	Tue Nov  6 14:38:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.394.2.14 2018/08/27 07:49:11 martin Exp $	*/
+/*	$NetBSD: if.c,v 1.394.2.15 2018/11/06 14:38:58 martin 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.394.2.14 2018/08/27 07:49:11 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.394.2.15 2018/11/06 14:38:58 martin Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -1777,8 +1777,8 @@ ifa_psref_init(struct ifaddr *ifa)
 void
 ifaref(struct ifaddr *ifa)
 {
-	KASSERT(!ISSET(ifa->ifa_flags, IFA_DESTROYING));
-	ifa->ifa_refcnt++;
+
+	atomic_inc_uint(&ifa->ifa_refcnt);
 }
 
 void
@@ -1787,7 +1787,7 @@ ifafree(struct ifaddr *ifa)
 	KASSERT(ifa != NULL);
 	KASSERT(ifa->ifa_refcnt > 0);
 
-	if (--ifa->ifa_refcnt == 0) {
+	if (atomic_dec_uint_nv(&ifa->ifa_refcnt) == 0) {
 		free(ifa, M_IFADDR);
 	}
 }
@@ -2177,7 +2177,8 @@ link_rtrequest(int cmd, struct rtentry *
 	struct psref psref;
 
 	if (cmd != RTM_ADD || (ifa = rt->rt_ifa) == NULL ||
-	    (ifp = ifa->ifa_ifp) == NULL || (dst = rt_getkey(rt)) == NULL)
+	    (ifp = ifa->ifa_ifp) == NULL || (dst = rt_getkey(rt)) == NULL ||
+	    ISSET(info->rti_flags, RTF_DONTCHANGEIFA))
 		return;
 	if ((ifa = ifaof_ifpforaddr_psref(dst, ifp, &psref)) != NULL) {
 		rt_replace_ifa(rt, ifa);
@@ -2431,6 +2432,9 @@ p2p_rtrequest(int req, struct rtentry *r
 
 		rt->rt_ifp = lo0ifp;
 
+		if (ISSET(info->rti_flags, RTF_DONTCHANGEIFA))
+			break;
+
 		IFADDR_READER_FOREACH(ifa, ifp) {
 			if (equal(rt_getkey(rt), ifa->ifa_addr))
 				break;

Index: src/sys/net/route.c
diff -u src/sys/net/route.c:1.194.6.11 src/sys/net/route.c:1.194.6.12
--- src/sys/net/route.c:1.194.6.11	Fri Sep  7 12:31:30 2018
+++ src/sys/net/route.c	Tue Nov  6 14:38:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.c,v 1.194.6.11 2018/09/07 12:31:30 martin Exp $	*/
+/*	$NetBSD: route.c,v 1.194.6.12 2018/11/06 14:38:58 martin 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.194.6.11 2018/09/07 12:31:30 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.194.6.12 2018/11/06 14:38:58 martin Exp $");
 
 #include <sys/param.h>
 #ifdef RTFLUSH_DEBUG
@@ -406,6 +406,11 @@ rt_ifa_connected(const struct rtentry *r
 void
 rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa)
 {
+	struct ifaddr *old;
+
+	if (rt->rt_ifa == ifa)
+		return;
+
 	if (rt->rt_ifa &&
 	    rt->rt_ifa != ifa &&
 	    rt->rt_ifa->ifa_flags & IFA_ROUTE &&
@@ -424,8 +429,9 @@ rt_replace_ifa(struct rtentry *rt, struc
 	}
 
 	ifaref(ifa);
-	ifafree(rt->rt_ifa);
+	old = rt->rt_ifa;
 	rt_set_ifa1(rt, ifa);
+	ifafree(old);
 }
 
 static void
@@ -1236,7 +1242,7 @@ rtrequest1(int req, struct rt_addrinfo *
 		if (rt == NULL)
 			senderr(ENOBUFS);
 		memset(rt, 0, sizeof(*rt));
-		rt->rt_flags = RTF_UP | flags;
+		rt->rt_flags = RTF_UP | (flags & ~RTF_DONTCHANGEIFA);
 		LIST_INIT(&rt->rt_timer);
 
 		RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
@@ -1599,7 +1605,7 @@ rtinit(struct ifaddr *ifa, int cmd, int 
 	}
 	memset(&info, 0, sizeof(info));
 	info.rti_ifa = ifa;
-	info.rti_flags = flags | ifa->ifa_flags;
+	info.rti_flags = flags | ifa->ifa_flags | RTF_DONTCHANGEIFA;
 	info.rti_info[RTAX_DST] = dst;
 	info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
 
@@ -1630,40 +1636,7 @@ rtinit(struct ifaddr *ifa, int cmd, int 
 		rt_unref(rt);
 		break;
 	case RTM_ADD:
-		/*
-		 * XXX it looks just reverting rt_ifa replaced by ifa_rtrequest
-		 * called via rtrequest1. Can we just prevent the replacement
-		 * somehow and remove the following code? And also doesn't
-		 * calling ifa_rtrequest(RTM_ADD) replace rt_ifa again?
-		 */
-		if (rt->rt_ifa != ifa) {
-			printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
-				rt->rt_ifa);
-#ifdef NET_MPSAFE
-			KASSERT(!cpu_softintr_p());
-
-			error = rt_update_prepare(rt);
-			if (error == 0) {
-#endif
-				if (rt->rt_ifa->ifa_rtrequest != NULL) {
-					rt->rt_ifa->ifa_rtrequest(RTM_DELETE,
-					    rt, &info);
-				}
-				rt_replace_ifa(rt, ifa);
-				rt->rt_ifp = ifa->ifa_ifp;
-				if (ifa->ifa_rtrequest != NULL)
-					ifa->ifa_rtrequest(RTM_ADD, rt, &info);
-#ifdef NET_MPSAFE
-				rt_update_finish(rt);
-			} else {
-				/*
-				 * If error != 0, the rtentry is being
-				 * destroyed, so doing nothing doesn't
-				 * matter.
-				 */
-			}
-#endif
-		}
+		KASSERT(rt->rt_ifa == ifa);
 		rt_newmsg(cmd, rt);
 		rt_unref(rt);
 		RT_REFCNT_TRACE(rt);
@@ -1695,17 +1668,16 @@ rt_ifa_addlocal(struct ifaddr *ifa)
 		struct rtentry *nrt;
 
 		memset(&info, 0, sizeof(info));
-		info.rti_flags = RTF_HOST | RTF_LOCAL;
+		info.rti_flags = RTF_HOST | RTF_LOCAL | RTF_DONTCHANGEIFA;
 		info.rti_info[RTAX_DST] = ifa->ifa_addr;
 		info.rti_info[RTAX_GATEWAY] =
 		    (const struct sockaddr *)ifa->ifa_ifp->if_sadl;
 		info.rti_ifa = ifa;
 		nrt = NULL;
 		e = rtrequest1(RTM_ADD, &info, &nrt);
-		if (nrt && ifa != nrt->rt_ifa)
-			rt_replace_ifa(nrt, ifa);
 		rt_newaddrmsg(RTM_ADD, ifa, e, nrt);
 		if (nrt != NULL) {
+			KASSERT(nrt->rt_ifa == ifa);
 #ifdef RT_DEBUG
 			dump_rt(nrt);
 #endif
@@ -1758,7 +1730,21 @@ rt_ifa_remlocal(struct ifaddr *ifa, stru
 			}
 			rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
 		} else {
+#ifdef NET_MPSAFE
+			int error = rt_update_prepare(rt);
+			if (error == 0) {
+				rt_replace_ifa(rt, alt_ifa);
+				rt_update_finish(rt);
+			} else {
+				/*
+				 * If error != 0, the rtentry is being
+				 * destroyed, so doing nothing doesn't
+				 * matter.
+				 */
+			}
+#else
 			rt_replace_ifa(rt, alt_ifa);
+#endif
 			rt_newmsg(RTM_CHANGE, rt);
 		}
 	} else

Index: src/sys/net/route.h
diff -u src/sys/net/route.h:1.112.4.4 src/sys/net/route.h:1.112.4.5
--- src/sys/net/route.h:1.112.4.4	Sat Apr 14 10:16:19 2018
+++ src/sys/net/route.h	Tue Nov  6 14:38:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.h,v 1.112.4.4 2018/04/14 10:16:19 martin Exp $	*/
+/*	$NetBSD: route.h,v 1.112.4.5 2018/11/06 14:38:58 martin Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -172,6 +172,11 @@ struct ortentry {
 #define RTF_LOCAL	0x40000		/* route represents a local address */
 #define RTF_BROADCAST	0x80000		/* route represents a bcast address */
 #define RTF_UPDATING	0x100000	/* route is updating */
+/*
+ * The flag is nevert set to rt_flags.  It just tells rtrequest1 to set a passed
+ * ifa to rt_ifa (via rti_ifa) and not replace rt_ifa in ifa_rtrequest.
+ */
+#define RTF_DONTCHANGEIFA	0x200000	/* suppress rt_ifa replacement */
 
 /*
  * Routing statistics.

Index: src/sys/netinet/if_arp.c
diff -u src/sys/netinet/if_arp.c:1.250.2.8 src/sys/netinet/if_arp.c:1.250.2.9
--- src/sys/netinet/if_arp.c:1.250.2.8	Mon Apr  2 08:54:35 2018
+++ src/sys/netinet/if_arp.c	Tue Nov  6 14:38:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.c,v 1.250.2.8 2018/04/02 08:54:35 martin Exp $	*/
+/*	$NetBSD: if_arp.c,v 1.250.2.9 2018/11/06 14:38:58 martin Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.250.2.8 2018/04/02 08:54:35 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.250.2.9 2018/11/06 14:38:58 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -603,6 +603,11 @@ arp_rtrequest(int req, struct rtentry *r
 			rt->rt_rmx.rmx_mtu = 0;
 		}
 		rt->rt_flags |= RTF_LOCAL;
+
+		if (ISSET(info->rti_flags, RTF_DONTCHANGEIFA)) {
+			pserialize_read_exit(s);
+			goto out;
+		}
 		/*
 		 * make sure to set rt->rt_ifa to the interface
 		 * address we are using, otherwise we will have trouble

Index: src/sys/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.245.2.11 src/sys/netinet6/in6.c:1.245.2.12
--- src/sys/netinet6/in6.c:1.245.2.11	Thu Jun  7 17:48:31 2018
+++ src/sys/netinet6/in6.c	Tue Nov  6 14:38:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.245.2.11 2018/06/07 17:48:31 martin Exp $	*/
+/*	$NetBSD: in6.c,v 1.245.2.12 2018/11/06 14:38:58 martin 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.245.2.11 2018/06/07 17:48:31 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.12 2018/11/06 14:38:58 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -869,8 +869,23 @@ in6_join_mcastgroups(struct in6_aliasreq
 			    ntohs(mltaddr.sin6_addr.s6_addr16[1]),
 			    satocsin6(rt_getkey(rt))->sin6_addr.s6_addr16[0],
 			    satocsin6(rt_getkey(rt))->sin6_addr.s6_addr16[1]);
+#ifdef NET_MPSAFE
+			error = rt_update_prepare(rt);
+			if (error == 0) {
+				rt_replace_ifa(rt, &ia->ia_ifa);
+				rt->rt_ifp = ifp;
+				rt_update_finish(rt);
+			} else {
+				/*
+				 * If error != 0, the rtentry is being
+				 * destroyed, so doing nothing doesn't
+				 * matter.
+				 */
+			}
+#else
 			rt_replace_ifa(rt, &ia->ia_ifa);
 			rt->rt_ifp = ifp;
+#endif
 		}
 	}
 	if (!rt) {
@@ -953,8 +968,23 @@ in6_join_mcastgroups(struct in6_aliasreq
 			    ntohs(mltaddr.sin6_addr.s6_addr16[1]),
 			    satocsin6(rt_getkey(rt))->sin6_addr.s6_addr16[0],
 			    satocsin6(rt_getkey(rt))->sin6_addr.s6_addr16[1]);
+#ifdef NET_MPSAFE
+			error = rt_update_prepare(rt);
+			if (error == 0) {
+				rt_replace_ifa(rt, &ia->ia_ifa);
+				rt->rt_ifp = ifp;
+				rt_update_finish(rt);
+			} else {
+				/*
+				 * If error != 0, the rtentry is being
+				 * destroyed, so doing nothing doesn't
+				 * matter.
+				 */
+			}
+#else
 			rt_replace_ifa(rt, &ia->ia_ifa);
 			rt->rt_ifp = ifp;
+#endif
 		}
 	}
 	if (!rt) {

Index: src/sys/netinet6/nd6.c
diff -u src/sys/netinet6/nd6.c:1.232.2.8 src/sys/netinet6/nd6.c:1.232.2.9
--- src/sys/netinet6/nd6.c:1.232.2.8	Thu Jun  7 17:48:31 2018
+++ src/sys/netinet6/nd6.c	Tue Nov  6 14:38:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6.c,v 1.232.2.8 2018/06/07 17:48:31 martin Exp $	*/
+/*	$NetBSD: nd6.c,v 1.232.2.9 2018/11/06 14:38:58 martin Exp $	*/
 /*	$KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.8 2018/06/07 17:48:31 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.9 2018/11/06 14:38:58 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -1567,7 +1567,8 @@ nd6_rtrequest(int req, struct rtentry *r
 				 * that the rt_ifa points to the address instead
 				 * of the loopback address.
 				 */
-				if (ifa != rt->rt_ifa)
+				if (!ISSET(info->rti_flags, RTF_DONTCHANGEIFA)
+				    && ifa != rt->rt_ifa)
 					rt_replace_ifa(rt, ifa);
 			}
 		} else if (rt->rt_flags & RTF_ANNOUNCE) {

Reply via email to