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/b5d1778fbdf1
branches: trunk
changeset: 346262:b5d1778fbdf1
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 791c04fbb4aa -r b5d1778fbdf1 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