Module Name:    src
Committed By:   snj
Date:           Tue Oct 24 08:55:56 UTC 2017

Modified Files:
        src/distrib/sets/lists/tests [netbsd-8]: mi
        src/sys/net [netbsd-8]: route.c route.h
        src/sys/netatalk [netbsd-8]: at_proto.c
        src/sys/netinet [netbsd-8]: in_proto.c
        src/sys/netinet6 [netbsd-8]: in6_proto.c
        src/sys/netmpls [netbsd-8]: mpls_proto.c
        src/sys/netnatm [netbsd-8]: natm_proto.c
        src/sys/rump/net/lib/libsockin [netbsd-8]: sockin.c
        src/sys/sys [netbsd-8]: domain.h
        src/tests/net/route [netbsd-8]: Makefile
Added Files:
        src/tests/net/route [netbsd-8]: t_rtcache.sh

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #305):
        distrib/sets/lists/tests/mi: revision 1.762
        sys/net/route.c: revision 1.198-1.201
        sys/net/route.h: revision 1.114
        sys/netatalk/at_proto.c: revision 1.22
        sys/netinet/in_proto.c: revision 1.124
        sys/netinet6/in6_proto.c: revision 1.118
        sys/netmpls/mpls_proto.c: revision 1.31
        sys/netnatm/natm_proto.c: revision 1.18
        sys/rump/net/lib/libsockin/sockin.c: revision 1.65
        sys/sys/domain.h: revision 1.33
        tests/net/route/Makefile: revision 1.6
        tests/net/route/t_rtcache.sh: revision 1.1
Add tests of rtcache invalidation
Remove unnecessary NULL check of rt_ifp
It's always non-NULL.
Invalidate rtcache based on a global generation counter
The change introduces a global generation counter that is incremented when any
routes have been added or deleted. When a rtcache caches a rtentry into itself,
it also stores a snapshot of the generation counter. If the snapshot equals to
the global counter, the cache is still valid, otherwise invalidated.
One drawback of the change is that all rtcaches of all protocol families are
invalidated when any routes of any protocol families are added or deleted.
If that matters, we should have separate generation counters based on
protocol families.
This change removes LIST_ENTRY from struct route, which fixes a part of
PR kern/52515.
Remove the global lock for rtcache
Thanks to removal of LIST_ENTRY of struct route, rtcaches are accessed only by
their users. And in existing usages a rtcache is guranteed to be not accessed
simultaneously. So the rtcache framework doesn't need any exclusion controls
in itself.
Synchronize on rtcache_generation with rtlock
It's racy if NET_MPSAFE is enabled.
Pointed out by joerg@


To generate a diff of this commit:
cvs rdiff -u -r1.752.2.4 -r1.752.2.5 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.194.6.2 -r1.194.6.3 src/sys/net/route.c
cvs rdiff -u -r1.112.4.1 -r1.112.4.2 src/sys/net/route.h
cvs rdiff -u -r1.21 -r1.21.10.1 src/sys/netatalk/at_proto.c
cvs rdiff -u -r1.123.4.1 -r1.123.4.2 src/sys/netinet/in_proto.c
cvs rdiff -u -r1.117.4.1 -r1.117.4.2 src/sys/netinet6/in6_proto.c
cvs rdiff -u -r1.30 -r1.30.8.1 src/sys/netmpls/mpls_proto.c
cvs rdiff -u -r1.17 -r1.17.8.1 src/sys/netnatm/natm_proto.c
cvs rdiff -u -r1.64 -r1.64.8.1 src/sys/rump/net/lib/libsockin/sockin.c
cvs rdiff -u -r1.32 -r1.32.10.1 src/sys/sys/domain.h
cvs rdiff -u -r1.5 -r1.5.6.1 src/tests/net/route/Makefile
cvs rdiff -u -r0 -r1.1.2.2 src/tests/net/route/t_rtcache.sh

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

Modified files:

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.752.2.4 src/distrib/sets/lists/tests/mi:1.752.2.5
--- src/distrib/sets/lists/tests/mi:1.752.2.4	Sat Oct 21 19:43:53 2017
+++ src/distrib/sets/lists/tests/mi	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.752.2.4 2017/10/21 19:43:53 snj Exp $
+# $NetBSD: mi,v 1.752.2.5 2017/10/24 08:55:55 snj Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -3376,6 +3376,7 @@
 ./usr/tests/net/route/t_flags			tests-net-tests		atf,rump
 ./usr/tests/net/route/t_flags6			tests-net-tests		atf,rump
 ./usr/tests/net/route/t_route			tests-net-tests		atf,rump
+./usr/tests/net/route/t_rtcache			tests-net-tests		atf,rump
 ./usr/tests/net/sys				tests-net-tests		compattestfile,atf
 ./usr/tests/net/sys/Atffile			tests-net-tests		compattestfile,atf
 ./usr/tests/net/sys/Kyuafile			tests-net-tests		compattestfile,atf,kyua

