Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet use pserialize(9) and psref(9) (1/2) : without i...



details:   https://anonhg.NetBSD.org/src/rev/6e21450da791
branches:  trunk
changeset: 816404:6e21450da791
user:      knakahara <knakahara%NetBSD.org@localhost>
date:      Mon Jul 04 04:29:11 2016 +0000

description:
use pserialize(9) and psref(9) (1/2) : without ip_encap radix tree care

diffstat:

 sys/netinet/ip_encap.c |  274 +++++++++++++++++++++++++++++++++++-------------
 sys/netinet/ip_encap.h |    9 +-
 2 files changed, 205 insertions(+), 78 deletions(-)

diffs (truncated from 662 to 300 lines):

diff -r 13d302f087b3 -r 6e21450da791 sys/netinet/ip_encap.c
--- a/sys/netinet/ip_encap.c    Mon Jul 04 04:26:00 2016 +0000
+++ b/sys/netinet/ip_encap.c    Mon Jul 04 04:29:11 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_encap.c,v 1.55 2016/07/04 04:26:00 knakahara Exp $  */
+/*     $NetBSD: ip_encap.c,v 1.56 2016/07/04 04:29:11 knakahara Exp $  */
 /*     $KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $       */
 
 /*
@@ -68,7 +68,7 @@
 #define USE_RADIX
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.55 2016/07/04 04:26:00 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.56 2016/07/04 04:29:11 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -84,7 +84,9 @@
 #include <sys/queue.h>
 #include <sys/kmem.h>
 #include <sys/once.h>
-#include <sys/rwlock.h>
+#include <sys/mutex.h>
+#include <sys/psref.h>
+#include <sys/pslist.h>
 
 #include <net/if.h>
 
@@ -111,10 +113,12 @@
 enum direction { INBOUND, OUTBOUND };
 
 #ifdef INET
-static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction);
+static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction,
+    struct psref *);
 #endif
 #ifdef INET6
-static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction);
+static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction,
+    struct psref *);
 #endif
 static int encap_add(struct encaptab *);
 static int encap_remove(struct encaptab *);
@@ -128,7 +132,18 @@
 #endif
 static void encap_fillarg(struct mbuf *, const struct encaptab *);
 
-LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
+/*
+ * In encap[46]_lookup(), ep->func can sleep(e.g. rtalloc1) while walking
+ * encap_table. So, it cannot use pserialize_read_enter()
+ */
+static struct {
+       struct pslist_head      list;
+       pserialize_t            psz;
+       struct psref_class      *elem_class; /* for the element of et_list */
+} encaptab  __cacheline_aligned = {
+       .list = PSLIST_INITIALIZER,
+};
+#define encap_table encaptab.list
 
 #ifdef USE_RADIX
 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */
@@ -136,8 +151,6 @@
 
 static ONCE_DECL(encap_init_control);
 
-static krwlock_t encap_whole_lock __cacheline_aligned;
-
 static int encap_init_once(void);
 
 void
@@ -156,7 +169,7 @@
         * initialization - using LIST_INIT() here can nuke encap_attach()
         * from drivers.
         */
-       LIST_INIT(&encaptab);
+       PSLIST_INIT(&encap_table);
 #endif
 
 #ifdef USE_RADIX
@@ -174,19 +187,20 @@
 
 #ifdef INET
 static struct encaptab *
-encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir)
+encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir,
+    struct psref *match_psref)
 {
        struct ip *ip;
        struct ip_pack4 pack;
        struct encaptab *ep, *match;
        int prio, matchprio;
+       int s;
 #ifdef USE_RADIX
        struct radix_node_head *rnh = encap_rnh(AF_INET);
        struct radix_node *rn;
 #endif
 
        KASSERT(m->m_len >= sizeof(*ip));
-       KASSERT(rw_read_held(&encap_whole_lock));
 
        ip = mtod(m, struct ip *);
 
@@ -205,24 +219,40 @@
        match = NULL;
        matchprio = 0;
 
+       s = pserialize_read_enter();
 #ifdef USE_RADIX
        rn = rnh->rnh_matchaddr((void *)&pack, rnh);
        if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
-               match = (struct encaptab *)rn;
+               struct encaptab *encapp = (struct encaptab *)rn;
+
+               psref_acquire(match_psref, &encapp->psref,
+                   encaptab.elem_class);
+               match = encapp;
                matchprio = mask_matchlen(match->srcmask) +
                    mask_matchlen(match->dstmask);
        }
 #endif
