Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/netinet6 Protect IPv6 default router and prefix lists wi...
details: https://anonhg.NetBSD.org/src/rev/0548c3e2518d
branches: trunk
changeset: 349700:0548c3e2518d
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Mon Dec 19 07:51:34 2016 +0000
description:
Protect IPv6 default router and prefix lists with coarse-grained rwlock
in6_purgeaddr (in6_unlink_ifa) itself unrefernces a prefix entry and calls
nd6_prelist_remove if the counter becomes 0, so callers doesn't need to
handle the reference counting.
Performance-sensitive paths (sending/forwarding packets) call just one
reader lock. This is a trade-off between performance impact vs. the amount
of efforts; if we want to remove the reader lock, we need huge amount of
works including destroying objects with psz/psref in softint, for example.
diffstat:
sys/netinet6/in6.c | 27 +++++--------
sys/netinet6/nd6.c | 97 ++++++++++++++++++++++++++++++++-----------------
sys/netinet6/nd6.h | 11 +++++-
sys/netinet6/nd6_nbr.c | 20 ++++------
sys/netinet6/nd6_rtr.c | 79 +++++++++++++++++++++++++++++++---------
5 files changed, 153 insertions(+), 81 deletions(-)
diffs (truncated from 906 to 300 lines):
diff -r 83f726e6dee1 -r 0548c3e2518d sys/netinet6/in6.c
--- a/sys/netinet6/in6.c Mon Dec 19 07:48:35 2016 +0000
+++ b/sys/netinet6/in6.c Mon Dec 19 07:51:34 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: in6.c,v 1.224 2016/12/12 03:55:57 ozaki-r Exp $ */
+/* $NetBSD: in6.c,v 1.225 2016/12/19 07:51:34 ozaki-r 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.224 2016/12/12 03:55:57 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.225 2016/12/19 07:51:34 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -709,23 +709,11 @@
}
case SIOCDIFADDR_IN6:
- {
- struct nd_prefix *pr;
-
- /*
- * If the address being deleted is the only one that owns
- * the corresponding prefix, expire the prefix as well.
- * Note that in6_purgeaddr() will decrement ndpr_refcnt.
- */
- pr = ia->ia6_ndpr;
ia6_release(ia, &psref);
in6_purgeaddr(&ia->ia_ifa);
ia = NULL;
- if (pr && pr->ndpr_refcnt == 0)
- nd6_prelist_remove(pr);
run_hooks = true;
break;
- }
default:
error = ENOTTY;
@@ -1388,7 +1376,7 @@
* Release the reference to the ND prefix.
*/
if (ia->ia6_ndpr != NULL) {
- ia->ia6_ndpr->ndpr_refcnt--;
+ nd6_prefix_unref(ia->ia6_ndpr);
ia->ia6_ndpr = NULL;
}
@@ -1397,8 +1385,11 @@
* nd6_pfxlist_onlink_check() since the release might affect the status of
* other (detached) addresses.
*/
- if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0)
+ if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0) {
+ ND6_WLOCK();
nd6_pfxlist_onlink_check();
+ ND6_UNLOCK();
+ }
IN6_ADDRLIST_ENTRY_DESTROY(ia);
@@ -2153,7 +2144,9 @@
curlwp_bindx(bound);
/* Restore any detached prefixes */
+ ND6_WLOCK();
nd6_pfxlist_onlink_check();
+ ND6_UNLOCK();
}
void
@@ -2180,7 +2173,9 @@
int s, bound;
/* Any prefixes on this interface should be detached as well */
+ ND6_WLOCK();
nd6_pfxlist_onlink_check();
+ ND6_UNLOCK();
bound = curlwp_bind();
s = pserialize_read_enter();
diff -r 83f726e6dee1 -r 0548c3e2518d sys/netinet6/nd6.c
--- a/sys/netinet6/nd6.c Mon Dec 19 07:48:35 2016 +0000
+++ b/sys/netinet6/nd6.c Mon Dec 19 07:51:34 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nd6.c,v 1.219 2016/12/19 04:52:17 ozaki-r Exp $ */
+/* $NetBSD: nd6.c,v 1.220 2016/12/19 07:51:34 ozaki-r 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.219 2016/12/19 04:52:17 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.220 2016/12/19 07:51:34 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -103,6 +103,8 @@
int nd6_debug = 0;
#endif
+krwlock_t nd6_lock __cacheline_aligned;
+
struct nd_drhead nd_defrouter;
struct nd_prhead nd_prefix = { 0 };
@@ -138,6 +140,8 @@
{
int error;
+ rw_init(&nd6_lock);
+
/* initialization of the default router list */
ND_DEFROUTER_LIST_INIT();
@@ -595,12 +599,14 @@
#endif
/* expire default router list */
-
+
+ ND6_WLOCK();
ND_DEFROUTER_LIST_FOREACH_SAFE(dr, next_dr) {
if (dr->expire && dr->expire < time_uptime) {
nd6_defrtrlist_del(dr, NULL);
}
}
+ ND6_UNLOCK();
/*
* expire interface addresses.
@@ -695,6 +701,7 @@
curlwp_bindx(bound);
/* expire prefix list */
+ ND6_WLOCK();
ND_PREFIX_LIST_FOREACH_SAFE(pr, next_pr) {
/*
* check prefix lifetime.
@@ -712,6 +719,7 @@
nd6_prelist_remove(pr);
}
}
+ ND6_UNLOCK();
#ifndef NET_MPSAFE
KERNEL_UNLOCK_ONE(NULL);
@@ -786,7 +794,10 @@
* Random factor is introduced in the preferred lifetime, so
* we do not need additional delay (3rd arg to in6_tmpifadd).
*/
- if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
+ ND6_WLOCK();
+ e = in6_tmpifadd(public_ifa6, 0, 0);
+ ND6_UNLOCK();
+ if (e != 0) {
ia6_release(public_ifa6, &psref);
log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
" tmp addr, errno=%d\n", e);
@@ -835,6 +846,7 @@
if (ext == NULL)
return;
+ ND6_WLOCK();
/*
* Nuke default router list entries toward ifp.
* We defer removal of default router list entries that is installed
@@ -884,6 +896,7 @@
nd6_defrouter_select();
}
}
+ ND6_UNLOCK();
/*
* We may not need to nuke the neighbor cache entries here
@@ -903,6 +916,7 @@
struct nd_defrouter *dr;
struct nd_prefix *pr;
+ ND6_RLOCK();
ND_DEFROUTER_LIST_FOREACH(dr) {
KASSERTMSG(dr->ifp != ifp,
"defrouter %s remains on %s",
@@ -915,6 +929,7 @@
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
pr->ndpr_plen, ifp->if_xname);
}
+ ND6_UNLOCK();
}
struct llentry *
@@ -993,6 +1008,7 @@
* If the address matches one of our on-link prefixes, it should be a
* neighbor.
*/
+ ND6_RLOCK();
ND_PREFIX_LIST_FOREACH(pr) {
if (pr->ndpr_ifp != ifp)
continue;
@@ -1022,9 +1038,12 @@
}
if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
- &addr->sin6_addr, &pr->ndpr_mask))
+ &addr->sin6_addr, &pr->ndpr_mask)) {
+ ND6_UNLOCK();
return 1;
+ }
}
+ ND6_UNLOCK();
/*
* If the address is assigned on the node of the other side of
@@ -1044,11 +1063,13 @@
* If the default router list is empty, all addresses are regarded
* as on-link, and thus, as a neighbor.
*/
+ ND6_RLOCK();
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV &&
- ND_DEFROUTER_LIST_EMPTY() &&
- nd6_defifindex == ifp->if_index) {
+ ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) {
+ ND6_UNLOCK();
return 1;
}
+ ND6_UNLOCK();
return 0;
}
@@ -1091,6 +1112,7 @@
* If the address matches one of our on-link prefixes, it should be a
* neighbor.
*/
+ ND6_RLOCK();
ND_PREFIX_LIST_FOREACH(pr) {
if (pr->ndpr_ifp != ifp)
continue;
@@ -1099,8 +1121,10 @@
continue;
if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
- &addr->sin6_addr, &pr->ndpr_mask))
+ &addr->sin6_addr, &pr->ndpr_mask)) {
+ ND6_UNLOCK();
return 1;
+ }
}
/*
@@ -1111,8 +1135,10 @@
*/
if (!ip6_forwarding && ND_DEFROUTER_LIST_EMPTY() &&
nd6_defifindex == ifp->if_index) {
+ ND6_UNLOCK();
return 1;
}
+ ND6_UNLOCK();
IF_AFDATA_UNLOCK_ASSERT(ifp);
if (nd6_is_new_addr_neighbor(addr, ifp))
@@ -1178,8 +1204,7 @@
nd6_llinfo_settimer(ln, -1);
if (!ip6_forwarding) {
- int s;
- s = splsoftnet();
+ ND6_WLOCK();
dr = nd6_defrouter_lookup(in6, ifp);
if (dr != NULL && dr->expire &&
@@ -1201,7 +1226,7 @@
(dr->expire - time_uptime) * hz);
else
nd6_llinfo_settimer(ln, nd6_gctimer * hz);
- splx(s);
+ ND6_UNLOCK();
LLE_WUNLOCK(ln);
return;
}
@@ -1262,11 +1287,10 @@
if (ln->la_flags & LLE_REDIRECT)
nd6_free_redirect(ln);
#endif
+ ND6_UNLOCK();
if (ln->ln_router || dr)
LLE_WLOCK(ln);
-
- splx(s);
}
/*
@@ -1620,7 +1644,6 @@
struct nd_defrouter *dr;
struct nd_prefix *pr;
Home |
Main Index |
Thread Index |
Old Index