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 +}