Module Name:    src
Committed By:   ozaki-r
Date:           Thu Sep 21 07:15:35 UTC 2017

Modified Files:
        src/sys/net: route.c route.h
        src/sys/netatalk: at_proto.c
        src/sys/netinet: in_proto.c
        src/sys/netinet6: in6_proto.c
        src/sys/netmpls: mpls_proto.c
        src/sys/netnatm: natm_proto.c
        src/sys/rump/net/lib/libsockin: sockin.c
        src/sys/sys: domain.h

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.198 -r1.199 src/sys/net/route.c
cvs rdiff -u -r1.113 -r1.114 src/sys/net/route.h
cvs rdiff -u -r1.21 -r1.22 src/sys/netatalk/at_proto.c
cvs rdiff -u -r1.123 -r1.124 src/sys/netinet/in_proto.c
cvs rdiff -u -r1.117 -r1.118 src/sys/netinet6/in6_proto.c
cvs rdiff -u -r1.30 -r1.31 src/sys/netmpls/mpls_proto.c
cvs rdiff -u -r1.17 -r1.18 src/sys/netnatm/natm_proto.c
cvs rdiff -u -r1.64 -r1.65 src/sys/rump/net/lib/libsockin/sockin.c
cvs rdiff -u -r1.32 -r1.33 src/sys/sys/domain.h

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/route.c
diff -u src/sys/net/route.c:1.198 src/sys/net/route.c:1.199
--- src/sys/net/route.c:1.198	Thu Sep 21 04:44:32 2017
+++ src/sys/net/route.c	Thu Sep 21 07:15:34 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.c,v 1.198 2017/09/21 04:44:32 ozaki-r Exp $	*/
+/*	$NetBSD: route.c,v 1.199 2017/09/21 07:15:34 ozaki-r 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.198 2017/09/21 04:44:32 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.199 2017/09/21 07:15:34 ozaki-r Exp $");
 
 #include <sys/param.h>
 #ifdef RTFLUSH_DEBUG
@@ -203,6 +203,13 @@ 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
  */
 
 /*
@@ -239,6 +246,8 @@ static krwlock_t		rtcache_lock __cacheli
 #define	RTCACHE_WLOCKED()	false
 #endif
 
+static uint64_t rtcache_generation;
+
 /*
  * mutex and cv that are used to wait for references to a rtentry left
  * before updating the rtentry.
@@ -271,14 +280,11 @@ 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 *);
 
@@ -491,40 +497,17 @@ rt_init(void)
 }
 
 static void
-rtflushall(int family)
+rtcache_invalidate(void)
 {
-	struct domain *dom;
 
 	if (rtcache_debug())
 		printf("%s: enter\n", __func__);
 
-	if ((dom = pffinddomain(family)) == NULL)
-		return;
-
 	RTCACHE_WLOCK();
-	rtcache_invalidate(&dom->dom_rtcache);
+	rtcache_generation++;
 	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);
-}
-
 #ifdef RT_DEBUG
 static void
 dump_rt(const struct rtentry *rt)
@@ -1251,7 +1234,7 @@ rtrequest1(int req, struct rt_addrinfo *
 		RT_UNLOCK();
 		need_unlock = false;
 		rt_timer_remove_all(rt);
-		rtcache_clear_rtentry(dst->sa_family, rt);
+		rtcache_invalidate();
 #if defined(INET) || defined(INET6)
 		if (netmask != NULL)
 			lltable_prefix_free(dst->sa_family, dst, netmask, 0);
@@ -1346,7 +1329,7 @@ rtrequest1(int req, struct rt_addrinfo *
 		}
 		RT_UNLOCK();
 		need_unlock = false;
-		rtflushall(dst->sa_family);
+		rtcache_invalidate();
 		break;
 	case RTM_GET:
 		if (netmask != NULL) {
@@ -1893,14 +1876,13 @@ _rtcache_init(struct route *ro, int flag
 
 	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;
+		ro->ro_rtcache_generation = rtcache_generation;
 		KASSERT(!ISSET(rt->rt_flags, RTF_UPDATING));
 		rtcache_ref(rt, ro);
 		rt_unref(rt);
-		rtcache(ro);
 	} else if (rt != NULL)
 		rt_unref(rt);
 
@@ -1933,7 +1915,7 @@ rtcache_update(struct route *ro, int clo
 {
 	struct rtentry *rt;
 	RTCACHE_WLOCK();
-	rtcache_clear(ro);
+	ro->_ro_rt = NULL;
 	rt = _rtcache_init(ro, clone);
 	RTCACHE_UNLOCK();
 	return rt;
@@ -1958,9 +1940,8 @@ rtcache_copy(struct route *new_ro, struc
 		goto out;
 
 	RTCACHE_WLOCK();
-	new_ro->ro_invalid = false;
-	if ((new_ro->_ro_rt = rt) != NULL)
-		rtcache(new_ro);
+	new_ro->_ro_rt = rt;
+	new_ro->ro_rtcache_generation = rtcache_generation;
 	rtcache_invariants(new_ro);
 	RTCACHE_UNLOCK();
 out:
@@ -1968,8 +1949,6 @@ out:
 	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)
@@ -2023,7 +2002,8 @@ retry:
 	rt = ro->_ro_rt;
 	rtcache_invariants(ro);
 
-	if (ro->ro_invalid) {
+	if (ro->ro_rtcache_generation != rtcache_generation) {
+		/* The cache is invalidated */
 		rt = NULL;
 		goto out;
 	}
