From a7f5886ec7e123268dc483535b7c6cd2b3635027 Mon Sep 17 00:00:00 2001 From: Hiroki Sato Date: Sun, 21 Sep 2014 03:55:04 +0000 Subject: [PATCH] Virtualize interface cloner for gif(4). This fixes a panic when destroying a vnet jail which has a gif(4) interface. --- sys/net/if_gif.c | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 7071fef45c90..f4cc3d8ca060 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -92,13 +92,20 @@ static const char gifname[] = "gif"; /* - * gif_mtx protects the global gif_softc_list. + * gif_mtx protects a per-vnet gif_softc_list. */ -static struct mtx gif_mtx; +static VNET_DEFINE(struct mtx, gif_mtx); +#define V_gif_mtx VNET(gif_mtx) static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); static VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); #define V_gif_softc_list VNET(gif_softc_list) +#define GIF_LIST_LOCK_INIT(x) mtx_init(&V_gif_mtx, "gif_mtx", \ + NULL, MTX_DEF) +#define GIF_LIST_LOCK_DESTROY(x) mtx_destroy(&V_gif_mtx) +#define GIF_LIST_LOCK(x) mtx_lock(&V_gif_mtx) +#define GIF_LIST_UNLOCK(x) mtx_unlock(&V_gif_mtx) + void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); void (*ng_gif_attach_p)(struct ifnet *ifp); @@ -107,7 +114,8 @@ void (*ng_gif_detach_p)(struct ifnet *ifp); static void gif_start(struct ifnet *); static int gif_clone_create(struct if_clone *, int, caddr_t); static void gif_clone_destroy(struct ifnet *); -static struct if_clone *gif_cloner; +static VNET_DEFINE(struct if_clone *, gif_cloner); +#define V_gif_cloner VNET(gif_cloner) static int gifmodevent(module_t, int, void *); @@ -189,9 +197,9 @@ gif_clone_create(struct if_clone *ifc, int unit, caddr_t params) if (ng_gif_attach_p != NULL) (*ng_gif_attach_p)(GIF2IFP(sc)); - mtx_lock(&gif_mtx); + GIF_LIST_LOCK(); LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); - mtx_unlock(&gif_mtx); + GIF_LIST_UNLOCK(); return (0); } @@ -204,9 +212,9 @@ gif_clone_destroy(struct ifnet *ifp) #endif struct gif_softc *sc = ifp->if_softc; - mtx_lock(&gif_mtx); + GIF_LIST_LOCK(); LIST_REMOVE(sc, gif_list); - mtx_unlock(&gif_mtx); + GIF_LIST_UNLOCK(); gif_delete_tunnel(ifp); #ifdef INET6 @@ -238,9 +246,22 @@ vnet_gif_init(const void *unused __unused) { LIST_INIT(&V_gif_softc_list); + GIF_LIST_LOCK_INIT(); + V_gif_cloner = if_clone_simple(gifname, gif_clone_create, + gif_clone_destroy, 0); } -VNET_SYSINIT(vnet_gif_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vnet_gif_init, - NULL); +VNET_SYSINIT(vnet_gif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_gif_init, NULL); + +static void +vnet_gif_uninit(const void *unused __unused) +{ + + if_clone_detach(V_gif_cloner); + GIF_LIST_LOCK_DESTROY(); +} +VNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_gif_uninit, NULL); static int gifmodevent(module_t mod, int type, void *data) @@ -248,19 +269,12 @@ gifmodevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: - mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF); - gif_cloner = if_clone_simple(gifname, gif_clone_create, - gif_clone_destroy, 0); - break; - case MOD_UNLOAD: - if_clone_detach(gif_cloner); - mtx_destroy(&gif_mtx); break; default: - return EOPNOTSUPP; + return (EOPNOTSUPP); } - return 0; + return (0); } static moduledata_t gif_mod = { @@ -364,7 +378,7 @@ gif_start(struct ifnet *ifp) #endif #ifdef INET6 if (sc->gif_psrc->sa_family == AF_INET6) - m->m_pkthdr.len -= GIF_HDR_LEN6; + m->m_pkthdr.len -= GIF_HDR_LEN6; #endif #endif /* @@ -373,6 +387,7 @@ gif_start(struct ifnet *ifp) */ af = m->m_pkthdr.csum_data; + /* override to IPPROTO_ETHERIP for bridged traffic */ if (ifp->if_bridge) af = AF_LINK; @@ -381,7 +396,6 @@ gif_start(struct ifnet *ifp) /* Done by IFQ_HANDOFF */ /* if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);*/ - /* override to IPPROTO_ETHERIP for bridged traffic */ M_SETFIB(m, sc->gif_fibnum); /* inner AF-specific encapsulation */ @@ -904,7 +918,7 @@ gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) struct sockaddr *osrc, *odst, *sa; int error = 0; - mtx_lock(&gif_mtx); + GIF_LIST_LOCK(); LIST_FOREACH(sc2, &V_gif_softc_list, gif_list) { if (sc2 == sc) continue; @@ -924,13 +938,13 @@ gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { error = EADDRNOTAVAIL; - mtx_unlock(&gif_mtx); + GIF_LIST_UNLOCK(); goto bad; } /* XXX both end must be valid? (I mean, not 0.0.0.0) */ } - mtx_unlock(&gif_mtx); + GIF_LIST_UNLOCK(); /* XXX we can detach from both, but be polite just in case */ if (sc->gif_psrc)