svn commit: r302054 - in head/sys: contrib/ipfilter/netinet dev/usb/net kern net netgraph netinet netinet6 netipsec netpfil/ipfw netpfil/pf

Navdeep Parhar np at FreeBSD.org
Tue Jun 21 23:59:52 UTC 2016


This causes a panic when a NIC driver module is unloaded from a kernel
without VIMAGE.  if_vnet is NULL and if_detach_internal tries to
dereference it.

Regards,
Navdeep

On 06/21/2016 06:48, Bjoern A. Zeeb wrote:
> Author: bz
> Date: Tue Jun 21 13:48:49 2016
> New Revision: 302054
> URL: https://svnweb.freebsd.org/changeset/base/302054
> 
> Log:
>   Get closer to a VIMAGE network stack teardown from top to bottom rather
>   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
> 
> Modified:
>   head/sys/contrib/ipfilter/netinet/mlfk_ipl.c
>   head/sys/dev/usb/net/usb_ethernet.c
>   head/sys/kern/kern_hhook.c
>   head/sys/net/if.c
>   head/sys/net/if_bridge.c
>   head/sys/net/if_disc.c
>   head/sys/net/if_edsc.c
>   head/sys/net/if_enc.c
>   head/sys/net/if_epair.c
>   head/sys/net/if_lagg.c
>   head/sys/net/if_loop.c
>   head/sys/net/if_vlan.c
>   head/sys/net/pfil.c
>   head/sys/net/route.c
>   head/sys/net/vnet.c
>   head/sys/net/vnet.h
>   head/sys/netgraph/ng_eiface.c
>   head/sys/netgraph/ng_iface.c
>   head/sys/netinet/igmp.c
>   head/sys/netinet/in.c
>   head/sys/netinet/in_var.h
>   head/sys/netinet/ip_id.c
>   head/sys/netinet/ip_input.c
>   head/sys/netinet/ip_mroute.c
>   head/sys/netinet6/in6.c
>   head/sys/netinet6/in6_ifattach.c
>   head/sys/netinet6/in6_ifattach.h
>   head/sys/netinet6/ip6_input.c
>   head/sys/netinet6/ip6_mroute.c
>   head/sys/netinet6/mld6.c
>   head/sys/netinet6/nd6.c
>   head/sys/netinet6/nd6.h
>   head/sys/netipsec/ipsec.c
>   head/sys/netipsec/xform_tcp.c
>   head/sys/netpfil/ipfw/dn_sched.h
>   head/sys/netpfil/ipfw/ip_dummynet.c
>   head/sys/netpfil/ipfw/ip_fw2.c
>   head/sys/netpfil/ipfw/ip_fw_nat.c
>   head/sys/netpfil/pf/pf_ioctl.c
> 
> Modified: head/sys/contrib/ipfilter/netinet/mlfk_ipl.c
> ==============================================================================
> --- head/sys/contrib/ipfilter/netinet/mlfk_ipl.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/contrib/ipfilter/netinet/mlfk_ipl.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -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
> 
> Modified: head/sys/dev/usb/net/usb_ethernet.c
> ==============================================================================
> --- head/sys/dev/usb/net/usb_ethernet.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/dev/usb/net/usb_ethernet.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -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);
> 
> Modified: head/sys/kern/kern_hhook.c
> ==============================================================================
> --- head/sys/kern/kern_hhook.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/kern/kern_hhook.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -510,7 +510,7 @@ hhook_vnet_uninit(const void *unused __u
>  /*
>   * 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);
>  
>  /*
> @@ -518,5 +518,5 @@ VNET_SYSINIT(hhook_vnet_init, SI_SUB_MBU
>   * 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);
> 
> Modified: head/sys/net/if.c
> ==============================================================================
> --- head/sys/net/if.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -914,6 +914,16 @@ 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)
>  {
> @@ -921,8 +931,10 @@ if_detach_internal(struct ifnet *ifp, in
>  	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) {
> @@ -930,10 +942,6 @@ if_detach_internal(struct ifnet *ifp, in
>  			found = 1;
>  			break;
>  		}
> -#ifdef VIMAGE
> -	if (found)
> -		curvnet->vnet_ifcnt--;
> -#endif
>  	IFNET_WUNLOCK();
>  	if (!found) {
>  		/*
> @@ -951,19 +959,58 @@ if_detach_internal(struct ifnet *ifp, in
>  #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);
> @@ -1018,8 +1065,8 @@ if_detach_internal(struct ifnet *ifp, in
>  	}
>  
>  	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
> @@ -1048,7 +1095,7 @@ if_detach_internal(struct ifnet *ifp, in
>   * 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;
> @@ -1115,6 +1162,7 @@ if_vmove_loan(struct thread *td, struct 
>  {
>  	struct prison *pr;
>  	struct ifnet *difp;
> +	int shutdown;
>  
>  	/* Try to find the prison within our visibility. */
>  	sx_slock(&allprison_lock);
> @@ -1135,12 +1183,22 @@ if_vmove_loan(struct thread *td, struct 
>  	/* 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);
>  
> @@ -1157,6 +1215,7 @@ if_vmove_reclaim(struct thread *td, char
>  	struct prison *pr;
>  	struct vnet *vnet_dst;
>  	struct ifnet *ifp;
> + 	int shutdown;
>  
>  	/* Try to find the prison within our visibility. */
>  	sx_slock(&allprison_lock);
> @@ -1184,6 +1243,15 @@ if_vmove_reclaim(struct thread *td, char
>  		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();
> @@ -2642,8 +2710,22 @@ ifioctl(struct socket *so, u_long cmd, c
>  	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);
> 
> Modified: head/sys/net/if_bridge.c
> ==============================================================================
> --- head/sys/net/if_bridge.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_bridge.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -541,7 +541,7 @@ vnet_bridge_uninit(const void *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
> 
> Modified: head/sys/net/if_disc.c
> ==============================================================================
> --- head/sys/net/if_disc.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_disc.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -137,7 +137,7 @@ vnet_disc_init(const void *unused __unus
>  	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
> @@ -146,7 +146,7 @@ vnet_disc_uninit(const void *unused __un
>  
>  	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
> 
> Modified: head/sys/net/if_edsc.c
> ==============================================================================
> --- head/sys/net/if_edsc.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_edsc.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -336,7 +336,7 @@ vnet_edsc_uninit(const void *unused __un
>  	 */
>  	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);
>  
>  /*
> 
> Modified: head/sys/net/if_enc.c
> ==============================================================================
> --- head/sys/net/if_enc.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_enc.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -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);
> @@ -170,10 +169,6 @@ enc_clone_create(struct if_clone *ifc, i
>  	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);
>  }
>  
> @@ -369,18 +364,44 @@ vnet_enc_init(const void *unused __unuse
>  	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)
>  {
> @@ -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);
> 
> Modified: head/sys/net/if_epair.c
> ==============================================================================
> --- head/sys/net/if_epair.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_epair.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -963,7 +963,7 @@ vnet_epair_init(const void *unused __unu
>  	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
> @@ -975,7 +975,7 @@ vnet_epair_uninit(const void *unused __u
>  #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
> @@ -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);
> 
> Modified: head/sys/net/if_lagg.c
> ==============================================================================
> --- head/sys/net/if_lagg.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_lagg.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -271,7 +271,7 @@ vnet_lagg_uninit(const void *unused __un
>  	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
> 
> Modified: head/sys/net/if_loop.c
> ==============================================================================
> --- head/sys/net/if_loop.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_loop.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -156,7 +156,7 @@ vnet_loif_init(const void *unused __unus
>  	    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
> @@ -167,7 +167,7 @@ vnet_loif_uninit(const void *unused __un
>  	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
>  
> 
> Modified: head/sys/net/if_vlan.c
> ==============================================================================
> --- head/sys/net/if_vlan.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/if_vlan.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -823,7 +823,7 @@ vnet_vlan_uninit(const void *unused __un
>  
>  	if_clone_detach(V_vlan_cloner);
>  }
> -VNET_SYSUNINIT(vnet_vlan_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST,
> +VNET_SYSUNINIT(vnet_vlan_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
>      vnet_vlan_uninit, NULL);
>  #endif
>  
> 
> Modified: head/sys/net/pfil.c
> ==============================================================================
> --- head/sys/net/pfil.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/pfil.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -383,17 +383,14 @@ vnet_pfil_uninit(const void *unused __un
>  	PFIL_LOCK_DESTROY_REAL(&V_pfil_lock);
>  }
>  
> -/* Define startup order. */
> -#define	PFIL_SYSINIT_ORDER	SI_SUB_PROTO_BEGIN
> -#define	PFIL_MODEVENT_ORDER	(SI_ORDER_FIRST) /* On boot slot in here. */
> -#define	PFIL_VNET_ORDER		(PFIL_MODEVENT_ORDER + 2) /* Later still. */
> -
>  /*
>   * Starting up.
>   *
>   * VNET_SYSINIT is called for each existing vnet and each new vnet.
> + * Make sure the pfil bits are first before any possible subsystem which
> + * might piggyback on the SI_SUB_PROTO_PFIL.
>   */
> -VNET_SYSINIT(vnet_pfil_init, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER,
> +VNET_SYSINIT(vnet_pfil_init, SI_SUB_PROTO_PFIL, SI_ORDER_FIRST,
>      vnet_pfil_init, NULL);
>   
>  /*
> @@ -401,5 +398,5 @@ VNET_SYSINIT(vnet_pfil_init, PFIL_SYSINI
>   *
>   * VNET_SYSUNINIT is called for each exiting vnet as it exits.
>   */
> -VNET_SYSUNINIT(vnet_pfil_uninit, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER,
> +VNET_SYSUNINIT(vnet_pfil_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_FIRST,
>      vnet_pfil_uninit, NULL);
> 
> Modified: head/sys/net/route.c
> ==============================================================================
> --- head/sys/net/route.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/route.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -334,7 +334,7 @@ vnet_route_uninit(const void *unused __u
>  	free(V_rt_tables, M_RTABLE);
>  	uma_zdestroy(V_rtzone);
>  }
> -VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
> +VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
>      vnet_route_uninit, 0);
>  #endif
>  
> 
> Modified: head/sys/net/vnet.c
> ==============================================================================
> --- head/sys/net/vnet.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/vnet.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -331,8 +331,7 @@ vnet_init_done(void *unused __unused)
>  
>  	curvnet = NULL;
>  }
> -
> -SYSINIT(vnet_init_done, SI_SUB_VNET_DONE, SI_ORDER_FIRST, vnet_init_done,
> +SYSINIT(vnet_init_done, SI_SUB_VNET_DONE, SI_ORDER_ANY, vnet_init_done,
>      NULL);
>  
>  /*
> 
> Modified: head/sys/net/vnet.h
> ==============================================================================
> --- head/sys/net/vnet.h	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/net/vnet.h	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -111,8 +111,8 @@ vnet_##name##_init(const void *unused)	\
>  {					\
>  	VNET_PCPUSTAT_ALLOC(name, M_WAITOK);	\
>  }					\
> -VNET_SYSINIT(vnet_ ## name ## _init, SI_SUB_PROTO_IFATTACHDOMAIN,	\
> -    SI_ORDER_ANY, vnet_ ## name ## _init, NULL)
> +VNET_SYSINIT(vnet_ ## name ## _init, SI_SUB_INIT_IF,			\
> +    SI_ORDER_FIRST, vnet_ ## name ## _init, NULL)
>  
>  #define	VNET_PCPUSTAT_SYSUNINIT(name)					\
>  static void								\
> @@ -120,8 +120,8 @@ vnet_##name##_uninit(const void *unused)
>  {									\
>  	VNET_PCPUSTAT_FREE(name);					\
>  }									\
> -VNET_SYSUNINIT(vnet_ ## name ## _uninit, SI_SUB_PROTO_IFATTACHDOMAIN,	\
> -    SI_ORDER_ANY, vnet_ ## name ## _uninit, NULL)
> +VNET_SYSUNINIT(vnet_ ## name ## _uninit, SI_SUB_INIT_IF,		\
> +    SI_ORDER_FIRST, vnet_ ## name ## _uninit, NULL)
>  
>  #ifdef SYSCTL_OID
>  #define	SYSCTL_VNET_PCPUSTAT(parent, nbr, name, type, array, desc)	\
> 
> Modified: head/sys/netgraph/ng_eiface.c
> ==============================================================================
> --- head/sys/netgraph/ng_eiface.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netgraph/ng_eiface.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -679,5 +679,5 @@ vnet_ng_eiface_uninit(const void *unused
>  
>  	delete_unrhdr(V_ng_eiface_unit);
>  }
> -VNET_SYSUNINIT(vnet_ng_eiface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
> +VNET_SYSUNINIT(vnet_ng_eiface_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
>     vnet_ng_eiface_uninit, NULL);
> 
> Modified: head/sys/netgraph/ng_iface.c
> ==============================================================================
> --- head/sys/netgraph/ng_iface.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netgraph/ng_iface.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -786,5 +786,5 @@ vnet_ng_iface_uninit(const void *unused)
>  
>  	delete_unrhdr(V_ng_iface_unit);
>  }
> -VNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
> +VNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
>      vnet_ng_iface_uninit, NULL);
> 
> Modified: head/sys/netinet/igmp.c
> ==============================================================================
> --- head/sys/netinet/igmp.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet/igmp.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -227,7 +227,8 @@ static VNET_DEFINE(int, current_state_ti
>  #define	V_state_change_timers_running	VNET(state_change_timers_running)
>  #define	V_current_state_timers_running	VNET(current_state_timers_running)
>  
> -static VNET_DEFINE(LIST_HEAD(, igmp_ifsoftc), igi_head);
> +static VNET_DEFINE(LIST_HEAD(, igmp_ifsoftc), igi_head) =
> +    LIST_HEAD_INITIALIZER(igi_head);
>  static VNET_DEFINE(struct igmpstat, igmpstat) = {
>  	.igps_version = IGPS_VERSION_3,
>  	.igps_len = sizeof(struct igmpstat),
> @@ -701,10 +702,6 @@ igi_delete_locked(const struct ifnet *if
>  			return;
>  		}
>  	}
> -
> -#ifdef INVARIANTS
> -	panic("%s: igmp_ifsoftc not found for ifp %p\n", __func__,  ifp);
> -#endif
>  }
>  
>  /*
> @@ -3595,57 +3592,28 @@ igmp_rec_type_to_str(const int type)
>  }
>  #endif
>  
> -static void
> -igmp_init(void *unused __unused)
> -{
> -
> -	CTR1(KTR_IGMPV3, "%s: initializing", __func__);
> -
> -	IGMP_LOCK_INIT();
> -
> -	m_raopt = igmp_ra_alloc();
> -
> -	netisr_register(&igmp_nh);
> -}
> -SYSINIT(igmp_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, igmp_init, NULL);
> -
> -static void
> -igmp_uninit(void *unused __unused)
> -{
> -
> -	CTR1(KTR_IGMPV3, "%s: tearing down", __func__);
> -
> -	netisr_unregister(&igmp_nh);
> -
> -	m_free(m_raopt);
> -	m_raopt = NULL;
> -
> -	IGMP_LOCK_DESTROY();
> -}
> -SYSUNINIT(igmp_uninit, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, igmp_uninit, NULL);
> -
> +#ifdef VIMAGE
>  static void
>  vnet_igmp_init(const void *unused __unused)
>  {
>  
> -	CTR1(KTR_IGMPV3, "%s: initializing", __func__);
> -
> -	LIST_INIT(&V_igi_head);
> +	netisr_register_vnet(&igmp_nh);
>  }
> -VNET_SYSINIT(vnet_igmp_init, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_igmp_init,
> -    NULL);
> +VNET_SYSINIT(vnet_igmp_init, SI_SUB_PROTO_MC, SI_ORDER_ANY,
> +    vnet_igmp_init, NULL);
>  
>  static void
>  vnet_igmp_uninit(const void *unused __unused)
>  {
>  
> +	/* This can happen when we shutdown the entire network stack. */
>  	CTR1(KTR_IGMPV3, "%s: tearing down", __func__);
>  
> -	KASSERT(LIST_EMPTY(&V_igi_head),
> -	    ("%s: igi list not empty; ifnets not detached?", __func__));
> +	netisr_unregister_vnet(&igmp_nh);
>  }
> -VNET_SYSUNINIT(vnet_igmp_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
> +VNET_SYSUNINIT(vnet_igmp_uninit, SI_SUB_PROTO_MC, SI_ORDER_ANY,
>      vnet_igmp_uninit, NULL);
> +#endif
>  
>  #ifdef DDB
>  DB_SHOW_COMMAND(igi_list, db_show_igi_list)
> @@ -3682,14 +3650,24 @@ static int
>  igmp_modevent(module_t mod, int type, void *unused __unused)
>  {
>  
> -    switch (type) {
> -    case MOD_LOAD:
> -    case MOD_UNLOAD:
> -	break;
> -    default:
> -	return (EOPNOTSUPP);
> -    }
> -    return (0);
> +	switch (type) {
> +	case MOD_LOAD:
> +		CTR1(KTR_IGMPV3, "%s: initializing", __func__);
> +		IGMP_LOCK_INIT();
> +		m_raopt = igmp_ra_alloc();
> +		netisr_register(&igmp_nh);
> +		break;
> +	case MOD_UNLOAD:
> +		CTR1(KTR_IGMPV3, "%s: tearing down", __func__);
> +		netisr_unregister(&igmp_nh);
> +		m_free(m_raopt);
> +		m_raopt = NULL;
> +		IGMP_LOCK_DESTROY();
> +		break;
> +	default:
> +		return (EOPNOTSUPP);
> +	}
> +	return (0);
>  }
>  
>  static moduledata_t igmp_mod = {
> @@ -3697,4 +3675,4 @@ static moduledata_t igmp_mod = {
>      igmp_modevent,
>      0
>  };
> -DECLARE_MODULE(igmp, igmp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
> +DECLARE_MODULE(igmp, igmp_mod, SI_SUB_PROTO_MC, SI_ORDER_MIDDLE);
> 
> Modified: head/sys/netinet/in.c
> ==============================================================================
> --- head/sys/netinet/in.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet/in.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -895,6 +895,39 @@ in_scrubprefix(struct in_ifaddr *target,
>  
>  #undef rtinitflags
>  
> +void
> +in_ifscrub_all(void)
> +{
> +	struct ifnet *ifp;
> +	struct ifaddr *ifa, *nifa;
> +	struct ifaliasreq ifr;
> +
> +	IFNET_RLOCK();
> +	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
> +		/* Cannot lock here - lock recursion. */
> +		/* IF_ADDR_RLOCK(ifp); */
> +		TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
> +			if (ifa->ifa_addr->sa_family != AF_INET)
> +				continue;
> +
> +			/*
> +			 * This is ugly but the only way for legacy IP to
> +			 * cleanly remove addresses and everything attached.
> +			 */
> +			bzero(&ifr, sizeof(ifr));
> +			ifr.ifra_addr = *ifa->ifa_addr;
> +			if (ifa->ifa_dstaddr)
> +			ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
> +			(void)in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr,
> +			    ifp, NULL);
> +		}
> +		/* IF_ADDR_RUNLOCK(ifp); */
> +		in_purgemaddrs(ifp);
> +		igmp_domifdetach(ifp);
> +	}
> +	IFNET_RUNLOCK();
> +}
> +
>  /*
>   * Return 1 if the address might be a local broadcast address.
>   */
> 
> Modified: head/sys/netinet/in_var.h
> ==============================================================================
> --- head/sys/netinet/in_var.h	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet/in_var.h	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -376,6 +376,7 @@ int	in_control(struct socket *, u_long, 
>  	    struct thread *);
>  int	in_addprefix(struct in_ifaddr *, int);
>  int	in_scrubprefix(struct in_ifaddr *, u_int);
> +void	in_ifscrub_all(void);
>  void	ip_input(struct mbuf *);
>  void	ip_direct_input(struct mbuf *);
>  void	in_ifadown(struct ifaddr *ifa, int);
> 
> Modified: head/sys/netinet/ip_id.c
> ==============================================================================
> --- head/sys/netinet/ip_id.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet/ip_id.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -294,4 +294,4 @@ ipid_sysuninit(void)
>  	counter_u64_free(V_ip_id);
>  	mtx_destroy(&V_ip_id_mtx);
>  }
> -VNET_SYSUNINIT(ip_id, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, ipid_sysuninit, NULL);
> +VNET_SYSUNINIT(ip_id, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ipid_sysuninit, NULL);
> 
> Modified: head/sys/netinet/ip_input.c
> ==============================================================================
> --- head/sys/netinet/ip_input.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet/ip_input.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -370,6 +370,7 @@ ip_init(void)
>  static void
>  ip_destroy(void *unused __unused)
>  {
> +	struct ifnet *ifp;
>  	int error;
>  
>  #ifdef	RSS
> @@ -393,11 +394,21 @@ ip_destroy(void *unused __unused)
>  		    "type HHOOK_TYPE_IPSEC_OUT, id HHOOK_IPSEC_INET: "
>  		    "error %d returned\n", __func__, error);
>  	}
> -	/* Cleanup in_ifaddr hash table; should be empty. */
> -	hashdestroy(V_in_ifaddrhashtbl, M_IFADDR, V_in_ifaddrhmask);
> +
> +	/* Remove the IPv4 addresses from all interfaces. */
> +	in_ifscrub_all();
> +
> +	/* Make sure the IPv4 routes are gone as well. */
> +	IFNET_RLOCK();
> +	TAILQ_FOREACH(ifp, &V_ifnet, if_link)
> +		rt_flushifroutes_af(ifp, AF_INET);
> +	IFNET_RUNLOCK();
>  
>  	/* Destroy IP reassembly queue. */
>  	ipreass_destroy();
> +
> +	/* Cleanup in_ifaddr hash table; should be empty. */
> +	hashdestroy(V_in_ifaddrhashtbl, M_IFADDR, V_in_ifaddrhmask);
>  }
>  
>  VNET_SYSUNINIT(ip, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip_destroy, NULL);
> 
> Modified: head/sys/netinet/ip_mroute.c
> ==============================================================================
> --- head/sys/netinet/ip_mroute.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet/ip_mroute.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -2822,7 +2822,7 @@ vnet_mroute_init(const void *unused __un
>  	callout_init(&V_bw_meter_ch, 1);
>  }
>  
> -VNET_SYSINIT(vnet_mroute_init, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_mroute_init,
> +VNET_SYSINIT(vnet_mroute_init, SI_SUB_PROTO_MC, SI_ORDER_ANY, vnet_mroute_init,
>  	NULL);
>  
>  static void
> @@ -2833,7 +2833,7 @@ vnet_mroute_uninit(const void *unused __
>  	V_nexpire = NULL;
>  }
>  
> -VNET_SYSUNINIT(vnet_mroute_uninit, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, 
> +VNET_SYSUNINIT(vnet_mroute_uninit, SI_SUB_PROTO_MC, SI_ORDER_MIDDLE, 
>  	vnet_mroute_uninit, NULL);
>  
>  static int
> @@ -2946,4 +2946,4 @@ static moduledata_t ip_mroutemod = {
>      0
>  };
>  
> -DECLARE_MODULE(ip_mroute, ip_mroutemod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
> +DECLARE_MODULE(ip_mroute, ip_mroutemod, SI_SUB_PROTO_MC, SI_ORDER_MIDDLE);
> 
> Modified: head/sys/netinet6/in6.c
> ==============================================================================
> --- head/sys/netinet6/in6.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/in6.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -2419,7 +2419,7 @@ in6_domifdetach(struct ifnet *ifp, void 
>  
>  	mld_domifdetach(ifp);
>  	scope6_ifdetach(ext->scope6_id);
> -	nd6_ifdetach(ext->nd_ifinfo);
> +	nd6_ifdetach(ifp, ext->nd_ifinfo);
>  	lltable_free(ext->lltable);
>  	COUNTER_ARRAY_FREE(ext->in6_ifstat,
>  	    sizeof(struct in6_ifstat) / sizeof(uint64_t));
> 
> Modified: head/sys/netinet6/in6_ifattach.c
> ==============================================================================
> --- head/sys/netinet6/in6_ifattach.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/in6_ifattach.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -761,19 +761,30 @@ in6_ifattach(struct ifnet *ifp, struct i
>  
>  /*
>   * NOTE: in6_ifdetach() does not support loopback if at this moment.
> - * We don't need this function in bsdi, because interfaces are never removed
> - * from the ifnet list in bsdi.
> + *
> + * When shutting down a VNET we clean up layers top-down.  In that case
> + * upper layer protocols (ulp) are cleaned up already and locks are destroyed
> + * and we must not call into these cleanup functions anymore, thus purgeulp
> + * is set to 0 in that case by in6_ifdetach_destroy().
> + * The normal case of destroying a (cloned) interface still needs to cleanup
> + * everything related to the interface and will have purgeulp set to 1.
>   */
> -void
> -in6_ifdetach(struct ifnet *ifp)
> +static void
> +_in6_ifdetach(struct ifnet *ifp, int purgeulp)
>  {
>  	struct ifaddr *ifa, *next;
>  
>  	if (ifp->if_afdata[AF_INET6] == NULL)
>  		return;
>  
> -	/* remove neighbor management table */
> -	nd6_purge(ifp);
> +	/*
> +	 * Remove neighbor management table.
> +	 * Enabling the nd6_purge will panic on vmove for interfaces on VNET
> +	 * teardown as the IPv6 layer is cleaned up already and the locks
> +	 * are destroyed.
> +	 */
> +	if (purgeulp)
> +		nd6_purge(ifp);
>  
>  	/*
>  	 * nuke any of IPv6 addresses we have
> @@ -784,9 +795,11 @@ in6_ifdetach(struct ifnet *ifp)
>  			continue;
>  		in6_purgeaddr(ifa);
>  	}
> -	in6_pcbpurgeif0(&V_udbinfo, ifp);
> -	in6_pcbpurgeif0(&V_ulitecbinfo, ifp);
> -	in6_pcbpurgeif0(&V_ripcbinfo, ifp);
> +	if (purgeulp) {
> +		in6_pcbpurgeif0(&V_udbinfo, ifp);
> +		in6_pcbpurgeif0(&V_ulitecbinfo, ifp);
> +		in6_pcbpurgeif0(&V_ripcbinfo, ifp);
> +	}
>  	/* leave from all multicast groups joined */
>  	in6_purgemaddrs(ifp);
>  
> @@ -798,7 +811,22 @@ in6_ifdetach(struct ifnet *ifp)
>  	 * prefixes after removing all addresses above.
>  	 * (Or can we just delay calling nd6_purge until at this point?)
>  	 */
> -	nd6_purge(ifp);
> +	if (purgeulp)
> +		nd6_purge(ifp);
> +}
> +
> +void
> +in6_ifdetach(struct ifnet *ifp)
> +{
> +
> +	_in6_ifdetach(ifp, 1);
> +}
> +
> +void
> +in6_ifdetach_destroy(struct ifnet *ifp)
> +{
> +
> +	_in6_ifdetach(ifp, 0);
>  }
>  
>  int
> 
> Modified: head/sys/netinet6/in6_ifattach.h
> ==============================================================================
> --- head/sys/netinet6/in6_ifattach.h	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/in6_ifattach.h	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -37,6 +37,7 @@
>  void in6_ifattach(struct ifnet *, struct ifnet *);
>  void in6_ifattach_destroy(void);
>  void in6_ifdetach(struct ifnet *);
> +void in6_ifdetach_destroy(struct ifnet *);
>  int in6_get_tmpifid(struct ifnet *, u_int8_t *, const u_int8_t *, int);
>  void in6_tmpaddrtimer(void *);
>  int in6_get_hw_ifid(struct ifnet *, struct in6_addr *);
> 
> Modified: head/sys/netinet6/ip6_input.c
> ==============================================================================
> --- head/sys/netinet6/ip6_input.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/ip6_input.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -113,6 +113,7 @@ __FBSDID("$FreeBSD$");
>  #include <netinet/icmp6.h>
>  #include <netinet6/scope6_var.h>
>  #include <netinet6/in6_ifattach.h>
> +#include <netinet6/mld6_var.h>
>  #include <netinet6/nd6.h>
>  #include <netinet6/in6_rss.h>
>  
> @@ -314,6 +315,8 @@ ip6proto_unregister(short ip6proto)
>  static void
>  ip6_destroy(void *unused __unused)
>  {
> +	struct ifaddr *ifa, *nifa;
> +	struct ifnet *ifp;
>  	int error;
>  
>  #ifdef RSS
> @@ -336,9 +339,30 @@ ip6_destroy(void *unused __unused)
>  		    "type HHOOK_TYPE_IPSEC_OUT, id HHOOK_IPSEC_INET6: "
>  		    "error %d returned\n", __func__, error);
>  	}
> -	hashdestroy(V_in6_ifaddrhashtbl, M_IFADDR, V_in6_ifaddrhmask);
> +
> +	/* Cleanup addresses. */
> +	IFNET_RLOCK();
> +	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
> +		/* Cannot lock here - lock recursion. */
> +		/* IF_ADDR_LOCK(ifp); */
> +		TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
> +
> +			if (ifa->ifa_addr->sa_family != AF_INET6)
> +				continue;
> +			in6_purgeaddr(ifa);
> +		}
> +		/* IF_ADDR_UNLOCK(ifp); */
> +		in6_ifdetach_destroy(ifp);
> +		mld_domifdetach(ifp);
> +		/* Make sure any routes are gone as well. */
> +		rt_flushifroutes_af(ifp, AF_INET6);
> +	}
> +	IFNET_RUNLOCK();
> +
>  	nd6_destroy();
>  	in6_ifattach_destroy();
> +
> +	hashdestroy(V_in6_ifaddrhashtbl, M_IFADDR, V_in6_ifaddrhmask);
>  }
>  
>  VNET_SYSUNINIT(inet6, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_destroy, NULL);
> 
> Modified: head/sys/netinet6/ip6_mroute.c
> ==============================================================================
> --- head/sys/netinet6/ip6_mroute.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/ip6_mroute.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -1966,4 +1966,4 @@ static moduledata_t ip6_mroutemod = {
>  	0
>  };
>  
> -DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PSEUDO, SI_ORDER_ANY);
> +DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PROTO_MC, SI_ORDER_ANY);
> 
> Modified: head/sys/netinet6/mld6.c
> ==============================================================================
> --- head/sys/netinet6/mld6.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/mld6.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -612,9 +612,6 @@ mli_delete_locked(const struct ifnet *if
>  			return;
>  		}
>  	}
> -#ifdef INVARIANTS
> -	panic("%s: mld_ifsoftc not found for ifp %p\n", __func__,  ifp);
> -#endif
>  }
>  
>  /*
> @@ -3265,7 +3262,7 @@ mld_init(void *unused __unused)
>  	mld_po.ip6po_prefer_tempaddr = IP6PO_TEMPADDR_NOTPREFER;
>  	mld_po.ip6po_flags = IP6PO_DONTFRAG;
>  }
> -SYSINIT(mld_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, mld_init, NULL);
> +SYSINIT(mld_init, SI_SUB_PROTO_MC, SI_ORDER_MIDDLE, mld_init, NULL);
>  
>  static void
>  mld_uninit(void *unused __unused)
> @@ -3274,7 +3271,7 @@ mld_uninit(void *unused __unused)
>  	CTR1(KTR_MLD, "%s: tearing down", __func__);
>  	MLD_LOCK_DESTROY();
>  }
> -SYSUNINIT(mld_uninit, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, mld_uninit, NULL);
> +SYSUNINIT(mld_uninit, SI_SUB_PROTO_MC, SI_ORDER_MIDDLE, mld_uninit, NULL);
>  
>  static void
>  vnet_mld_init(const void *unused __unused)
> @@ -3284,19 +3281,17 @@ vnet_mld_init(const void *unused __unuse
>  
>  	LIST_INIT(&V_mli_head);
>  }
> -VNET_SYSINIT(vnet_mld_init, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_mld_init,
> +VNET_SYSINIT(vnet_mld_init, SI_SUB_PROTO_MC, SI_ORDER_ANY, vnet_mld_init,
>      NULL);
>  
>  static void
>  vnet_mld_uninit(const void *unused __unused)
>  {
>  
> +	/* This can happen if we shutdown the network stack. */
>  	CTR1(KTR_MLD, "%s: tearing down", __func__);
> -
> -	KASSERT(LIST_EMPTY(&V_mli_head),
> -	    ("%s: mli list not empty; ifnets not detached?", __func__));
>  }
> -VNET_SYSUNINIT(vnet_mld_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_mld_uninit,
> +VNET_SYSUNINIT(vnet_mld_uninit, SI_SUB_PROTO_MC, SI_ORDER_ANY, vnet_mld_uninit,
>      NULL);
>  
>  static int
> @@ -3318,4 +3313,4 @@ static moduledata_t mld_mod = {
>      mld_modevent,
>      0
>  };
> -DECLARE_MODULE(mld, mld_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
> +DECLARE_MODULE(mld, mld_mod, SI_SUB_PROTO_MC, SI_ORDER_ANY);
> 
> Modified: head/sys/netinet6/nd6.c
> ==============================================================================
> --- head/sys/netinet6/nd6.c	Tue Jun 21 07:05:49 2016	(r302053)
> +++ head/sys/netinet6/nd6.c	Tue Jun 21 13:48:49 2016	(r302054)
> @@ -292,8 +292,19 @@ nd6_ifattach(struct ifnet *ifp)
>  }
>  
>  void
> -nd6_ifdetach(struct nd_ifinfo *nd)
> +nd6_ifdetach(struct ifnet *ifp, struct nd_ifinfo *nd)
>  {
> +	struct ifaddr *ifa, *next;
> 
> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
> 



More information about the svn-src-head mailing list