Index: src/sys/net/route.c
diff -u src/sys/net/route.c:1.194.6.2 src/sys/net/route.c:1.194.6.3
--- src/sys/net/route.c:1.194.6.2	Fri Jul  7 13:57:26 2017
+++ src/sys/net/route.c	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.c,v 1.194.6.2 2017/07/07 13:57:26 martin Exp $	*/
+/*	$NetBSD: route.c,v 1.194.6.3 2017/10/24 08:55:55 snj 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.2 2017/07/07 13:57:26 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.194.6.3 2017/10/24 08:55:55 snj Exp $");
 
 #include <sys/param.h>
 #ifdef RTFLUSH_DEBUG
@@ -169,8 +169,12 @@ static void	rt_timer_timer(void *);
  * Locking notes:
  * - The routing table is protected by a global rwlock
  *   - API: RT_RLOCK and friends
- * - rtcaches are protected by a global rwlock
- *   - API: RTCACHE_RLOCK and friends
+ * - rtcaches are NOT protected by the framework
+ *   - Callers must guarantee a rtcache isn't accessed simultaneously
+ *   - How the constraint is guranteed in the wild
+ *     - Protect a rtcache by a mutex (e.g., inp_route)
+ *     - Make rtcache per-CPU and allow only accesses from softint
+ *       (e.g., ipforward_rt_percpu)
  * - References to a rtentry is managed by reference counting and psref
  *   - Reference couting is used for temporal reference when a rtentry
  *     is fetched from the routing table
@@ -203,11 +207,17 @@ static void	rt_timer_timer(void *);
  *     - if the caller runs in softint, the caller fails to fetch
  *     - otherwise, the caller waits for the update completed and retries
  *       to fetch (probably succeed to fetch for the second time)
+ * - rtcache invalidation
+ *   - There is a global generation counter that is incremented when
+ *     any routes have been added or deleted
+ *   - When a rtcache caches a rtentry into itself, it also stores
+ *     a snapshot of the generation counter
+ *   - If the snapshot equals to the global counter, the cache is valid,
+ *     otherwise the cache is invalidated
  */
 
 /*
- * Global locks for the routing table and rtcaches.
- * Locking order: rtcache_lock => rt_lock
+ * Global lock for the routing table.
  */
 static krwlock_t		rt_lock __cacheline_aligned;
 #ifdef NET_MPSAFE
@@ -224,20 +234,7 @@ static krwlock_t		rt_lock __cacheline_al
 #define	RT_ASSERT_WLOCK()	do {} while (0)
 #endif
 
