Skip to content

Commit

Permalink
Get closer to a VIMAGE network stack teardown from top to bottom rather
Browse files Browse the repository at this point in the history
than removing the network interfaces first. This change is rather larger
and convoluted as the ordering requirements cannot be separated.

Move the pfil(9) framework to SI_SUB_PROTO_PFIL, move Firewalls and
related modules to their own SI_SUB_PROTO_FIREWALL.
Move initialization of "physical" interfaces to SI_SUB_DRIVERS,
move virtual (cloned) interfaces to SI_SUB_PSEUDO.
Move Multicast to SI_SUB_PROTO_MC.

Re-work parts of multicast initialisation and teardown, not taking the
huge amount of memory into account if used as a module yet.

For interface teardown we try to do as many of them as we can on
SI_SUB_INIT_IF, but for some this makes no sense, e.g., when tunnelling
over a higher layer protocol such as IP. In that case the interface
has to go along (or before) the higher layer protocol is shutdown.

Kernel hhooks need to go last on teardown as they may be used at various
higher layers and we cannot remove them before we cleaned up the higher
layers.

For interface teardown there are multiple paths:
(a) a cloned interface is destroyed (inside a VIMAGE or in the base system),
(b) any interface is moved from a virtual network stack to a different
network stack ("vmove"), or (c) a virtual network stack is being shut down.
All code paths go through if_detach_internal() where we, depending on the
vmove flag or the vnet state, make a decision on how much to shut down;
in case we are destroying a VNET the individual protocol layers will
cleanup their own parts thus we cannot do so again for each interface as
we end up with, e.g., double-frees, destroying locks twice or acquiring
already destroyed locks.
When calling into protocol cleanups we equally have to tell them
whether they need to detach upper layer protocols ("ulp") or not
(e.g., in6_ifdetach()).

Provide or enahnce helper functions to do proper cleanup at a protocol
rather than at an interface level.

Approved by:		re (hrs)
Obtained from:		projects/vnet
Reviewed by:		gnn, jhb
Sponsored by:		The FreeBSD Foundation
MFC after:		2 weeks
Differential Revision:	https://reviews.freebsd.org/D6747
  • Loading branch information
Bjoern A. Zeeb authored and Bjoern A. Zeeb committed Jun 21, 2016
1 parent 1fe8c30 commit 89856f7
Show file tree
Hide file tree
Showing 39 changed files with 326 additions and 141 deletions.
2 changes: 1 addition & 1 deletion sys/contrib/ipfilter/netinet/mlfk_ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ static moduledata_t ipfiltermod = {
};


DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY);
#ifdef MODULE_VERSION
MODULE_VERSION(ipfilter, 1);
#endif
Expand Down
6 changes: 5 additions & 1 deletion sys/dev/usb/net/usb_ethernet.c
Original file line number Diff line number Diff line change
Expand Up @@ -641,5 +641,9 @@ uether_rxflush(struct usb_ether *ue)
}
}