@@ -2063,57 +2043,6 @@ rtcache_validate(struct route *ro)
 	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)
@@ -2140,7 +2069,7 @@ rtcache_lookup2(struct route *ro, const 
 	if (rt == NULL) {
 		RTCACHE_UNLOCK();
 		RTCACHE_WLOCK();
-		rtcache_clear(ro);
+		ro->_ro_rt = NULL;
 		goto miss;
 	}
 
@@ -2167,7 +2096,8 @@ rtcache_free_locked(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;
@@ -2194,7 +2124,7 @@ rtcache_setdst_locked(struct route *ro, 
 	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;

Index: src/sys/net/route.h
diff -u src/sys/net/route.h:1.113 src/sys/net/route.h:1.114
--- src/sys/net/route.h:1.113	Fri Jun 16 02:24:54 2017
+++ src/sys/net/route.h	Thu Sep 21 07:15:34 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.h,v 1.113 2017/06/16 02:24:54 ozaki-r Exp $	*/
+/*	$NetBSD: route.h,v 1.114 2017/09/21 07:15:34 ozaki-r 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.22
--- src/sys/netatalk/at_proto.c:1.21	Thu Jan 21 15:41:30 2016
+++ src/sys/netatalk/at_proto.c	Thu Sep 21 07:15:34 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.22 2017/09/21 07:15:34 ozaki-r 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.22 2017/09/21 07:15:34 ozaki-r 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 src/sys/netinet/in_proto.c:1.124
--- src/sys/netinet/in_proto.c:1.123	Fri Apr 14 02:43:27 2017
+++ src/sys/netinet/in_proto.c	Thu Sep 21 07:15:34 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_proto.c,v 1.123 2017/04/14 02:43:27 ozaki-r Exp $	*/
+/*	$NetBSD: in_proto.c,v 1.124 2017/09/21 07:15:34 ozaki-r 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 2017/04/14 02:43:27 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.124 2017/09/21 07:15:34 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -489,7 +489,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 src/sys/netinet6/in6_proto.c:1.118
--- src/sys/netinet6/in6_proto.c:1.117	Fri Apr 14 02:43:28 2017
+++ src/sys/netinet6/in6_proto.c	Thu Sep 21 07:15:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_proto.c,v 1.117 2017/04/14 02:43:28 ozaki-r Exp $	*/
+/*	$NetBSD: in6_proto.c,v 1.118 2017/09/21 07:15:35 ozaki-r 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 2017/04/14 02:43:28 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.118 2017/09/21 07:15:35 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_gateway.h"
@@ -490,7 +490,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.31
--- src/sys/netmpls/mpls_proto.c:1.30	Mon Oct  3 11:06:06 2016
+++ src/sys/netmpls/mpls_proto.c	Thu Sep 21 07:15:35 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.31 2017/09/21 07:15:35 ozaki-r 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.31 2017/09/21 07:15:35 ozaki-r 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.18
--- src/sys/netnatm/natm_proto.c:1.17	Mon Oct  3 11:06:06 2016
+++ src/sys/netnatm/natm_proto.c	Thu Sep 21 07:15:35 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.18 2017/09/21 07:15:35 ozaki-r 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.18 2017/09/21 07:15:35 ozaki-r 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.65
--- 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	Thu Sep 21 07:15:35 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.65 2017/09/21 07:15:35 ozaki-r 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.65 2017/09/21 07:15:35 ozaki-r 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.33
--- src/sys/sys/domain.h:1.32	Wed Apr 22 19:46:08 2015
+++ src/sys/sys/domain.h	Thu Sep 21 07:15:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: domain.h,v 1.32 2015/04/22 19:46:08 roy Exp $	*/
+/*	$NetBSD: domain.h,v 1.33 2017/09/21 07:15:35 ozaki-r 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);

Reply via email to