Module Name:    src
Committed By:   knakahara
Date:           Mon Jul  4 04:17:25 UTC 2016

Modified Files:
        src/sys/net: if_gif.c if_stf.c
        src/sys/netinet: ip_encap.c ip_encap.h ip_mroute.c
        src/sys/netipsec: xform_ipip.c

Log Message:
let gif(4) promise softint(9) contract (2/2) : ip_encap side

The last commit does not care encaptab. This commit fixes encaptab race which
is used not only gif(4).


To generate a diff of this commit:
cvs rdiff -u -r1.114 -r1.115 src/sys/net/if_gif.c
cvs rdiff -u -r1.91 -r1.92 src/sys/net/if_stf.c
cvs rdiff -u -r1.53 -r1.54 src/sys/netinet/ip_encap.c
cvs rdiff -u -r1.19 -r1.20 src/sys/netinet/ip_encap.h
cvs rdiff -u -r1.141 -r1.142 src/sys/netinet/ip_mroute.c
cvs rdiff -u -r1.39 -r1.40 src/sys/netipsec/xform_ipip.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_gif.c
diff -u src/sys/net/if_gif.c:1.114 src/sys/net/if_gif.c:1.115
--- src/sys/net/if_gif.c:1.114	Mon Jul  4 04:14:47 2016
+++ src/sys/net/if_gif.c	Mon Jul  4 04:17:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gif.c,v 1.114 2016/07/04 04:14:47 knakahara Exp $	*/
+/*	$NetBSD: if_gif.c,v 1.115 2016/07/04 04:17:25 knakahara Exp $	*/
 /*	$KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.114 2016/07/04 04:14:47 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.115 2016/07/04 04:17:25 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -110,9 +110,6 @@ static int	gif_encap_attach(struct gif_s
 static int	gif_encap_detach(struct gif_softc *);
 static void	gif_encap_pause(struct gif_softc *);
 
-static void	gif_list_lock_enter(void);
-static void	gif_list_lock_exit(void);
-
 static struct if_clone gif_cloner =
     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
 
@@ -812,7 +809,7 @@ gif_set_tunnel(struct ifnet *ifp, struct
 	int error;
 
 	s = splsoftnet();
-	gif_list_lock_enter();
+	encap_lock_enter();
 
 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
 		if (sc2 == sc)
@@ -823,7 +820,7 @@ gif_set_tunnel(struct ifnet *ifp, struct
 		if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
 		    sockaddr_cmp(sc2->gif_psrc, src) == 0) {
 			/* continue to use the old configureation. */
-			gif_list_lock_exit();
+			encap_lock_exit();
 			splx(s);
 			return EADDRNOTAVAIL;
 		}
@@ -832,13 +829,13 @@ gif_set_tunnel(struct ifnet *ifp, struct
 	}
 
 	if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
-		gif_list_lock_exit();
+		encap_lock_exit();
 		splx(s);
 		return ENOMEM;
 	}
 	if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
 		sockaddr_free(nsrc);
-		gif_list_lock_exit();
+		encap_lock_exit();
 		splx(s);
 		return ENOMEM;
 	}
@@ -889,7 +886,7 @@ gif_set_tunnel(struct ifnet *ifp, struct
 	else
 		ifp->if_flags &= ~IFF_RUNNING;
 
-	gif_list_lock_exit();
+	encap_lock_exit();
 	splx(s);
 	return error;
 }
@@ -901,7 +898,7 @@ gif_delete_tunnel(struct ifnet *ifp)
 	int s;
 
 	s = splsoftnet();
-	gif_list_lock_enter();
+	encap_lock_enter();
 
 	gif_encap_pause(sc);
 	if (sc->gif_psrc) {
@@ -925,26 +922,6 @@ gif_delete_tunnel(struct ifnet *ifp)
 	else
 		ifp->if_flags &= ~IFF_RUNNING;
 
-	gif_list_lock_exit();
+	encap_lock_exit();
 	splx(s);
 }
