Module Name:    src
Committed By:   knakahara
Date:           Mon Jul  4 04:14:47 UTC 2016

Modified Files:
        src/sys/net: if_gif.c
        src/sys/netinet: in_gif.c
        src/sys/netinet6: in6_gif.c

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

To prevent calling softint_schedule() after called softint_disestablish(),
the following modifications are added
    + ioctl (writing configuration) side
      - off IFF_RUNNING flag before changing configuration
      - wait softint handler completion before changing configuration
    + packet processing (reading configuraiotn) side
      - if IFF_RUNNING flag is on, do nothing
    + in whole
      - add gif_list_lock_{enter,exit} to prevent the same configuration is
        set to other gif(4) interfaces


To generate a diff of this commit:
cvs rdiff -u -r1.113 -r1.114 src/sys/net/if_gif.c
cvs rdiff -u -r1.76 -r1.77 src/sys/netinet/in_gif.c
cvs rdiff -u -r1.75 -r1.76 src/sys/netinet6/in6_gif.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.113 src/sys/net/if_gif.c:1.114
--- src/sys/net/if_gif.c:1.113	Mon Jun 27 09:06:56 2016
+++ src/sys/net/if_gif.c	Mon Jul  4 04:14:47 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gif.c,v 1.113 2016/06/27 09:06:56 knakahara Exp $	*/
+/*	$NetBSD: if_gif.c,v 1.114 2016/07/04 04:14:47 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.113 2016/06/27 09:06:56 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.114 2016/07/04 04:14:47 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1
 #include <sys/intr.h>
 #include <sys/kmem.h>
 #include <sys/sysctl.h>
+#include <sys/xcall.h>
 
 #include <net/if.h>
 #include <net/if_types.h>
@@ -107,6 +108,10 @@ static int	gif_check_nesting(struct ifne
 
 static int	gif_encap_attach(struct gif_softc *);
 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);
@@ -226,7 +231,8 @@ gif_encapcheck(struct mbuf *m, int off, 
 	if (sc == NULL)
 		return 0;
 
-	if ((sc->gif_if.if_flags & IFF_UP) == 0)
+	if ((sc->gif_if.if_flags & (IFF_UP|IFF_RUNNING))
+	    != (IFF_UP|IFF_RUNNING))
 		return 0;
 
 	/* no physical address */
@@ -329,7 +335,7 @@ gif_output(struct ifnet *ifp, struct mbu
 	}
 
 	m->m_flags &= ~(M_BCAST|M_MCAST);
-	if (!(ifp->if_flags & IFF_UP) ||
+	if (((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) ||
 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
 		m_freem(m);
 		error = ENETDOWN;
@@ -776,6 +782,25 @@ gif_encap_detach(struct gif_softc *sc)
 	return error;
 }
 
+static void
+gif_encap_pause(struct gif_softc *sc)
+{
+	struct ifnet *ifp = &sc->gif_if;
+	uint64_t where;
+
+	ifp->if_flags &= ~IFF_RUNNING;
+	/* membar_sync() is done in xc_broadcast(). */
+
+	/*
+	 * Wait for softint_execute()(ipintr() or ip6intr())
+	 * completion done by other CPUs which already run over if_flags
+	 * check in in_gif_input() or in6_gif_input().
+	 * Furthermore, wait for gif_output() completion too.
+	 */
+	where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
+	xc_wait(where);
+}
+
 static int
 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
 {
@@ -787,6 +812,7 @@ gif_set_tunnel(struct ifnet *ifp, struct
 	int error;
 
 	s = splsoftnet();
+	gif_list_lock_enter();
 
 	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
 		if (sc2 == sc)
@@ -797,6 +823,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();
 			splx(s);
 			return EADDRNOTAVAIL;
 		}
@@ -805,15 +832,19 @@ gif_set_tunnel(struct ifnet *ifp, struct
 	}
 
 	if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
+		gif_list_lock_exit();
 		splx(s);
 		return ENOMEM;
 	}
 	if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
 		sockaddr_free(nsrc);
+		gif_list_lock_exit();
 		splx(s);
 		return ENOMEM;
 	}
 
+	gif_encap_pause(sc);
+
 	/* Firstly, clear old configurations. */
 	/* XXX we can detach from both, but be polite just in case */
 	if (sc->gif_psrc)
@@ -858,6 +889,7 @@ gif_set_tunnel(struct ifnet *ifp, struct
 	else
 		ifp->if_flags &= ~IFF_RUNNING;
 
+	gif_list_lock_exit();
 	splx(s);
 	return error;
 }
@@ -869,7 +901,9 @@ gif_delete_tunnel(struct ifnet *ifp)
 	int s;
 
 	s = splsoftnet();
+	gif_list_lock_enter();
 
+	gif_encap_pause(sc);
 	if (sc->gif_psrc) {
 		sockaddr_free(sc->gif_psrc);
 		sc->gif_psrc = NULL;
@@ -890,5 +924,27 @@ gif_delete_tunnel(struct ifnet *ifp)
 		ifp->if_flags |= IFF_RUNNING;
 	else
 		ifp->if_flags &= ~IFF_RUNNING;
+
+	gif_list_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/netinet/in_gif.c
diff -u src/sys/netinet/in_gif.c:1.76 src/sys/netinet/in_gif.c:1.77
--- src/sys/netinet/in_gif.c:1.76	Fri Jun 10 13:31:44 2016
+++ src/sys/netinet/in_gif.c	Mon Jul  4 04:14:47 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_gif.c,v 1.76 2016/06/10 13:31:44 ozaki-r Exp $	*/
+/*	$NetBSD: in_gif.c,v 1.77 2016/07/04 04:14:47 knakahara Exp $	*/
 /*	$KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.76 2016/06/10 13:31:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.77 2016/07/04 04:14:47 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -206,7 +206,8 @@ in_gif_input(struct mbuf *m, int off, in
 
 	gifp = (struct ifnet *)encap_getarg(m);
 
-	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
+	if (gifp == NULL || (gifp->if_flags & (IFF_UP|IFF_RUNNING))
+		!= (IFF_UP|IFF_RUNNING)) {
 		m_freem(m);
 		ip_statinc(IP_STAT_NOGIF);
 		return;

Index: src/sys/netinet6/in6_gif.c
diff -u src/sys/netinet6/in6_gif.c:1.75 src/sys/netinet6/in6_gif.c:1.76
--- src/sys/netinet6/in6_gif.c:1.75	Tue Jun 28 02:02:56 2016
+++ src/sys/netinet6/in6_gif.c	Mon Jul  4 04:14:47 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_gif.c,v 1.75 2016/06/28 02:02:56 ozaki-r Exp $	*/
+/*	$NetBSD: in6_gif.c,v 1.76 2016/07/04 04:14:47 knakahara Exp $	*/
 /*	$KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.75 2016/06/28 02:02:56 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.76 2016/07/04 04:14:47 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -215,7 +215,8 @@ in6_gif_input(struct mbuf **mp, int *off
 
 	gifp = (struct ifnet *)encap_getarg(m);
 
-	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
+	if (gifp == NULL || (gifp->if_flags & (IFF_UP|IFF_RUNNING))
+		!= (IFF_UP|IFF_RUNNING)) {
 		m_freem(m);
 		IP6_STATINC(IP6_STAT_NOGIF);
 		return IPPROTO_DONE;

Reply via email to