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;