-
-static void
-gif_list_lock_enter(void)
-{
-
-	/* XXX future work
-	 * should change interruptable lock.
-	 */
-	KERNEL_LOCK(1, NULL);
-}
-
-static void
-gif_list_lock_exit(void)
-{
-
-	/* XXX future work
-	 * should change interruptable lock.
-	 */
-	KERNEL_UNLOCK_ONE(NULL);
-}

Index: src/sys/net/if_stf.c
diff -u src/sys/net/if_stf.c:1.91 src/sys/net/if_stf.c:1.92
--- src/sys/net/if_stf.c:1.91	Wed Jun 22 07:48:17 2016
+++ src/sys/net/if_stf.c	Mon Jul  4 04:17:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_stf.c,v 1.91 2016/06/22 07:48:17 ozaki-r Exp $	*/
+/*	$NetBSD: if_stf.c,v 1.92 2016/07/04 04:17:25 knakahara Exp $	*/
 /*	$KAME: if_stf.c,v 1.62 2001/06/07 22:32:16 itojun Exp $ */
 
 /*
@@ -75,7 +75,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_stf.c,v 1.91 2016/06/22 07:48:17 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_stf.c,v 1.92 2016/07/04 04:17:25 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -191,17 +191,20 @@ stf_clone_create(struct if_clone *ifc, i
 {
 	struct stf_softc *sc;
 
+	sc = malloc(sizeof(struct stf_softc), M_DEVBUF, M_WAIT|M_ZERO);
+	if_initname(&sc->sc_if, ifc->ifc_name, unit);
+
+	encap_lock_enter();
 	if (LIST_FIRST(&stf_softc_list) != NULL) {
 		/* Only one stf interface is allowed. */
+		encap_lock_exit();
+		free(sc, M_DEVBUF);
 		return (EEXIST);
 	}
 
-	sc = malloc(sizeof(struct stf_softc), M_DEVBUF, M_WAIT|M_ZERO);
-
-	if_initname(&sc->sc_if, ifc->ifc_name, unit);
-
 	sc->encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV6,
 	    stf_encapcheck, &in_stf_encapsw, sc);
