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/84c33d0f7bb9
branches:  trunk
changeset: 819842:84c33d0f7bb9
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 b6d554c5add6 -r 84c33d0f7bb9 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 b6d554c5add6 -r 84c33d0f7bb9 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