DECLARE_MODULE(uether, uether_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
/*
* USB net drivers are run by DRIVER_MODULE() thus SI_SUB_DRIVERS,
* SI_ORDER_MIDDLE. Run uether after that.
*/
DECLARE_MODULE(uether, uether_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
MODULE_VERSION(uether, 1);
4 changes: 2 additions & 2 deletions sys/kern/kern_hhook.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,13 +510,13 @@ hhook_vnet_uninit(const void *unused __unused)
/*
* When a vnet is created and being initialised, init the V_hhook_vhead_list.
*/
VNET_SYSINIT(hhook_vnet_init, SI_SUB_MBUF, SI_ORDER_FIRST,
VNET_SYSINIT(hhook_vnet_init, SI_SUB_INIT_IF, SI_ORDER_FIRST,
hhook_vnet_init, NULL);

/*
* The hhook KPI provides a mechanism for subsystems which export helper hook
* points to clean up on vnet tear down, but in case the KPI is misused,
* provide a function to clean up and free memory for a vnet being destroyed.
*/
VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_MBUF, SI_ORDER_ANY,
VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
hhook_vnet_uninit, NULL);
106 changes: 94 additions & 12 deletions sys/net/if.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,26 +914,34 @@ if_detach(struct ifnet *ifp)
CURVNET_RESTORE();
}

/*
* The vmove flag, if set, indicates that we are called from a callpath
* that is moving an interface to a different vnet instance.
*
* The shutdown flag, if set, indicates that we are called in the
* process of shutting down a vnet instance. Currently only the
* vnet_if_return SYSUNINIT function sets it. Note: we can be called
* on a vnet instance shutdown without this flag being set, e.g., when
* the cloned interfaces are destoyed as first thing of teardown.
*/
static int
if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
{
struct ifaddr *ifa;
int i;
struct domain *dp;
struct ifnet *iter;
int found = 0;
int found = 0, shutdown;

shutdown = (ifp->if_vnet->vnet_state > SI_SUB_VNET &&
ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
IFNET_WLOCK();
TAILQ_FOREACH(iter, &V_ifnet, if_link)
if (iter == ifp) {
TAILQ_REMOVE(&V_ifnet, ifp, if_link);
found = 1;
break;
}
#ifdef VIMAGE
if (found)
curvnet->vnet_ifcnt--;
#endif
IFNET_WUNLOCK();
if (!found) {
/*
Expand All @@ -951,19 +959,58 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
#endif
}

/* Check if this is a cloned interface or not. */
/*
* At this point we know the interface still was on the ifnet list
* and we removed it so we are in a stable state.
*/
#ifdef VIMAGE
curvnet->vnet_ifcnt--;
#endif

/*
* In any case (destroy or vmove) detach us from the groups
* and remove/wait for pending events on the taskq.
* XXX-BZ in theory an interface could still enqueue a taskq change?
*/
if_delgroups(ifp);

taskqueue_drain(taskqueue_swi, &ifp->if_linktask);

/*
* Check if this is a cloned interface or not. Must do even if
* shutting down as a if_vmove_reclaim() would move the ifp and
* the if_clone_addgroup() will have a corrupted string overwise
* from a gibberish pointer.
*/
if (vmove && ifcp != NULL)
*ifcp = if_clone_findifc(ifp);

if_down(ifp);

/*
* Remove/wait for pending events.
* On VNET shutdown abort here as the stack teardown will do all
* the work top-down for us.
*/
if (shutdown) {
/*
* In case of a vmove we are done here without error.
* If we would signal an error it would lead to the same
* abort as if we did not find the ifnet anymore.
* if_detach() calls us in void context and does not care
* about an early abort notification, so life is splendid :)
*/
goto finish_vnet_shutdown;
}

/*
* At this point we are not tearing down a VNET and are either
* going to destroy or vmove the interface and have to cleanup
* accordingly.
*/
taskqueue_drain(taskqueue_swi, &ifp->if_linktask);

/*
* Remove routes and flush queues.
*/
if_down(ifp);
#ifdef ALTQ
if (ALTQ_IS_ENABLED(&ifp->if_snd))
altq_disable(&ifp->if_snd);
Expand Down Expand Up @@ -1018,8 +1065,8 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
}

rt_flushifroutes(ifp);
if_delgroups(ifp);

finish_vnet_shutdown:
/*
* We cannot hold the lock over dom_ifdetach calls as they might
* sleep, for example trying to drain a callout, thus open up the
Expand Down Expand Up @@ -1048,7 +1095,7 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
* unused if_index in target vnet and calls if_grow() if necessary,
* and finally find an unused if_xname for the target vnet.
*/
void
static void
if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
{
struct if_clone *ifc;
Expand Down Expand Up @@ -1115,6 +1162,7 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
{
struct prison *pr;
struct ifnet *difp;
int shutdown;

/* Try to find the prison within our visibility. */
sx_slock(&allprison_lock);
Expand All @@ -1135,12 +1183,22 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
/* XXX Lock interfaces to avoid races. */
CURVNET_SET_QUIET(pr->pr_vnet);
difp = ifunit(ifname);
CURVNET_RESTORE();
if (difp != NULL) {
CURVNET_RESTORE();
prison_free(pr);
return (EEXIST);
}

/* Make sure the VNET is stable. */
shutdown = (ifp->if_vnet->vnet_state > SI_SUB_VNET &&
ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
if (shutdown) {
CURVNET_RESTORE();
prison_free(pr);
return (EBUSY);
}
CURVNET_RESTORE();

/* Move the interface into the child jail/vnet. */
if_vmove(ifp, pr->pr_vnet);

Expand All @@ -1157,6 +1215,7 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid)
struct prison *pr;
struct vnet *vnet_dst;
struct ifnet *ifp;
int shutdown;

/* Try to find the prison within our visibility. */
sx_slock(&allprison_lock);
Expand Down Expand Up @@ -1184,6 +1243,15 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid)
return (EEXIST);
}

/* Make sure the VNET is stable. */
shutdown = (ifp->if_vnet->vnet_state > SI_SUB_VNET &&
ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
if (shutdown) {
CURVNET_RESTORE();
prison_free(pr);
return (EBUSY);
}

/* Get interface back from child jail/vnet. */
if_vmove(ifp, vnet_dst);
CURVNET_RESTORE();
Expand Down Expand Up @@ -2642,8 +2710,22 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
struct ifreq *ifr;
int error;
int oif_flags;
#ifdef VIMAGE
int shutdown;
#endif

CURVNET_SET(so->so_vnet);
#ifdef VIMAGE
/* Make sure the VNET is stable. */
shutdown = (so->so_vnet->vnet_state > SI_SUB_VNET &&
so->so_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
if (shutdown) {
CURVNET_RESTORE();
return (EBUSY);
}
#endif


switch (cmd) {
case SIOCGIFCONF:
error = ifconf(cmd, data);
Expand Down
2 changes: 1 addition & 1 deletion sys/net/if_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ vnet_bridge_uninit(const void *unused __unused)
V_bridge_cloner = NULL;
BRIDGE_LIST_LOCK_DESTROY();
}
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_bridge_uninit, NULL);

static int
Expand Down
4 changes: 2 additions & 2 deletions sys/net/if_disc.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ vnet_disc_init(const void *unused __unused)
V_disc_cloner = if_clone_simple(discname, disc_clone_create,
disc_clone_destroy, 0);
}
VNET_SYSINIT(vnet_disc_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSINIT(vnet_disc_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_disc_init, NULL);

static void
Expand All @@ -146,7 +146,7 @@ vnet_disc_uninit(const void *unused __unused)

if_clone_detach(V_disc_cloner);
}
VNET_SYSUNINIT(vnet_disc_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_disc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
vnet_disc_uninit, NULL);

static int
Expand Down
2 changes: 1 addition & 1 deletion sys/net/if_edsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ vnet_edsc_uninit(const void *unused __unused)
*/
if_clone_detach(V_edsc_cloner);
}
VNET_SYSUNINIT(vnet_edsc_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_edsc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
vnet_edsc_uninit, NULL);

/*
Expand Down
37 changes: 29 additions & 8 deletions sys/net/if_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ enc_clone_destroy(struct ifnet *ifp)
sc = ifp->if_softc;
KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc"));

enc_remove_hhooks(sc);
bpfdetach(ifp);
if_detach(ifp);
if_free(ifp);
Expand Down Expand Up @@ -170,10 +169,6 @@ enc_clone_create(struct if_clone *ifc, int unit, caddr_t params)
ifp->if_softc = sc;
if_attach(ifp);
bpfattach(ifp, DLT_ENC, sizeof(struct enchdr));
if (enc_add_hhooks(sc) != 0) {
enc_clone_destroy(ifp);
return (ENXIO);
}
return (0);
}

Expand Down Expand Up @@ -369,18 +364,44 @@ vnet_enc_init(const void *unused __unused)
V_enc_cloner = if_clone_simple(encname, enc_clone_create,
enc_clone_destroy, 1);
}
VNET_SYSINIT(vnet_enc_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_enc_init, NULL);

static void
vnet_enc_init_proto(void *unused __unused)
{
KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc));

if (enc_add_hhooks(V_enc_sc) != 0)
enc_clone_destroy(V_enc_sc->sc_ifp);
}
VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
vnet_enc_init_proto, NULL);

static void
vnet_enc_uninit(const void *unused __unused)
{
KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc));

if_clone_detach(V_enc_cloner);
}
VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
vnet_enc_uninit, NULL);

/*
* The hhook consumer needs to go before ip[6]_destroy are called on
* SI_ORDER_THIRD.
*/
static void
vnet_enc_uninit_hhook(const void *unused __unused)
{
KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc));

enc_remove_hhooks(V_enc_sc);
}
VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH,
vnet_enc_uninit_hhook, NULL);

