Lock down global variables in if_gre:
- Add gre_mtx to protect global softc list. - Hold gre_mtx over various list operations (insert, delete). - Centralize if_gre interface teardown in gre_destroy(), and call this from modevent unload and gre_clone_destroy(). - Export gre_mtx to ip_gre.c, which walks the gre list to look up gre interfaces during encapsulation. Add a wonking comment on how we need some sort of drain/reference count mechanism to keep gre references alive while in use and simultaneous destroy. This commit does not lockdown softc data, which follows in a future commit.
This commit is contained in:
parent
7676d865bd
commit
bdae44a844
@ -91,6 +91,11 @@
|
||||
|
||||
#define GRENAME "gre"
|
||||
|
||||
/*
|
||||
* gre_mtx protects all global variables in if_gre.c.
|
||||
* XXX: gre_softc data not protected yet.
|
||||
*/
|
||||
struct mtx gre_mtx;
|
||||
static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation");
|
||||
|
||||
struct gre_softc_head gre_softc_list;
|
||||
@ -149,6 +154,7 @@ static void
|
||||
greattach(void)
|
||||
{
|
||||
|
||||
mtx_init(&gre_mtx, "gre_mtx", NULL, MTX_DEF);
|
||||
LIST_INIT(&gre_softc_list);
|
||||
if_clone_attach(&gre_cloner);
|
||||
}
|
||||
@ -181,24 +187,35 @@ gre_clone_create(ifc, unit)
|
||||
sc->wccp_ver = WCCP_V1;
|
||||
if_attach(&sc->sc_if);
|
||||
bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
|
||||
mtx_lock(&gre_mtx);
|
||||
LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
|
||||
mtx_unlock(&gre_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
gre_destroy(struct gre_softc *sc)
|
||||
{
|
||||
|
||||
#ifdef INET
|
||||
if (sc->encap != NULL)
|
||||
encap_detach(sc->encap);
|
||||
#endif
|
||||
bpfdetach(&sc->sc_if);
|
||||
if_detach(&sc->sc_if);
|
||||
free(sc, M_GRE);
|
||||
}
|
||||
|
||||
static void
|
||||
gre_clone_destroy(ifp)
|
||||
struct ifnet *ifp;
|
||||
{
|
||||
struct gre_softc *sc = ifp->if_softc;
|
||||
|
||||
#ifdef INET
|
||||
if (sc->encap != NULL)
|
||||
encap_detach(sc->encap);
|
||||
#endif
|
||||
mtx_lock(&gre_mtx);
|
||||
LIST_REMOVE(sc, sc_list);
|
||||
bpfdetach(ifp);
|
||||
if_detach(ifp);
|
||||
free(sc, M_GRE);
|
||||
mtx_unlock(&gre_mtx);
|
||||
gre_destroy(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -727,6 +744,7 @@ gre_in_cksum(u_int16_t *p, u_int len)
|
||||
static int
|
||||
gremodevent(module_t mod, int type, void *data)
|
||||
{
|
||||
struct gre_softc *sc;
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
@ -735,8 +753,15 @@ gremodevent(module_t mod, int type, void *data)
|
||||
case MOD_UNLOAD:
|
||||
if_clone_detach(&gre_cloner);
|
||||
|
||||
while (!LIST_EMPTY(&gre_softc_list))
|
||||
gre_clone_destroy(&LIST_FIRST(&gre_softc_list)->sc_if);
|
||||
mtx_lock(&gre_mtx);
|
||||
while ((sc = LIST_FIRST(&gre_softc_list)) != NULL) {
|
||||
LIST_REMOVE(sc, sc_list);
|
||||
mtx_unlock(&gre_mtx);
|
||||
gre_destroy(sc);
|
||||
mtx_lock(&gre_mtx);
|
||||
}
|
||||
mtx_unlock(&gre_mtx);
|
||||
mtx_destroy(&gre_mtx);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -176,6 +176,7 @@ struct mobip_h {
|
||||
|
||||
#ifdef _KERNEL
|
||||
LIST_HEAD(gre_softc_head, gre_softc);
|
||||
extern struct mtx gre_mtx;
|
||||
extern struct gre_softc_head gre_softc_list;
|
||||
|
||||
u_int16_t gre_in_cksum(u_int16_t *, u_int);
|
||||
|
@ -314,6 +314,13 @@ gre_mobile_input(m, va_alist)
|
||||
|
||||
/*
|
||||
* Find the gre interface associated with our src/dst/proto set.
|
||||
*
|
||||
* XXXRW: Need some sort of drain/refcount mechanism so that the softc
|
||||
* reference remains valid after it's returned from gre_lookup(). Right
|
||||
* now, I'm thinking it should be reference-counted with a gre_dropref()
|
||||
* when the caller is done with the softc. This is complicated by how
|
||||
* to handle destroying the gre softc; probably using a gre_drain() in
|
||||
* in_gre.c during destroy.
|
||||
*/
|
||||
static struct gre_softc *
|
||||
gre_lookup(m, proto)
|
||||
@ -323,14 +330,18 @@ gre_lookup(m, proto)
|
||||
struct ip *ip = mtod(m, struct ip *);
|
||||
struct gre_softc *sc;
|
||||
|
||||
mtx_lock(&gre_mtx);
|
||||
for (sc = LIST_FIRST(&gre_softc_list); sc != NULL;
|
||||
sc = LIST_NEXT(sc, sc_list)) {
|
||||
if ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
|
||||
(sc->g_src.s_addr == ip->ip_dst.s_addr) &&
|
||||
(sc->g_proto == proto) &&
|
||||
((sc->sc_if.if_flags & IFF_UP) != 0))
|
||||
((sc->sc_if.if_flags & IFF_UP) != 0)) {
|
||||
mtx_unlock(&gre_mtx);
|
||||
return (sc);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&gre_mtx);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user