+       PSLIST_READER_FOREACH(ep, &encap_table, struct encaptab, chain) {
+               struct psref elem_psref;
 
-       LIST_FOREACH(ep, &encaptab, chain) {
+               membar_datadep_consumer();
+
                if (ep->af != AF_INET)
                        continue;
                if (ep->proto >= 0 && ep->proto != proto)
                        continue;
-               if (ep->func)
+
+               psref_acquire(&elem_psref, &ep->psref,
+                   encaptab.elem_class);
+               if (ep->func) {
+                       pserialize_read_exit(s);
+                       /* ep->func is sleepable. e.g. rtalloc1 */
                        prio = (*ep->func)(m, off, proto, ep->arg);
-               else {
+                       s = pserialize_read_enter();
+               } else {
 #ifdef USE_RADIX
+                       psref_release(&elem_psref, &ep->psref,
+                           encaptab.elem_class);
                        continue;
 #else
                        prio = mask_match(ep, (struct sockaddr *)&pack.mine,
@@ -251,13 +281,30 @@
                 * For radix-based lookup, I guess source takes precedence.
                 * See rn_{refines,lexobetter} for the correct answer.
                 */
-               if (prio <= 0)
+               if (prio <= 0) {
+                       psref_release(&elem_psref, &ep->psref,
+                           encaptab.elem_class);
                        continue;
+               }
                if (prio > matchprio) {
+                       /* release last matched ep */
+                       if (match != NULL)
+                               psref_release(match_psref, &match->psref,
+                                   encaptab.elem_class);
+
+                       psref_copy(match_psref, &elem_psref,
+                           encaptab.elem_class);
                        matchprio = prio;
                        match = ep;
                }
+               KASSERTMSG((match == NULL) || psref_held(&match->psref,
+                       encaptab.elem_class),
+                   "current match = %p, but not hold its psref", match);
+
+               psref_release(&elem_psref, &ep->psref,
+                   encaptab.elem_class);
        }
+       pserialize_read_exit(s);
 
        return match;
 }
@@ -269,29 +316,29 @@
        va_list ap;
        const struct encapsw *esw;
        struct encaptab *match;
+       struct psref match_psref;
 
        va_start(ap, m);
        off = va_arg(ap, int);
        proto = va_arg(ap, int);
        va_end(ap);
 
-       rw_enter(&encap_whole_lock, RW_READER);
-       match = encap4_lookup(m, off, proto, INBOUND);
-
+       match = encap4_lookup(m, off, proto, INBOUND, &match_psref);
        if (match) {
                /* found a match, "match" has the best one */
                esw = match->esw;
                if (esw && esw->encapsw4.pr_input) {
                        encap_fillarg(m, match);
-                       rw_exit(&encap_whole_lock);
                        (*esw->encapsw4.pr_input)(m, off, proto);
+                       psref_release(&match_psref, &match->psref,
+                           encaptab.elem_class);
                } else {
-                       rw_exit(&encap_whole_lock);
+                       psref_release(&match_psref, &match->psref,
+                           encaptab.elem_class);
                        m_freem(m);
                }
                return;
        }
-       rw_exit(&encap_whole_lock);
 
        /* last resort: inject to raw socket */
        rip_input(m, off, proto);
@@ -300,11 +347,13 @@
 
 #ifdef INET6
 static struct encaptab *
-encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir)
+encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir,
+    struct psref *match_psref)
 {
        struct ip6_hdr *ip6;
        struct ip_pack6 pack;
        int prio, matchprio;
+       int s;
        struct encaptab *ep, *match;
 #ifdef USE_RADIX
        struct radix_node_head *rnh = encap_rnh(AF_INET6);
@@ -312,7 +361,6 @@
 #endif
 
        KASSERT(m->m_len >= sizeof(*ip6));
-       KASSERT(rw_read_held(&encap_whole_lock));
 
        ip6 = mtod(m, struct ip6_hdr *);
 
@@ -331,24 +379,41 @@
        match = NULL;
        matchprio = 0;
 
+       s = pserialize_read_enter();
 #ifdef USE_RADIX
        rn = rnh->rnh_matchaddr((void *)&pack, rnh);
        if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
-               match = (struct encaptab *)rn;
+               struct encaptab *encapp = (struct encaptab *)rn;
+
+               psref_acquire(match_psref, &encapp->psref,
+                   encaptab.elem_class);
+               match = encapp;
                matchprio = mask_matchlen(match->srcmask) +
                    mask_matchlen(match->dstmask);
        }
 #endif
+       PSLIST_READER_FOREACH(ep, &encap_table, struct encaptab, chain) {
+               struct psref elem_psref;
 
-       LIST_FOREACH(ep, &encaptab, chain) {
+               membar_datadep_consumer();
+
                if (ep->af != AF_INET6)
                        continue;
                if (ep->proto >= 0 && ep->proto != proto)
                        continue;
-               if (ep->func)
+
+               psref_acquire(&elem_psref, &ep->psref,
+                   encaptab.elem_class);
+
+               if (ep->func) {
+                       pserialize_read_exit(s);
+                       /* ep->func is sleepable. e.g. rtalloc1 */
                        prio = (*ep->func)(m, off, proto, ep->arg);
-               else {
+                       s = pserialize_read_enter();
+               } else {
 #ifdef USE_RADIX
+                       psref_release(&elem_psref, &ep->psref,
+                           encaptab.elem_class);
                        continue;
 #else
                        prio = mask_match(ep, (struct sockaddr *)&pack.mine,
@@ -357,13 +422,30 @@
                }
 
                /* see encap4_lookup() for issues here */
-               if (prio <= 0)
+               if (prio <= 0) {
+                       psref_release(&elem_psref, &ep->psref,
+                           encaptab.elem_class);
                        continue;
+               }
                if (prio > matchprio) {
+                       /* release last matched ep */
+                       if (match != NULL)



Home | Main Index | Thread Index | Old Index