-static krwlock_t		rtcache_lock __cacheline_aligned;
-#ifdef NET_MPSAFE
-#define RTCACHE_RLOCK()		rw_enter(&rtcache_lock, RW_READER)
-#define RTCACHE_WLOCK()		rw_enter(&rtcache_lock, RW_WRITER)
-#define RTCACHE_UNLOCK()	rw_exit(&rtcache_lock)
-#define	RTCACHE_ASSERT_WLOCK()	KASSERT(rw_write_held(&rtcache_lock))
-#define	RTCACHE_WLOCKED()	rw_write_held(&rtcache_lock)
-#else
-#define RTCACHE_RLOCK()		do {} while (0)
-#define RTCACHE_WLOCK()		do {} while (0)
-#define RTCACHE_UNLOCK()	do {} while (0)
-#define	RTCACHE_ASSERT_WLOCK()	do {} while (0)
-#define	RTCACHE_WLOCKED()	false
-#endif
+static uint64_t rtcache_generation;
 
 /*
  * mutex and cv that are used to wait for references to a rtentry left
@@ -271,23 +268,16 @@ static int _rtcache_debug = 0;
 static kauth_listener_t route_listener;
 
 static int rtdeletemsg(struct rtentry *);
-static void rtflushall(int);
 
 static void rt_maskedcopy(const struct sockaddr *,
     struct sockaddr *, const struct sockaddr *);
 
-static void rtcache_clear(struct route *);
-static void rtcache_clear_rtentry(int, struct rtentry *);
-static void rtcache_invalidate(struct dom_rtlist *);
+static void rtcache_invalidate(void);
 
 static void rt_ref(struct rtentry *);
 
 static struct rtentry *
     rtalloc1_locked(const struct sockaddr *, int, bool, bool);
-static struct rtentry *
-    rtcache_validate_locked(struct route *);
-static void rtcache_free_locked(struct route *);
-static int rtcache_setdst_locked(struct route *, const struct sockaddr *);
 
 static void rtcache_ref(struct rtentry *, struct route *);
 
@@ -491,38 +481,15 @@ rt_init(void)
 }
 
 static void
-rtflushall(int family)
+rtcache_invalidate(void)
 {
-	struct domain *dom;
+
+	RT_ASSERT_WLOCK();
 
 	if (rtcache_debug())
 		printf("%s: enter\n", __func__);
 
-	if ((dom = pffinddomain(family)) == NULL)
-		return;
-
-	RTCACHE_WLOCK();
-	rtcache_invalidate(&dom->dom_rtcache);
-	RTCACHE_UNLOCK();
-}
-
-static void
-rtcache(struct route *ro)
-{
-	struct domain *dom;
-
-	RTCACHE_ASSERT_WLOCK();
-
-	rtcache_invariants(ro);
-	KASSERT(ro->_ro_rt != NULL);
-	KASSERT(ro->ro_invalid == false);
-	KASSERT(rtcache_getdst(ro) != NULL);
-
-	if ((dom = pffinddomain(rtcache_getdst(ro)->sa_family)) == NULL)
-		return;
-
-	LIST_INSERT_HEAD(&dom->dom_rtcache, ro, ro_rtcache_next);
-	rtcache_invariants(ro);
+	rtcache_generation++;
 }
 
 #ifdef RT_DEBUG
@@ -586,23 +553,14 @@ retry:
 	if (ISSET(rt->rt_flags, RTF_UPDATING) &&
 	    /* XXX updater should be always able to acquire */
 	    curlwp != rt_update_global.lwp) {
-		bool need_lock = false;
 		if (!wait_ok || !rt_wait_ok())
 			goto miss;
 		RT_UNLOCK();
 		splx(s);
 
-		/* XXX need more proper solution */
-		if (RTCACHE_WLOCKED()) {
-			RTCACHE_UNLOCK();
-			need_lock = true;
-		}
-
 		/* We can wait until the update is complete */
 		rt_update_wait();
 
-		if (need_lock)
-			RTCACHE_WLOCK();
 		if (wlock)
 			RT_WLOCK();
 		else
@@ -792,17 +750,14 @@ rt_update_prepare(struct rtentry *rt)
 
 	dlog(LOG_DEBUG, "%s: updating rt=%p lwp=%p\n", __func__, rt, curlwp);
 
-	RTCACHE_WLOCK();
 	RT_WLOCK();
 	/* If the entry is being destroyed, don't proceed the update. */
 	if (!ISSET(rt->rt_flags, RTF_UP)) {
 		RT_UNLOCK();
-		RTCACHE_UNLOCK();
 		return -1;
 	}
 	rt->rt_flags |= RTF_UPDATING;
 	RT_UNLOCK();
-	RTCACHE_UNLOCK();
 
 	mutex_enter(&rt_update_global.lock);
 	while (rt_update_global.ongoing) {
@@ -827,11 +782,9 @@ void
 rt_update_finish(struct rtentry *rt)
 {
 
-	RTCACHE_WLOCK();
 	RT_WLOCK();
 	rt->rt_flags &= ~RTF_UPDATING;
 	RT_UNLOCK();
-	RTCACHE_UNLOCK();
 
 	mutex_enter(&rt_update_global.lock);
 	rt_update_global.ongoing = false;
@@ -1248,10 +1201,10 @@ rtrequest1(int req, struct rt_addrinfo *
 			rt_ref(rt);
 			RT_REFCNT_TRACE(rt);
 		}
+		rtcache_invalidate();
 		RT_UNLOCK();
 		need_unlock = false;
 		rt_timer_remove_all(rt);
-		rtcache_clear_rtentry(dst->sa_family, rt);
 #if defined(INET) || defined(INET6)
 		if (netmask != NULL)
 			lltable_prefix_free(dst->sa_family, dst, netmask, 0);
@@ -1344,9 +1297,9 @@ rtrequest1(int req, struct rt_addrinfo *
 			rt_ref(rt);
 			RT_REFCNT_TRACE(rt);
 		}
+		rtcache_invalidate();
 		RT_UNLOCK();
 		need_unlock = false;
-		rtflushall(dst->sa_family);
 		break;
 	case RTM_GET:
 		if (netmask != NULL) {
@@ -1696,7 +1649,6 @@ rt_timer_init(void)
 
 	/* XXX should be in rt_init */
 	rw_init(&rt_lock);
-	rw_init(&rtcache_lock);
 
 	LIST_INIT(&rttimer_queue_head);
 	callout_init(&rt_timer_ch, CALLOUT_MPSAFE);
@@ -1889,20 +1841,20 @@ _rtcache_init(struct route *ro, int flag
 
 	rtcache_invariants(ro);
 	KASSERT(ro->_ro_rt == NULL);
-	RTCACHE_ASSERT_WLOCK();
 
 	if (rtcache_getdst(ro) == NULL)
 		return NULL;
-	ro->ro_invalid = false;
 	rt = rtalloc1(rtcache_getdst(ro), flag);
-	if (rt != NULL && ISSET(rt->rt_flags, RTF_UP)) {
-		ro->_ro_rt = rt;
-		KASSERT(!ISSET(rt->rt_flags, RTF_UPDATING));
-		rtcache_ref(rt, ro);
-		rt_unref(rt);
-		rtcache(ro);
-	} else if (rt != NULL)
+	if (rt != NULL) {
+		RT_RLOCK();
+		if (ISSET(rt->rt_flags, RTF_UP)) {
+			ro->_ro_rt = rt;
+			ro->ro_rtcache_generation = rtcache_generation;
+			rtcache_ref(rt, ro);
+		}
+		RT_UNLOCK();
 		rt_unref(rt);
+	}
 
 	rtcache_invariants(ro);
 	return ro->_ro_rt;
@@ -1911,32 +1863,23 @@ _rtcache_init(struct route *ro, int flag
 struct rtentry *
 rtcache_init(struct route *ro)
 {
-	struct rtentry *rt;
-	RTCACHE_WLOCK();
-	rt = _rtcache_init(ro, 1);
-	RTCACHE_UNLOCK();
-	return rt;
+
+	return _rtcache_init(ro, 1);
 }
 
 struct rtentry *
 rtcache_init_noclone(struct route *ro)
 {
-	struct rtentry *rt;
-	RTCACHE_WLOCK();
-	rt = _rtcache_init(ro, 0);
-	RTCACHE_UNLOCK();
-	return rt;
+
+	return _rtcache_init(ro, 0);
 }
 
 struct rtentry *
 rtcache_update(struct route *ro, int clone)
 {
-	struct rtentry *rt;
-	RTCACHE_WLOCK();
-	rtcache_clear(ro);
-	rt = _rtcache_init(ro, clone);
-	RTCACHE_UNLOCK();
-	return rt;
+
+	ro->_ro_rt = NULL;
+	return _rtcache_init(ro, clone);
 }
 
 void
@@ -1957,19 +1900,16 @@ rtcache_copy(struct route *new_ro, struc
 	if (ret != 0)
 		goto out;
 
-	RTCACHE_WLOCK();
-	new_ro->ro_invalid = false;
-	if ((new_ro->_ro_rt = rt) != NULL)
-		rtcache(new_ro);
+	RT_RLOCK();
+	new_ro->_ro_rt = rt;
+	new_ro->ro_rtcache_generation = rtcache_generation;
+	RT_UNLOCK();
 	rtcache_invariants(new_ro);
-	RTCACHE_UNLOCK();
 out:
 	rtcache_unref(rt, old_ro);
 	return;
 }
 
-static struct dom_rtlist invalid_routes = LIST_HEAD_INITIALIZER(dom_rtlist);
-
 #if defined(RT_DEBUG) && defined(NET_MPSAFE)
 static void
 rtcache_trace(const char *func, struct rtentry *rt, struct route *ro)
@@ -2012,162 +1952,92 @@ rtcache_unref(struct rtentry *rt, struct
 #endif
 }
 
-static struct rtentry *
-rtcache_validate_locked(struct route *ro)
+struct rtentry *
+rtcache_validate(struct route *ro)
 {
 	struct rtentry *rt = NULL;
 
 #ifdef NET_MPSAFE
 retry:
 #endif
-	rt = ro->_ro_rt;
 	rtcache_invariants(ro);
-
-	if (ro->ro_invalid) {
+	RT_RLOCK();
+	if (ro->ro_rtcache_generation != rtcache_generation) {
+		/* The cache is invalidated */
 		rt = NULL;
 		goto out;
 	}
 
-	RT_RLOCK();
-	if (rt != NULL && (rt->rt_flags & RTF_UP) != 0 && rt->rt_ifp != NULL) {
+	rt = ro->_ro_rt;
+	if (rt == NULL)
+		goto out;
+
+	if ((rt->rt_flags & RTF_UP) == 0) {
+		rt = NULL;
+		goto out;
+	}
 #ifdef NET_MPSAFE
-		if (ISSET(rt->rt_flags, RTF_UPDATING)) {
-			if (rt_wait_ok()) {
-				RT_UNLOCK();
-				RTCACHE_UNLOCK();
-				/* We can wait until the update is complete */
-				rt_update_wait();
-				RTCACHE_RLOCK();
-				goto retry;
-			} else {
-				rt = NULL;
-			}
-		} else
-#endif
-			rtcache_ref(rt, ro);
+	if (ISSET(rt->rt_flags, RTF_UPDATING)) {
+		if (rt_wait_ok()) {
+			RT_UNLOCK();
+
+			/* We can wait until the update is complete */
+			rt_update_wait();
+			goto retry;
+		} else {
+			rt = NULL;
+		}
 	} else
-		rt = NULL;
-	RT_UNLOCK();
+#endif
+		rtcache_ref(rt, ro);
 out:
+	RT_UNLOCK();
 	return rt;
 }
 
 struct rtentry *
-rtcache_validate(struct route *ro)
-{
-	struct rtentry *rt;
-
-	RTCACHE_RLOCK();
-	rt = rtcache_validate_locked(ro);
-	RTCACHE_UNLOCK();
-	return rt;
-}
-
-static void
-rtcache_invalidate(struct dom_rtlist *rtlist)
-{
-	struct route *ro;
-
-	RTCACHE_ASSERT_WLOCK();
-
-	while ((ro = LIST_FIRST(rtlist)) != NULL) {
-		rtcache_invariants(ro);
-		KASSERT(ro->_ro_rt != NULL);
-		ro->ro_invalid = true;
-		LIST_REMOVE(ro, ro_rtcache_next);
-		LIST_INSERT_HEAD(&invalid_routes, ro, ro_rtcache_next);
-		rtcache_invariants(ro);
-	}
-}
-
-static void
-rtcache_clear_rtentry(int family, struct rtentry *rt)
-{
-	struct domain *dom;
-	struct route *ro, *nro;
-
-	if ((dom = pffinddomain(family)) == NULL)
-		return;
-
-	RTCACHE_WLOCK();
-	LIST_FOREACH_SAFE(ro, &dom->dom_rtcache, ro_rtcache_next, nro) {
-		if (ro->_ro_rt == rt)
-			rtcache_clear(ro);
-	}
-	RTCACHE_UNLOCK();
-}
-
-static void
-rtcache_clear(struct route *ro)
-{
-
-	RTCACHE_ASSERT_WLOCK();
-
-	rtcache_invariants(ro);
-	if (ro->_ro_rt == NULL)
-		return;
-
-	LIST_REMOVE(ro, ro_rtcache_next);
-
-	ro->_ro_rt = NULL;
-	ro->ro_invalid = false;
-	rtcache_invariants(ro);
-}
-
-struct rtentry *
 rtcache_lookup2(struct route *ro, const struct sockaddr *dst,
     int clone, int *hitp)
 {
 	const struct sockaddr *odst;
 	struct rtentry *rt = NULL;
 
-	RTCACHE_RLOCK();
 	odst = rtcache_getdst(ro);
-	if (odst == NULL) {
-		RTCACHE_UNLOCK();
-		RTCACHE_WLOCK();
+	if (odst == NULL)
 		goto miss;
-	}
 
 	if (sockaddr_cmp(odst, dst) != 0) {
-		RTCACHE_UNLOCK();
-		RTCACHE_WLOCK();
-		rtcache_free_locked(ro);
+		rtcache_free(ro);
 		goto miss;
 	}
 
-	rt = rtcache_validate_locked(ro);
+	rt = rtcache_validate(ro);
 	if (rt == NULL) {
-		RTCACHE_UNLOCK();
-		RTCACHE_WLOCK();
-		rtcache_clear(ro);
+		ro->_ro_rt = NULL;
 		goto miss;
 	}
 
 	rtcache_invariants(ro);
 
-	RTCACHE_UNLOCK();
 	if (hitp != NULL)
 		*hitp = 1;
 	return rt;
 miss:
 	if (hitp != NULL)
 		*hitp = 0;
-	if (rtcache_setdst_locked(ro, dst) == 0)
+	if (rtcache_setdst(ro, dst) == 0)
 		rt = _rtcache_init(ro, clone);
 
 	rtcache_invariants(ro);
 
-	RTCACHE_UNLOCK();
 	return rt;
 }
 
-static void
-rtcache_free_locked(struct route *ro)
+void
+rtcache_free(struct route *ro)
 {
 
-	RTCACHE_ASSERT_WLOCK();
-	rtcache_clear(ro);
+	ro->_ro_rt = NULL;
 	if (ro->ro_sa != NULL) {
 		sockaddr_free(ro->ro_sa);
 		ro->ro_sa = NULL;
@@ -2175,32 +2045,21 @@ rtcache_free_locked(struct route *ro)
 	rtcache_invariants(ro);
 }
 
-void
-rtcache_free(struct route *ro)
-{
-
-	RTCACHE_WLOCK();
-	rtcache_free_locked(ro);
-	RTCACHE_UNLOCK();
-}
-
-static int
-rtcache_setdst_locked(struct route *ro, const struct sockaddr *sa)
+int
+rtcache_setdst(struct route *ro, const struct sockaddr *sa)
 {
 	KASSERT(sa != NULL);
 
-	RTCACHE_ASSERT_WLOCK();
-
 	rtcache_invariants(ro);
 	if (ro->ro_sa != NULL) {
 		if (ro->ro_sa->sa_family == sa->sa_family) {
-			rtcache_clear(ro);
+			ro->_ro_rt = NULL;
 			sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa);
 			rtcache_invariants(ro);
 			return 0;
 		}
 		/* free ro_sa, wrong family */
-		rtcache_free_locked(ro);
+		rtcache_free(ro);
 	}
 
 	KASSERT(ro->_ro_rt == NULL);
@@ -2213,18 +2072,6 @@ rtcache_setdst_locked(struct route *ro, 
 	return 0;
 }
 
-int
-rtcache_setdst(struct route *ro, const struct sockaddr *sa)
-{
-	int error;
-
-	RTCACHE_WLOCK();
-	error = rtcache_setdst_locked(ro, sa);
-	RTCACHE_UNLOCK();
-
-	return error;
-}
-
 const struct sockaddr *
 rt_settag(struct rtentry *rt, const struct sockaddr *tag)
 {

Index: src/sys/net/route.h
diff -u src/sys/net/route.h:1.112.4.1 src/sys/net/route.h:1.112.4.2
--- src/sys/net/route.h:1.112.4.1	Fri Jul  7 13:57:26 2017
+++ src/sys/net/route.h	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.h,v 1.112.4.1 2017/07/07 13:57:26 martin Exp $	*/
+/*	$NetBSD: route.h,v 1.112.4.2 2017/10/24 08:55:55 snj Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -64,8 +64,7 @@
 struct route {
 	struct	rtentry		*_ro_rt;
 	struct	sockaddr	*ro_sa;
-	LIST_ENTRY(route)	ro_rtcache_next;
-	bool			ro_invalid;
+	uint64_t		ro_rtcache_generation;
 	struct	psref		ro_psref;
 	int			ro_bound;
 };
@@ -458,8 +457,8 @@ struct rtentry *
 static inline void
 rtcache_invariants(const struct route *ro)
 {
+
 	KASSERT(ro->ro_sa != NULL || ro->_ro_rt == NULL);
-	KASSERT(!ro->ro_invalid || ro->_ro_rt != NULL);
 }
 
 static inline struct rtentry *

Index: src/sys/netatalk/at_proto.c
diff -u src/sys/netatalk/at_proto.c:1.21 src/sys/netatalk/at_proto.c:1.21.10.1
--- src/sys/netatalk/at_proto.c:1.21	Thu Jan 21 15:41:30 2016
+++ src/sys/netatalk/at_proto.c	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: at_proto.c,v 1.21 2016/01/21 15:41:30 riastradh Exp $	*/
+/*	$NetBSD: at_proto.c,v 1.21.10.1 2017/10/24 08:55:55 snj Exp $	*/
 
 /*
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: at_proto.c,v 1.21 2016/01/21 15:41:30 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: at_proto.c,v 1.21.10.1 2017/10/24 08:55:55 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -78,7 +78,6 @@ struct domain atalkdomain = {
 	.dom_mowner = MOWNER_INIT("",""),
 	.dom_sa_cmpofs = offsetof(struct sockaddr_at, sat_addr),
 	.dom_sa_cmplen = sizeof(struct at_addr),
-	.dom_rtcache = LIST_HEAD_INITIALIZER(atalkdomain.dom_rtcache)
 };
 
 int

Index: src/sys/netinet/in_proto.c
diff -u src/sys/netinet/in_proto.c:1.123.4.1 src/sys/netinet/in_proto.c:1.123.4.2
--- src/sys/netinet/in_proto.c:1.123.4.1	Sat Oct 21 19:43:54 2017
+++ src/sys/netinet/in_proto.c	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_proto.c,v 1.123.4.1 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: in_proto.c,v 1.123.4.2 2017/10/24 08:55:55 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.123.4.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.123.4.2 2017/10/24 08:55:55 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -522,7 +522,6 @@ struct domain inetdomain = {
 	.dom_sa_any = (const struct sockaddr *)&in_any,
 	.dom_sockaddr_const_addr = sockaddr_in_const_addr,
 	.dom_sockaddr_addr = sockaddr_in_addr,
-	.dom_rtcache = LIST_HEAD_INITIALIZER(inetdomain.dom_rtcache)
 };
 
 u_char	ip_protox[IPPROTO_MAX];

Index: src/sys/netinet6/in6_proto.c
diff -u src/sys/netinet6/in6_proto.c:1.117.4.1 src/sys/netinet6/in6_proto.c:1.117.4.2
--- src/sys/netinet6/in6_proto.c:1.117.4.1	Sat Oct 21 19:43:54 2017
+++ src/sys/netinet6/in6_proto.c	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_proto.c,v 1.117.4.1 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: in6_proto.c,v 1.117.4.2 2017/10/24 08:55:55 snj Exp $	*/
 /*	$KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.117.4.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.117.4.2 2017/10/24 08:55:55 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_gateway.h"
@@ -524,7 +524,6 @@ struct domain inet6domain = {
 	.dom_sa_cmplen = sizeof(struct in6_addr),
 	.dom_sa_any = (const struct sockaddr *)&in6_any,
 	.dom_sockaddr_externalize = sockaddr_in6_externalize,
-	.dom_rtcache = LIST_HEAD_INITIALIZER(inet6domain.dom_rtcache)
 };
 
 #if 0

Index: src/sys/netmpls/mpls_proto.c
diff -u src/sys/netmpls/mpls_proto.c:1.30 src/sys/netmpls/mpls_proto.c:1.30.8.1
--- src/sys/netmpls/mpls_proto.c:1.30	Mon Oct  3 11:06:06 2016
+++ src/sys/netmpls/mpls_proto.c	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mpls_proto.c,v 1.30 2016/10/03 11:06:06 ozaki-r Exp $ */
+/*	$NetBSD: mpls_proto.c,v 1.30.8.1 2017/10/24 08:55:55 snj Exp $ */
 
 /*
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpls_proto.c,v 1.30 2016/10/03 11:06:06 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpls_proto.c,v 1.30.8.1 2017/10/24 08:55:55 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -391,5 +391,4 @@ struct domain mplsdomain = {
 	.dom_mowner = MOWNER_INIT("MPLS", ""),
 	.dom_sa_cmpofs = offsetof(struct sockaddr_mpls, smpls_addr),
 	.dom_sa_cmplen = sizeof(union mpls_shim),
-	.dom_rtcache = LIST_HEAD_INITIALIZER(mplsdomain.dom_rtcache)
 };

Index: src/sys/netnatm/natm_proto.c
diff -u src/sys/netnatm/natm_proto.c:1.17 src/sys/netnatm/natm_proto.c:1.17.8.1
--- src/sys/netnatm/natm_proto.c:1.17	Mon Oct  3 11:06:06 2016
+++ src/sys/netnatm/natm_proto.c	Tue Oct 24 08:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: natm_proto.c,v 1.17 2016/10/03 11:06:06 ozaki-r Exp $	*/
+/*	$NetBSD: natm_proto.c,v 1.17.8.1 2017/10/24 08:55:55 snj Exp $	*/
 
 /*
  * Copyright (c) 1996 Charles D. Cranor and Washington University.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: natm_proto.c,v 1.17 2016/10/03 11:06:06 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: natm_proto.c,v 1.17.8.1 2017/10/24 08:55:55 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -105,7 +105,6 @@ struct domain natmdomain = {
 	.dom_protosw = natmsw,
 	.dom_protoswNPROTOSW = &natmsw[sizeof(natmsw)/sizeof(natmsw[0])],
 	.dom_ifqueues = { &natmintrq, NULL },
-	.dom_rtcache = LIST_HEAD_INITIALIZER(natmdomain.dom_rtcache)
 };
 #ifdef NATM_STAT
 u_int natm_sodropcnt = 0;		/* # mbufs dropped due to full sb */

Index: src/sys/rump/net/lib/libsockin/sockin.c
diff -u src/sys/rump/net/lib/libsockin/sockin.c:1.64 src/sys/rump/net/lib/libsockin/sockin.c:1.64.8.1
--- src/sys/rump/net/lib/libsockin/sockin.c:1.64	Tue Nov 15 09:04:30 2016
+++ src/sys/rump/net/lib/libsockin/sockin.c	Tue Oct 24 08:55:56 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sockin.c,v 1.64 2016/11/15 09:04:30 ozaki-r Exp $	*/
+/*	$NetBSD: sockin.c,v 1.64.8.1 2017/10/24 08:55:56 snj Exp $	*/
 
 /*
  * Copyright (c) 2008, 2009 Antti Kantee.  All Rights Reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sockin.c,v 1.64 2016/11/15 09:04:30 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sockin.c,v 1.64.8.1 2017/10/24 08:55:56 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/condvar.h>
@@ -162,7 +162,6 @@ struct domain sockindomain = {
 	.dom_ifqueues = { NULL },
 	.dom_link = { NULL },
 	.dom_mowner = MOWNER_INIT("",""),
-	.dom_rtcache = { NULL },
 	.dom_sockaddr_cmp = NULL
 };
 struct domain sockin6domain = {
@@ -181,7 +180,6 @@ struct domain sockin6domain = {
 	.dom_ifqueues = { NULL },
 	.dom_link = { NULL },
 	.dom_mowner = MOWNER_INIT("",""),
-	.dom_rtcache = { NULL },
 	.dom_sockaddr_cmp = NULL
 };
 

Index: src/sys/sys/domain.h
diff -u src/sys/sys/domain.h:1.32 src/sys/sys/domain.h:1.32.10.1
--- src/sys/sys/domain.h:1.32	Wed Apr 22 19:46:08 2015
+++ src/sys/sys/domain.h	Tue Oct 24 08:55:56 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: domain.h,v 1.32 2015/04/22 19:46:08 roy Exp $	*/
+/*	$NetBSD: domain.h,v 1.32.10.1 2017/10/24 08:55:56 snj Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -90,7 +90,6 @@ struct	domain {
 	struct	mowner dom_mowner;
 	uint_fast8_t	dom_sa_cmpofs;
 	uint_fast8_t	dom_sa_cmplen;
-	struct dom_rtlist dom_rtcache;
 };
 
 STAILQ_HEAD(domainhead,domain);

Index: src/tests/net/route/Makefile
diff -u src/tests/net/route/Makefile:1.5 src/tests/net/route/Makefile:1.5.6.1
--- src/tests/net/route/Makefile:1.5	Thu Nov 24 09:05:17 2016
+++ src/tests/net/route/Makefile	Tue Oct 24 08:55:56 2017
@@ -1,11 +1,11 @@
-#	$NetBSD: Makefile,v 1.5 2016/11/24 09:05:17 ozaki-r Exp $
+#	$NetBSD: Makefile,v 1.5.6.1 2017/10/24 08:55:56 snj Exp $
 #
 
 .include <bsd.own.mk>
 
 TESTSDIR=	${TESTSBASE}/net/route
 
-.for name in change flags flags6 route
+.for name in change flags flags6 route rtcache
 TESTS_SH+=		t_${name}
 TESTS_SH_SRC_t_${name}=	../net_common.sh t_${name}.sh
 .endfor

Added files:

Index: src/tests/net/route/t_rtcache.sh
diff -u /dev/null src/tests/net/route/t_rtcache.sh:1.1.2.2
--- /dev/null	Tue Oct 24 08:55:56 2017
+++ src/tests/net/route/t_rtcache.sh	Tue Oct 24 08:55:56 2017
@@ -0,0 +1,167 @@
+#	$NetBSD: t_rtcache.sh,v 1.1.2.2 2017/10/24 08:55:56 snj Exp $
+#
+# Copyright (c) 2017 Internet Initiative Japan Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+SOCK_SRC=unix://rtcache_src
+SOCK_FWD=unix://rtcache_fwd
+SOCK_DST1=unix://rtcache_dst1
+SOCK_DST2=unix://rtcache_dst2
+
+BUS_SRC=./src
+BUS_DST1=./dst1
+BUS_DST2=./dst2
+
+DEBUG=${DEBUG:-false}
+
+atf_test_case rtcache_invalidation cleanup
+rtcache_invalidation_head()
+{
+
+	atf_set "descr" "Tests for rtcache invalidation"
+	atf_set "require.progs" "rump_server"
+}
+
+rtcache_invalidation_body()
+{
+	local ip_src=10.0.0.2
+	local ip_gwsrc=10.0.0.1
+	local ip_gwdst1=10.0.1.1
+	local ip_gwdst2=10.0.2.1
+	local ip_dst1=10.0.1.2
+	local ip_dst2=10.0.2.2
+	local ip_dst=10.0.3.1
+	local subnet_src=10.0.0.0
+	local subnet_dst=10.0.3.0
+
+	rump_server_start $SOCK_SRC
+	rump_server_start $SOCK_FWD
+	rump_server_start $SOCK_DST1
+	rump_server_start $SOCK_DST2
+
+	rump_server_add_iface $SOCK_SRC shmif0 $BUS_SRC
+
+	rump_server_add_iface $SOCK_FWD shmif0 $BUS_SRC
+	rump_server_add_iface $SOCK_FWD shmif1 $BUS_DST1
+	rump_server_add_iface $SOCK_FWD shmif2 $BUS_DST2
+
+	rump_server_add_iface $SOCK_DST1 shmif0 $BUS_DST1
+	rump_server_add_iface $SOCK_DST2 shmif0 $BUS_DST2
+
+	export RUMP_SERVER=$SOCK_SRC
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_src/24
+	atf_check -s exit:0 -o ignore rump.route add default $ip_gwsrc
+
+	export RUMP_SERVER=$SOCK_FWD
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=1
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_gwsrc/24
+	atf_check -s exit:0 rump.ifconfig shmif1 $ip_gwdst1/24
+	atf_check -s exit:0 rump.ifconfig shmif2 $ip_gwdst2/24
+
+	export RUMP_SERVER=$SOCK_DST1
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_dst1/24
+	atf_check -s exit:0 -o ignore rump.route add default $ip_gwdst1
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_dst/24 alias
+
+	export RUMP_SERVER=$SOCK_DST2
+	atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.dad_count=0
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_dst2/24
+	atf_check -s exit:0 -o ignore rump.route add default $ip_gwdst2
+	atf_check -s exit:0 rump.ifconfig shmif0 $ip_dst/24 alias
+
+	export RUMP_SERVER=$SOCK_SRC
+	atf_check -s exit:0 -o ignore rump.ping -n -w 3 -c 1 $ip_dst1
+	atf_check -s exit:0 -o ignore rump.ping -n -w 3 -c 1 $ip_dst2
+	# It fails because there is no route to $ip_dst
+	atf_check -s not-exit:0 -o ignore rump.ping -n -w 3 -c 1 $ip_dst
+
+	extract_new_packets $BUS_DST1 > ./outfile
+
+	export RUMP_SERVER=$SOCK_FWD
+	# Add the default route so that $ip_dst @ dst1 is reachable now
+	atf_check -s exit:0 -o ignore rump.route add default $ip_dst1
+	export RUMP_SERVER=$SOCK_DST1
+	# ...but don't response ICMP requests to avoid rtcache pollution
+	atf_check -s exit:0 -o ignore \
+	    rump.route add -net $subnet_src/24 127.0.0.1 -blackhole
+
+	export RUMP_SERVER=$SOCK_SRC
+	# ping fails expectedly
+	atf_check -s not-exit:0 -o ignore rump.ping -n -w 3 -c 1 $ip_dst
+
+	# An ICMP request should come to dst1
+	extract_new_packets $BUS_DST1 > ./outfile
+	atf_check -s exit:0 -o match:"$ip_src > $ip_dst: ICMP echo request" \
+	    cat ./outfile
+
+	export RUMP_SERVER=$SOCK_FWD
+	# Teach the subnet of $ip_dst is at dst2
+	atf_check -s exit:0 -o ignore rump.route add -net $subnet_dst/24 $ip_dst2
+	export RUMP_SERVER=$SOCK_DST2
+	# ...but don't response ICMP requests to avoid rtcache pollution
+	atf_check -s exit:0 -o ignore \
+	    rump.route add -net $subnet_src/24 127.0.0.1 -blackhole
+
+	export RUMP_SERVER=$SOCK_SRC
+	# ping fails expectedly
+	atf_check -s not-exit:0 -o ignore rump.ping -n -w 3 -c 1 $ip_dst
+
+	# An ICMP request should come to dst2. If rtcaches aren't invalidated
+	# correctly, the ICMP request should appear at dst1
+	extract_new_packets $BUS_DST1 > ./outfile
+	atf_check -s exit:0 -o not-match:"$ip_src > $ip_dst: ICMP echo request" \
+	    cat ./outfile
+
+	export RUMP_SERVER=$SOCK_FWD
+	# Delete the route so the packets heading to $ip_dst should go dst1 again
+	atf_check -s exit:0 -o ignore rump.route delete -net $subnet_dst/24 $ip_dst2
+
+	export RUMP_SERVER=$SOCK_SRC
+	# ping fails expectedly
+	atf_check -s not-exit:0 -o ignore rump.ping -n -w 3 -c 1 $ip_dst
+
+	# An ICMP request should come to dst1
+	extract_new_packets $BUS_DST1 > ./outfile
+	atf_check -s exit:0 -o match:"$ip_src > $ip_dst: ICMP echo request" \
+	    cat ./outfile
+
+	rump_server_destroy_ifaces
+}
+
+rtcache_invalidation_cleanup()
+{
+
+	$DEBUG && dump
+	cleanup
+}
+
+atf_init_test_cases()
+{
+
+	atf_add_test_case rtcache_invalidation
+}

Reply via email to