+	encap_lock_exit();
 	if (sc->encap_cookie == NULL) {
 		printf("%s: unable to attach encap\n", if_name(&sc->sc_if));
 		free(sc, M_DEVBUF);
@@ -226,8 +229,10 @@ stf_clone_destroy(struct ifnet *ifp)
 {
 	struct stf_softc *sc = (void *) ifp;
 
+	encap_lock_enter();
 	LIST_REMOVE(sc, sc_list);
 	encap_detach(sc->encap_cookie);
+	encap_lock_exit();
 	bpf_detach(ifp);
 	if_detach(ifp);
 	rtcache_free(&sc->sc_ro);

Index: src/sys/netinet/ip_encap.c
diff -u src/sys/netinet/ip_encap.c:1.53 src/sys/netinet/ip_encap.c:1.54
--- src/sys/netinet/ip_encap.c:1.53	Tue Apr 26 08:44:44 2016
+++ src/sys/netinet/ip_encap.c	Mon Jul  4 04:17:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_encap.c,v 1.53 2016/04/26 08:44:44 ozaki-r Exp $	*/
+/*	$NetBSD: ip_encap.c,v 1.54 2016/07/04 04:17:25 knakahara Exp $	*/
 /*	$KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $	*/
 
 /*
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.53 2016/04/26 08:44:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.54 2016/07/04 04:17:25 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -82,6 +82,8 @@ __KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v
 #include <sys/errno.h>
 #include <sys/queue.h>
 #include <sys/kmem.h>
+#include <sys/once.h>
+#include <sys/rwlock.h>
 
 #include <net/if.h>
 
@@ -124,6 +126,12 @@ LIST_HEAD(, encaptab) encaptab = LIST_HE
 
 struct radix_node_head *encap_head[2];	/* 0 for AF_INET, 1 for AF_INET6 */
 
+static ONCE_DECL(encap_init_control);
+
+static krwlock_t encap_whole_lock __cacheline_aligned;
+
+static int encap_init_once(void);
+
 void
 encap_init(void)
 {
@@ -166,6 +174,7 @@ encap4_lookup(struct mbuf *m, int off, i
 	struct radix_node *rn;
 
 	KASSERT(m->m_len >= sizeof(*ip));
+	KASSERT(rw_read_held(&encap_whole_lock));
 
 	ip = mtod(m, struct ip *);
 
@@ -246,6 +255,7 @@ encap4_input(struct mbuf *m, ...)
 	proto = va_arg(ap, int);
 	va_end(ap);
 
+	rw_enter(&encap_whole_lock, RW_READER);
 	match = encap4_lookup(m, off, proto, INBOUND);
 
 	if (match) {
@@ -253,11 +263,15 @@ encap4_input(struct mbuf *m, ...)
 		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);
-		} else
+		} else {
+			rw_exit(&encap_whole_lock);
 			m_freem(m);
+		}
 		return;
 	}
+	rw_exit(&encap_whole_lock);
 
 	/* last resort: inject to raw socket */
 	rip_input(m, off, proto);
@@ -276,6 +290,7 @@ encap6_lookup(struct mbuf *m, int off, i
 	struct radix_node *rn;
 
 	KASSERT(m->m_len >= sizeof(*ip6));
+	KASSERT(rw_read_held(&encap_whole_lock));
 
 	ip6 = mtod(m, struct ip6_hdr *);
 
@@ -330,6 +345,7 @@ encap6_input(struct mbuf **mp, int *offp
 	const struct encapsw *esw;
 	struct encaptab *match;
 
+	rw_enter(&encap_whole_lock, RW_READER);
 	match = encap6_lookup(m, *offp, proto, INBOUND);
 
 	if (match) {
@@ -337,24 +353,33 @@ encap6_input(struct mbuf **mp, int *offp
 		esw = match->esw;
 		if (esw && esw->encapsw6.pr_input) {
 			encap_fillarg(m, match);
+			rw_exit(&encap_whole_lock);
 			return (*esw->encapsw6.pr_input)(mp, offp, proto);
 		} else {
+			rw_exit(&encap_whole_lock);
 			m_freem(m);
 			return IPPROTO_DONE;
 		}
 	}
+	rw_exit(&encap_whole_lock);
 
 	/* last resort: inject to raw socket */
 	return rip6_input(mp, offp, proto);
 }
 #endif
 
+/*
+ * XXX
+ * The encaptab list and the rnh radix tree must be manipulated atomically.
+ */
 static int
 encap_add(struct encaptab *ep)
 {
 	struct radix_node_head *rnh = encap_rnh(ep->af);
 	int error = 0;
 
+	KASSERT(rw_write_held(&encap_whole_lock));
+
 	LIST_INSERT_HEAD(&encaptab, ep, chain);
 	if (!ep->func && rnh) {
 		if (!rnh->rnh_addaddr((void *)ep->addrpack,
@@ -370,12 +395,18 @@ encap_add(struct encaptab *ep)
 	return error;
 }
 
+/*
+ * XXX
+ * The encaptab list and the rnh radix tree must be manipulated atomically.
+ */
 static int
 encap_remove(struct encaptab *ep)
 {
 	struct radix_node_head *rnh = encap_rnh(ep->af);
 	int error = 0;
 
+	KASSERT(rw_write_held(&encap_whole_lock));
+
 	LIST_REMOVE(ep, chain);
 	if (!ep->func && rnh) {
 		if (!rnh->rnh_deladdr((void *)ep->addrpack,
@@ -420,6 +451,15 @@ encap_afcheck(int af, const struct socka
 	return 0;
 }
 
+static int
+encap_init_once(void)
+{
+
+	rw_init(&encap_whole_lock);
+
+	return 0;
+}
+
 /*
  * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
  * length of mask (sm and dm) is assumed to be same as sp/dp.
@@ -440,6 +480,8 @@ encap_attach(int af, int proto,
 	struct ip_pack6 *pack6;
 #endif
 
+	RUN_ONCE(&encap_init_control, encap_init_once);
+
 	s = splsoftnet();
 	/* sanity check on args */
 	error = encap_afcheck(af, sp, dp);
@@ -535,7 +577,9 @@ encap_attach(int af, int proto,
 	ep->esw = esw;
 	ep->arg = arg;
 
+	rw_enter(&encap_whole_lock, RW_WRITER);
 	error = encap_add(ep);
+	rw_exit(&encap_whole_lock);
 	if (error)
 		goto gc;
 
@@ -564,6 +608,8 @@ encap_attach_func(int af, int proto,
 	int error;
 	int s;
 
+	RUN_ONCE(&encap_init_control, encap_init_once);
+
 	s = splsoftnet();
 	/* sanity check on args */
 	if (!func) {
@@ -588,7 +634,9 @@ encap_attach_func(int af, int proto,
 	ep->esw = esw;
 	ep->arg = arg;
 
+	rw_enter(&encap_whole_lock, RW_WRITER);
 	error = encap_add(ep);
+	rw_exit(&encap_whole_lock);
 	if (error)
 		goto fail;
 
@@ -644,9 +692,11 @@ encap6_ctlinput(int cmd, const struct so
 			/*
 		 	* Check to see if we have a valid encap configuration.
 		 	*/
+			rw_enter(&encap_whole_lock, RW_READER);
 			match = encap6_lookup(m, off, nxt, OUTBOUND);
 			if (match)
 				valid++;
+			rw_exit(&encap_whole_lock);
 
 			/*
 		 	* Depending on the value of "valid" and routing table
@@ -664,6 +714,7 @@ encap6_ctlinput(int cmd, const struct so
 	}
 
 	/* inform all listeners */
+	rw_enter(&encap_whole_lock, RW_READER);
 	LIST_FOREACH(ep, &encaptab, chain) {
 		if (ep->af != AF_INET6)
 			continue;
@@ -678,6 +729,7 @@ encap6_ctlinput(int cmd, const struct so
 			(*esw->encapsw6.pr_ctlinput)(cmd, sa, d, ep->arg);
 		}
 	}
+	rw_exit(&encap_whole_lock);
 
 	rip6_ctlinput(cmd, sa, d0);
 	return NULL;
@@ -691,11 +743,14 @@ encap_detach(const struct encaptab *cook
 	struct encaptab *p, *np;
 	int error;
 
+	rw_enter(&encap_whole_lock, RW_WRITER);
 	LIST_FOREACH_SAFE(p, &encaptab, chain, np) {
 		if (p == ep) {
 			error = encap_remove(p);
+			rw_exit(&encap_whole_lock);
 			if (error)
 				return error;
+
 			if (!ep->func) {
 				kmem_free(p->addrpack, ep->addrpack->sa_len);
 				kmem_free(p->maskpack, ep->maskpack->sa_len);
@@ -704,6 +759,7 @@ encap_detach(const struct encaptab *cook
 			return 0;
 		}
 	}
+	rw_exit(&encap_whole_lock);
 
 	return ENOENT;
 }
@@ -747,6 +803,8 @@ encap_fillarg(struct mbuf *m, const stru
 {
 	struct m_tag *mtag;
 
+	KASSERT(rw_read_held(&encap_whole_lock));
+
 	mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
 	if (mtag) {
 		*(void **)(mtag + 1) = ep->arg;
@@ -768,3 +826,23 @@ encap_getarg(struct mbuf *m)
 	}
 	return p;
 }
+
+void
+encap_lock_enter(void)
+{
+
+	/* XXX future work
+	 * change interruptable lock.
+	 */
+	KERNEL_LOCK(1, NULL);
+}
+
+void
+encap_lock_exit(void)
+{
+
+	/* XXX future work
+	 * change interruptable lock
+	 */
+	KERNEL_UNLOCK_ONE(NULL);
+}

Index: src/sys/netinet/ip_encap.h
diff -u src/sys/netinet/ip_encap.h:1.19 src/sys/netinet/ip_encap.h:1.20
--- src/sys/netinet/ip_encap.h:1.19	Mon Feb 29 01:29:15 2016
+++ src/sys/netinet/ip_encap.h	Mon Jul  4 04:17:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_encap.h,v 1.19 2016/02/29 01:29:15 knakahara Exp $	*/
+/*	$NetBSD: ip_encap.h,v 1.20 2016/07/04 04:17:25 knakahara Exp $	*/
 /*	$KAME: ip_encap.h,v 1.7 2000/03/25 07:23:37 sumikawa Exp $	*/
 
 /*
@@ -106,6 +106,9 @@ void	*encap6_ctlinput(int, const struct 
 int	encap_detach(const struct encaptab *);
 void	*encap_getarg(struct mbuf *);
 
+void	encap_lock_enter(void);
+void	encap_lock_exit(void);
+
 #define	ENCAP_PR_WRAP_CTLINPUT(name)				\
 static void *							\
 name##_wrapper(int a, const struct sockaddr *b, void *c, void *d) \

Index: src/sys/netinet/ip_mroute.c
diff -u src/sys/netinet/ip_mroute.c:1.141 src/sys/netinet/ip_mroute.c:1.142
--- src/sys/netinet/ip_mroute.c:1.141	Tue Jun 21 03:28:27 2016
+++ src/sys/netinet/ip_mroute.c	Mon Jul  4 04:17:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_mroute.c,v 1.141 2016/06/21 03:28:27 ozaki-r Exp $	*/
+/*	$NetBSD: ip_mroute.c,v 1.142 2016/07/04 04:17:25 knakahara Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -93,7 +93,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.141 2016/06/21 03:28:27 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.142 2016/07/04 04:17:25 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -832,8 +832,10 @@ add_vif(struct vifctl *vifcp)
 		 * this requires both radix tree lookup and then a
 		 * function to check, and this is not supported yet.
 		 */
+		encap_lock_enter();
 		vifp->v_encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV4,
 		    vif_encapcheck, &vif_encapsw, vifp);
+		encap_lock_exit();
 		if (!vifp->v_encap_cookie)
 			return (EINVAL);
 
@@ -929,7 +931,9 @@ reset_vif(struct vif *vifp)
 	callout_stop(&vifp->v_repq_ch);
 
 	/* detach this vif from decapsulator dispatch table */
+	encap_lock_enter();
 	encap_detach(vifp->v_encap_cookie);
+	encap_lock_exit();
 	vifp->v_encap_cookie = NULL;
 
 	/*

Index: src/sys/netipsec/xform_ipip.c
diff -u src/sys/netipsec/xform_ipip.c:1.39 src/sys/netipsec/xform_ipip.c:1.40
--- src/sys/netipsec/xform_ipip.c:1.39	Fri Jun 10 13:31:44 2016
+++ src/sys/netipsec/xform_ipip.c	Mon Jul  4 04:17:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_ipip.c,v 1.39 2016/06/10 13:31:44 ozaki-r Exp $	*/
+/*	$NetBSD: xform_ipip.c,v 1.40 2016/07/04 04:17:25 knakahara Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_ipip.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
 
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.39 2016/06/10 13:31:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.40 2016/07/04 04:17:25 knakahara Exp $");
 
 /*
  * IP-inside-IP processing
@@ -725,6 +725,8 @@ ipe4_attach(void)
 	xform_register(&ipe4_xformsw);
 	/* attach to encapsulation framework */
 	/* XXX save return cookie for detach on module remove */
+	encap_lock_enter();
+	/* ipe4_encapsw and ipe4_encapsw must be added atomically */
 #ifdef INET
 	(void) encap_attach_func(AF_INET, -1,
 		ipe4_encapcheck, &ipe4_encapsw, NULL);
@@ -733,6 +735,7 @@ ipe4_attach(void)
 	(void) encap_attach_func(AF_INET6, -1,
 		ipe4_encapcheck, &ipe4_encapsw6, NULL);
 #endif
+	encap_lock_exit();
 }
 
 #ifdef SYSINIT

Reply via email to