static int
enc_modevent(module_t mod, int type, void *data)
{
Expand All @@ -401,4 +422,4 @@ static moduledata_t enc_mod = {
0
};

DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
6 changes: 3 additions & 3 deletions sys/net/if_epair.c
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,7 @@ vnet_epair_init(const void *unused __unused)
netisr_register_vnet(&epair_nh);
#endif
}
VNET_SYSINIT(vnet_epair_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSINIT(vnet_epair_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_epair_init, NULL);

static void
Expand All @@ -975,7 +975,7 @@ vnet_epair_uninit(const void *unused __unused)
#endif
if_clone_detach(V_epair_cloner);
}
VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
vnet_epair_uninit, NULL);

static int
Expand Down Expand Up @@ -1012,5 +1012,5 @@ static moduledata_t epair_mod = {
0
};

DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
MODULE_VERSION(if_epair, 1);
2 changes: 1 addition & 1 deletion sys/net/if_lagg.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ vnet_lagg_uninit(const void *unused __unused)
if_clone_detach(V_lagg_cloner);
LAGG_LIST_LOCK_DESTROY();
}
VNET_SYSUNINIT(vnet_lagg_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_lagg_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
vnet_lagg_uninit, NULL);

static int
Expand Down
4 changes: 2 additions & 2 deletions sys/net/if_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ vnet_loif_init(const void *unused __unused)
1);
#endif
}
VNET_SYSINIT(vnet_loif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSINIT(vnet_loif_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_loif_init, NULL);

#ifdef VIMAGE
Expand All @@ -167,7 +167,7 @@ vnet_loif_uninit(const void *unused __unused)
if_clone_detach(V_lo_cloner);
V_loif = NULL;
}
VNET_SYSUNINIT(vnet_loif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
VNET_SYSUNINIT(vnet_loif_uninit, SI_SUB_INIT_IF, SI_ORDER_SECOND,
vnet_loif_uninit, NULL);
#endif

Expand Down
Loading

0 comments on commit 89856f7

Please sign in to comment.