svn commit: r299173 - in projects/vnet/sys: net netinet netinet6

Bjoern A. Zeeb bz at FreeBSD.org
Fri May 6 13:41:45 UTC 2016


Author: bz
Date: Fri May  6 13:41:43 2016
New Revision: 299173
URL: https://svnweb.freebsd.org/changeset/base/299173

Log:
  Revert the netisr changes.  Introduce a per-VNET flag to enable/disable
  netisr prcessing on that VNET.  Add functions to toggle the state.
  Update consumers.  Upon disabling netisr processing for a VNET drain
  the netisr queue.
  
  In if_attachdomain1() there is no need for trylock.
  Also do not update the status before the initialisation has happened.
  
  Reshuffle things a bit more in if_detach_internal();  always set the
  interface down;  set the if_afdata to NULL after clearing it.
  
  In the vmove functions, as well as the if_ioctl, make sure the VNET
  we are working on is not in the process of shutting down already.
  
  Add a couple of __ununsed to vnet.c functions.  Improve DDB printing
  there to properly zero-prefix hex numbers to 8 digits.
  
  Add an extra ifp argument to nd6_ifdetach() in order to be able to
  walk the address list and stop DAD processing.
  
  In nd6_timer() do not reset the callout before we are done with
  handling everything.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/vnet/sys/net/if.c
  projects/vnet/sys/net/if_epair.c
  projects/vnet/sys/net/if_ethersubr.c
  projects/vnet/sys/net/netisr.c
  projects/vnet/sys/net/netisr.h
  projects/vnet/sys/net/rtsock.c
  projects/vnet/sys/net/vnet.c
  projects/vnet/sys/netinet/if_ether.c
  projects/vnet/sys/netinet/igmp.c
  projects/vnet/sys/netinet/ip_input.c
  projects/vnet/sys/netinet6/in6.c
  projects/vnet/sys/netinet6/ip6_input.c
  projects/vnet/sys/netinet6/nd6.c
  projects/vnet/sys/netinet6/nd6.h

Modified: projects/vnet/sys/net/if.c
==============================================================================
--- projects/vnet/sys/net/if.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/if.c	Fri May  6 13:41:43 2016	(r299173)
@@ -814,15 +814,13 @@ if_attachdomain1(struct ifnet *ifp)
 	 * Since dp->dom_ifattach calls malloc() with M_WAITOK, we
 	 * cannot lock ifp->if_afdata initialization, entirely.
 	 */
-	if (IF_AFDATA_TRYLOCK(ifp) == 0)
-		return;
+	IF_AFDATA_LOCK(ifp);
 	if (ifp->if_afdata_initialized >= domain_init_status) {
 		IF_AFDATA_UNLOCK(ifp);
 		log(LOG_WARNING, "%s called more than once on %s\n",
 		    __func__, ifp->if_xname);
 		return;
 	}
-	ifp->if_afdata_initialized = domain_init_status;
 	IF_AFDATA_UNLOCK(ifp);
 
 	/* address family dependent data region */
@@ -832,6 +830,10 @@ if_attachdomain1(struct ifnet *ifp)
 			ifp->if_afdata[dp->dom_family] =
 			    (*dp->dom_ifattach)(ifp);
 	}
+
+	IF_AFDATA_LOCK(ifp);
+	ifp->if_afdata_initialized = domain_init_status;
+	IF_AFDATA_UNLOCK(ifp);
 }
 
 /*
@@ -936,10 +938,6 @@ if_detach_internal(struct ifnet *ifp, in
 			found = 1;
 			break;
 		}
-#ifdef VIMAGE
-	if (found)
-		curvnet->vnet_ifcnt--;
-#endif
 	IFNET_WUNLOCK();
 	if (!found) {
 		/*
@@ -961,6 +959,9 @@ if_detach_internal(struct ifnet *ifp, in
 	 * 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
@@ -980,6 +981,8 @@ if_detach_internal(struct ifnet *ifp, in
 	if (vmove && ifcp != NULL)
 		*ifcp = if_clone_findifc(ifp);
 
+	if_down(ifp);
+
 	/*
 	 * On VNET shutdown abort here as the stack teardown will do all
 	 * the work top-down for us.
@@ -1004,7 +1007,6 @@ if_detach_internal(struct ifnet *ifp, in
 	/*
 	 * Remove routes and flush queues.
 	 */
-	if_down(ifp);
 #ifdef ALTQ
 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
 		altq_disable(&ifp->if_snd);
@@ -1070,9 +1072,11 @@ finish_vnet_shutdown:
 	ifp->if_afdata_initialized = 0;
 	IF_AFDATA_UNLOCK(ifp);
 	for (dp = domains; i > 0 && dp; dp = dp->dom_next) {
-		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
+		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) {
 			(*dp->dom_ifdetach)(ifp,
 			    ifp->if_afdata[dp->dom_family]);
+			ifp->if_afdata[dp->dom_family] = NULL;
+		}
 	}
 
 	return (0);
@@ -1153,6 +1157,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);
@@ -1173,12 +1178,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);
 
@@ -1195,6 +1210,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);
@@ -1222,6 +1238,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();
@@ -2673,8 +2698,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: projects/vnet/sys/net/if_epair.c
==============================================================================
--- projects/vnet/sys/net/if_epair.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/if_epair.c	Fri May  6 13:41:43 2016	(r299173)
@@ -959,7 +959,7 @@ vnet_epair_init(const void *unused __unu
 
 	V_epair_cloner = if_clone_advanced(epairname, 0,
 	    epair_clone_match, epair_clone_create, epair_clone_destroy);
-	netisr_register(&epair_nh);
+	netisr_register_vnet(&epair_nh);
 }
 VNET_SYSINIT(vnet_epair_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
     vnet_epair_init, NULL);
@@ -968,7 +968,7 @@ static void
 vnet_epair_uninit(const void *unused __unused)
 {
 
-	netisr_unregister(&epair_nh);
+	netisr_unregister_vnet(&epair_nh);
 	if_clone_detach(V_epair_cloner);
 }
 VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
@@ -986,10 +986,12 @@ epair_modevent(module_t mod, int type, v
 		epair_nh.nh_qlimit = 42 * ifqmaxlen; /* 42 shall be the number. */
 		if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &qlimit))
 		    epair_nh.nh_qlimit = qlimit;
+		netisr_register(&epair_nh);
 		if (bootverbose)
 			printf("%s initialized.\n", epairname);
 		break;
 	case MOD_UNLOAD:
+		netisr_unregister(&epair_nh);
 		epair_dpcpu_detach();
 		if (bootverbose)
 			printf("%s unloaded.\n", epairname);

Modified: projects/vnet/sys/net/if_ethersubr.c
==============================================================================
--- projects/vnet/sys/net/if_ethersubr.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/if_ethersubr.c	Fri May  6 13:41:43 2016	(r299173)
@@ -654,6 +654,14 @@ static struct netisr_handler	ether_nh = 
 };
 
 static void
+ether_init(__unused void *arg)
+{
+
+	netisr_register(&ether_nh);
+}
+SYSINIT(ether, SI_SUB_INIT_IF, SI_ORDER_ANY, ether_init, NULL);
+
+static void
 vnet_ether_init(__unused void *arg)
 {
 	int i;
@@ -664,7 +672,7 @@ vnet_ether_init(__unused void *arg)
 	if ((i = pfil_head_register(&V_link_pfil_hook)) != 0)
 		printf("%s: WARNING: unable to register pfil link hook, "
 			"error %d\n", __func__, i);
-	netisr_register(&ether_nh);
+	netisr_register_vnet(&ether_nh);
 }
 VNET_SYSINIT(vnet_ether_init, SI_SUB_PROTO_IF, SI_ORDER_ANY,
     vnet_ether_init, NULL);
@@ -685,7 +693,7 @@ static void
 vnet_ether_destroy(__unused void *arg)
 {
 
-	netisr_unregister(&ether_nh);
+	netisr_unregister_vnet(&ether_nh);
 }
 VNET_SYSUNINIT(vnet_ether_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY,
     vnet_ether_destroy, NULL);
@@ -709,7 +717,8 @@ ether_input(struct ifnet *ifp, struct mb
 		 * We will rely on rcvif being set properly in the deferred context,
 		 * so assert it is correct here.
 		 */
-		KASSERT(m->m_pkthdr.rcvif == ifp, ("%s: ifnet mismatch", __func__));
+		KASSERT(m->m_pkthdr.rcvif == ifp, ("%s: ifnet mismatch m %p "
+		    "rcvif %p ifp %p", __func__, m, m->m_pkthdr.rcvif, ifp));
 		CURVNET_SET_QUIET(ifp->if_vnet);
 		netisr_dispatch(NETISR_ETHER, m);
 		CURVNET_RESTORE();

Modified: projects/vnet/sys/net/netisr.c
==============================================================================
--- projects/vnet/sys/net/netisr.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/netisr.c	Fri May  6 13:41:43 2016	(r299173)
@@ -208,8 +208,22 @@ SYSCTL_UINT(_net_isr, OID_AUTO, maxprot,
  * The netisr_proto array describes all registered protocols, indexed by
  * protocol number.  See netisr_internal.h for more details.
  */
-static VNET_DEFINE(struct netisr_proto,	netisr_proto[NETISR_MAXPROT]);
-#define	V_netisr_proto		VNET(netisr_proto)
+static struct netisr_proto	netisr_proto[NETISR_MAXPROT];
+
+/*
+ * The netisr_enable array describes a per-VNET flag for registered
+ * protocols on whether this netisr is active in this VNET or not.
+ * netisr_register() will automatically enable the netisr for the
+ * default VNET and all currently active instances.
+ * netisr_unregister() will disable all active VNETs, including vnet0.
+ * Individual network stack instances can be enabled/disabled by the
+ * netisr_(un)register _vnet() functions.
+ * With this we keep the one netisr_proto per protocol but add a
+ * mechanism to stop netisr processing for vnet teardown.
+ * Apart from that we expect a VNET to always be enabled.
+ */
+static VNET_DEFINE(u_int,	netisr_enable[NETISR_MAXPROT]);
+#define	V_netisr_enable		VNET(netisr_enable)
 
 /*
  * Per-CPU workstream data.  See netisr_internal.h for more details.
@@ -355,6 +369,7 @@ sysctl_netisr_dispatch_policy(SYSCTL_HAN
 void
 netisr_register(const struct netisr_handler *nhp)
 {
+	VNET_ITERATOR_DECL(vnet_iter);
 	struct netisr_work *npwp;
 	const char *name;
 	u_int i, proto;
@@ -397,32 +412,48 @@ netisr_register(const struct netisr_hand
 	 * Test that no existing registration exists for this protocol.
 	 */
 	NETISR_WLOCK();
-	KASSERT(V_netisr_proto[proto].np_name == NULL,
+	KASSERT(netisr_proto[proto].np_name == NULL,
 	    ("%s(%u, %s): name present", __func__, proto, name));
-	KASSERT(V_netisr_proto[proto].np_handler == NULL,
+	KASSERT(netisr_proto[proto].np_handler == NULL,
 	    ("%s(%u, %s): handler present", __func__, proto, name));
 
-	V_netisr_proto[proto].np_name = name;
-	V_netisr_proto[proto].np_handler = nhp->nh_handler;
-	V_netisr_proto[proto].np_m2flow = nhp->nh_m2flow;
-	V_netisr_proto[proto].np_m2cpuid = nhp->nh_m2cpuid;
-	V_netisr_proto[proto].np_drainedcpu = nhp->nh_drainedcpu;
+	netisr_proto[proto].np_name = name;
+	netisr_proto[proto].np_handler = nhp->nh_handler;
+	netisr_proto[proto].np_m2flow = nhp->nh_m2flow;
+	netisr_proto[proto].np_m2cpuid = nhp->nh_m2cpuid;
+	netisr_proto[proto].np_drainedcpu = nhp->nh_drainedcpu;
 	if (nhp->nh_qlimit == 0)
-		V_netisr_proto[proto].np_qlimit = netisr_defaultqlimit;
+		netisr_proto[proto].np_qlimit = netisr_defaultqlimit;
 	else if (nhp->nh_qlimit > netisr_maxqlimit) {
 		printf("%s: %s requested queue limit %u capped to "
 		    "net.isr.maxqlimit %u\n", __func__, name, nhp->nh_qlimit,
 		    netisr_maxqlimit);
-		V_netisr_proto[proto].np_qlimit = netisr_maxqlimit;
+		netisr_proto[proto].np_qlimit = netisr_maxqlimit;
 	} else
-		V_netisr_proto[proto].np_qlimit = nhp->nh_qlimit;
-	V_netisr_proto[proto].np_policy = nhp->nh_policy;
-	V_netisr_proto[proto].np_dispatch = nhp->nh_dispatch;
+		netisr_proto[proto].np_qlimit = nhp->nh_qlimit;
+	netisr_proto[proto].np_policy = nhp->nh_policy;
+	netisr_proto[proto].np_dispatch = nhp->nh_dispatch;
 	CPU_FOREACH(i) {
 		npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto];
 		bzero(npwp, sizeof(*npwp));
-		npwp->nw_qlimit = V_netisr_proto[proto].np_qlimit;
+		npwp->nw_qlimit = netisr_proto[proto].np_qlimit;
+	}
+
+#ifdef VIMAGE
+	/*
+	 * Test that we are in vnet0 and have a curvnet set.
+	 */
+	KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__));
+	KASSERT(IS_DEFAULT_VNET(curvnet), ("%s: curvnet %p is not vnet0 %p",
+	    __func__, curvnet, vnet0));
+	VNET_LIST_RLOCK_NOSLEEP();
+	VNET_FOREACH(vnet_iter) {
+		CURVNET_SET(vnet_iter);
+		V_netisr_enable[proto] = 1;
+		CURVNET_RESTORE();
 	}
+	VNET_LIST_RUNLOCK_NOSLEEP();
+#endif
 	NETISR_WUNLOCK();
 }
 
@@ -446,7 +477,7 @@ netisr_clearqdrops(const struct netisr_h
 	    ("%s(%u): protocol too big for %s", __func__, proto, name));
 
 	NETISR_WLOCK();
-	KASSERT(V_netisr_proto[proto].np_handler != NULL,
+	KASSERT(netisr_proto[proto].np_handler != NULL,
 	    ("%s(%u): protocol not registered for %s", __func__, proto,
 	    name));
 
@@ -479,7 +510,7 @@ netisr_getqdrops(const struct netisr_han
 	    ("%s(%u): protocol too big for %s", __func__, proto, name));
 
 	NETISR_RLOCK(&tracker);
-	KASSERT(V_netisr_proto[proto].np_handler != NULL,
+	KASSERT(netisr_proto[proto].np_handler != NULL,
 	    ("%s(%u): protocol not registered for %s", __func__, proto,
 	    name));
 
@@ -510,10 +541,10 @@ netisr_getqlimit(const struct netisr_han
 	    ("%s(%u): protocol too big for %s", __func__, proto, name));
 
 	NETISR_RLOCK(&tracker);
-	KASSERT(V_netisr_proto[proto].np_handler != NULL,
+	KASSERT(netisr_proto[proto].np_handler != NULL,
 	    ("%s(%u): protocol not registered for %s", __func__, proto,
 	    name));
-	*qlimitp = V_netisr_proto[proto].np_qlimit;
+	*qlimitp = netisr_proto[proto].np_qlimit;
 	NETISR_RUNLOCK(&tracker);
 }
 
@@ -542,11 +573,11 @@ netisr_setqlimit(const struct netisr_han
 	    ("%s(%u): protocol too big for %s", __func__, proto, name));
 
 	NETISR_WLOCK();
-	KASSERT(V_netisr_proto[proto].np_handler != NULL,
+	KASSERT(netisr_proto[proto].np_handler != NULL,
 	    ("%s(%u): protocol not registered for %s", __func__, proto,
 	    name));
 
-	V_netisr_proto[proto].np_qlimit = qlimit;
+	netisr_proto[proto].np_qlimit = qlimit;
 	CPU_FOREACH(i) {
 		npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto];
 		npwp->nw_qlimit = qlimit;
@@ -587,6 +618,7 @@ netisr_drain_proto(struct netisr_work *n
 void
 netisr_unregister(const struct netisr_handler *nhp)
 {
+	VNET_ITERATOR_DECL(vnet_iter);
 	struct netisr_work *npwp;
 #ifdef INVARIANTS
 	const char *name;
@@ -601,16 +633,26 @@ netisr_unregister(const struct netisr_ha
 	    ("%s(%u): protocol too big for %s", __func__, proto, name));
 
 	NETISR_WLOCK();
-	KASSERT(V_netisr_proto[proto].np_handler != NULL,
+	KASSERT(netisr_proto[proto].np_handler != NULL,
 	    ("%s(%u): protocol not registered for %s", __func__, proto,
 	    name));
 
-	V_netisr_proto[proto].np_name = NULL;
-	V_netisr_proto[proto].np_handler = NULL;
-	V_netisr_proto[proto].np_m2flow = NULL;
-	V_netisr_proto[proto].np_m2cpuid = NULL;
-	V_netisr_proto[proto].np_qlimit = 0;
-	V_netisr_proto[proto].np_policy = 0;
+#ifdef VIMAGE
+	VNET_LIST_RLOCK_NOSLEEP();
+	VNET_FOREACH(vnet_iter) {
+		CURVNET_SET(vnet_iter);
+		V_netisr_enable[proto] = 0;
+		CURVNET_RESTORE();
+	}
+	VNET_LIST_RUNLOCK_NOSLEEP();
+#endif
+
+	netisr_proto[proto].np_name = NULL;
+	netisr_proto[proto].np_handler = NULL;
+	netisr_proto[proto].np_m2flow = NULL;
+	netisr_proto[proto].np_m2cpuid = NULL;
+	netisr_proto[proto].np_qlimit = 0;
+	netisr_proto[proto].np_policy = 0;
 	CPU_FOREACH(i) {
 		npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto];
 		netisr_drain_proto(npwp);
@@ -619,6 +661,117 @@ netisr_unregister(const struct netisr_ha
 	NETISR_WUNLOCK();
 }
 
+#ifdef VIMAGE
+void
+netisr_register_vnet(const struct netisr_handler *nhp)
+{
+	u_int proto;
+
+	proto = nhp->nh_proto;
+
+	KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__));
+	KASSERT(proto < NETISR_MAXPROT,
+	    ("%s(%u): protocol too big for %s", __func__, proto, nhp->nh_name));
+	NETISR_WLOCK();
+	KASSERT(netisr_proto[proto].np_handler != NULL,
+	    ("%s(%u): protocol not registered for %s", __func__, proto,
+	    nhp->nh_name));
+	
+	V_netisr_enable[proto] = 1;
+	NETISR_WUNLOCK();
+}
+#endif
+
+#ifdef VIMAGE
+static void
+netisr_drain_proto_vnet(struct vnet *vnet, u_int proto)
+{
+	struct netisr_workstream *nwsp;
+	struct netisr_work *npwp;
+	struct mbuf *m, *mp, *n, *ne;
+	u_int i;
+#ifdef INVARIANTS
+	u_int b, k, f;
+#endif
+
+	KASSERT(vnet != NULL, ("%s: vnet is NULL", __func__));
+	NETISR_LOCK_ASSERT();
+
+	CPU_FOREACH(i) {
+		nwsp = DPCPU_ID_PTR(i, nws);
+		if (nwsp->nws_intr_event == NULL)
+			continue;
+		npwp = &nwsp->nws_work[proto];
+		NWS_LOCK(nwsp);
+#ifdef INVARIANTS
+		b = npwp->nw_len;
+		k = f = 0;
+#endif
+
+		/*
+		 * Rather than dissecting and removing mbufs from the middle
+		 * of the chain, we build a new chain if the packet stays and
+		 * update the head and tial pointers at the end.  All packets
+		 * matching the given vnet are freed.
+		 */
+		m = npwp->nw_head;
+		n = ne = NULL;
+		while (m != NULL) {
+			mp = m;
+			m = m->m_nextpkt;
+			mp->m_nextpkt = NULL;
+			if (mp->m_pkthdr.rcvif->if_vnet != vnet) {
+				if (n == NULL) {
+					n = ne = mp;
+				} else {
+					ne->m_nextpkt = mp;
+					ne = mp;
+				}
+#ifdef INVARIANTS
+				k++;
+#endif
+				continue;
+			}
+			/* This is a packet in the selected vnet. Free it. */
+			npwp->nw_len--;
+#ifdef INVARIANTS
+			f++;
+#endif
+			m_freem(mp);
+		}
+		npwp->nw_head = n;
+		npwp->nw_tail = ne;
+#ifdef INVARIANTS
+		KASSERT((k + f) == b, ("%s: b %u != k %u + f %u, nw_len %u "
+		    "vnet %p proto %u", __func__, b, k, f, npwp->nw_len,
+		    vnet, proto));
+#endif
+		NWS_UNLOCK(nwsp);
+	}
+}
+
+void
+netisr_unregister_vnet(const struct netisr_handler *nhp)
+{
+	u_int proto;
+
+	proto = nhp->nh_proto;
+
+	KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__));
+	KASSERT(proto < NETISR_MAXPROT,
+	    ("%s(%u): protocol too big for %s", __func__, proto, nhp->nh_name));
+	NETISR_WLOCK();
+	KASSERT(netisr_proto[proto].np_handler != NULL,
+	    ("%s(%u): protocol not registered for %s", __func__, proto,
+	    nhp->nh_name));
+	
+	V_netisr_enable[proto] = 0;
+
+	netisr_drain_proto_vnet(curvnet, proto);
+	NETISR_WUNLOCK();
+}
+#endif
+
 /*
  * Compose the global and per-protocol policies on dispatch, and return the
  * dispatch policy to use.
@@ -728,6 +881,9 @@ netisr_process_workstream_proto(struct n
 	struct netisr_work local_npw, *npwp;
 	u_int handled;
 	struct mbuf *m;
+#ifdef INVARIANTS
+	u_int b, f;
+#endif
 
 	NETISR_LOCK_ASSERT();
 	NWS_LOCK_ASSERT(nwsp);
@@ -741,6 +897,10 @@ netisr_process_workstream_proto(struct n
 	if (npwp->nw_len == 0)
 		return (0);
 
+#ifdef INVARIANTS
+	b = npwp->nw_len;
+	f = 0;
+#endif
 	/*
 	 * Move the global work queue to a thread-local work queue.
 	 *
@@ -761,19 +921,18 @@ netisr_process_workstream_proto(struct n
 		if (local_npw.nw_head == NULL)
 			local_npw.nw_tail = NULL;
 		local_npw.nw_len--;
+		f++;
 		VNET_ASSERT(m->m_pkthdr.rcvif != NULL,
 		    ("%s:%d rcvif == NULL: m=%p", __func__, __LINE__, m));
 		CURVNET_SET(m->m_pkthdr.rcvif->if_vnet);
-		V_netisr_proto[proto].np_handler(m);
+		netisr_proto[proto].np_handler(m);
 		CURVNET_RESTORE();
 	}
 	KASSERT(local_npw.nw_len == 0,
-	    ("%s(%u): len %u", __func__, proto, local_npw.nw_len));
-	/* We can just use the one from the default VNET. */
-	CURVNET_SET_QUIET(vnet0);
-	if (V_netisr_proto[proto].np_drainedcpu)
-		V_netisr_proto[proto].np_drainedcpu(nwsp->nws_cpu);
-	CURVNET_RESTORE();
+	    ("%s(%u): len %u b %u f %u", __func__, proto, local_npw.nw_len,
+	    b, f));
+	if (netisr_proto[proto].np_drainedcpu)
+		netisr_proto[proto].np_drainedcpu(nwsp->nws_cpu);
 	NWS_LOCK(nwsp);
 	npwp->nw_handled += handled;
 	return (handled);
@@ -909,12 +1068,15 @@ netisr_queue_src(u_int proto, uintptr_t 
 #ifdef NETISR_LOCKING
 	NETISR_RLOCK(&tracker);
 #endif
-	if (V_netisr_proto[proto].np_handler == NULL) {
+	KASSERT(netisr_proto[proto].np_handler != NULL,
+	    ("%s: invalid proto %u", __func__, proto));
+
+	if (V_netisr_enable[proto] == 0) {
 		m_freem(m);
 		return (ENOPROTOOPT);
 	}
 
-	m = netisr_select_cpuid(&V_netisr_proto[proto], NETISR_DISPATCH_DEFERRED,
+	m = netisr_select_cpuid(&netisr_proto[proto], NETISR_DISPATCH_DEFERRED,
 	    source, m, &cpuid);
 	if (m != NULL) {
 		KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__,
@@ -956,8 +1118,11 @@ netisr_dispatch_src(u_int proto, uintptr
 #ifdef NETISR_LOCKING
 	NETISR_RLOCK(&tracker);
 #endif
-	npp = &V_netisr_proto[proto];
-	if (npp->np_handler == NULL) {
+	npp = &netisr_proto[proto];
+	KASSERT(npp->np_handler != NULL, ("%s: invalid proto %u", __func__,
+	    proto));
+
+	if (V_netisr_enable[proto] == 0) {
 		m_freem(m);
 		return (ENOPROTOOPT);
 	}
@@ -978,7 +1143,7 @@ netisr_dispatch_src(u_int proto, uintptr
 		npwp = &nwsp->nws_work[proto];
 		npwp->nw_dispatched++;
 		npwp->nw_handled++;
-		V_netisr_proto[proto].np_handler(m);
+		netisr_proto[proto].np_handler(m);
 		error = 0;
 		goto out_unlock;
 	}
@@ -992,7 +1157,7 @@ netisr_dispatch_src(u_int proto, uintptr
 	 * already running.
 	 */
 	sched_pin();
-	m = netisr_select_cpuid(&V_netisr_proto[proto], NETISR_DISPATCH_HYBRID,
+	m = netisr_select_cpuid(&netisr_proto[proto], NETISR_DISPATCH_HYBRID,
 	    source, m, &cpuid);
 	if (m == NULL) {
 		error = ENOBUFS;
@@ -1029,7 +1194,7 @@ netisr_dispatch_src(u_int proto, uintptr
 	 */
 	nwsp->nws_flags |= NWS_DISPATCHING;
 	NWS_UNLOCK(nwsp);
-	V_netisr_proto[proto].np_handler(m);
+	netisr_proto[proto].np_handler(m);
 	NWS_LOCK(nwsp);
 	nwsp->nws_flags &= ~NWS_DISPATCHING;
 	npwp->nw_handled++;
@@ -1202,7 +1367,7 @@ sysctl_netisr_proto(SYSCTL_HANDLER_ARGS)
 	counter = 0;
 	NETISR_RLOCK(&tracker);
 	for (proto = 0; proto < NETISR_MAXPROT; proto++) {
-		npp = &V_netisr_proto[proto];
+		npp = &netisr_proto[proto];
 		if (npp->np_name == NULL)
 			continue;
 		snpp = &snp_array[counter];
@@ -1311,7 +1476,7 @@ sysctl_netisr_work(SYSCTL_HANDLER_ARGS)
 			continue;
 		NWS_LOCK(nwsp);
 		for (proto = 0; proto < NETISR_MAXPROT; proto++) {
-			npp = &V_netisr_proto[proto];
+			npp = &netisr_proto[proto];
 			if (npp->np_name == NULL)
 				continue;
 			nwp = &nwsp->nws_work[proto];
@@ -1360,7 +1525,7 @@ DB_SHOW_COMMAND(netisr, db_show_netisr)
 			continue;
 		first = 1;
 		for (proto = 0; proto < NETISR_MAXPROT; proto++) {
-			if (V_netisr_proto[proto].np_handler == NULL)
+			if (netisr_proto[proto].np_handler == NULL)
 				continue;
 			nwp = &nwsp->nws_work[proto];
 			if (first) {
@@ -1370,7 +1535,7 @@ DB_SHOW_COMMAND(netisr, db_show_netisr)
 				db_printf("%3s ", "");
 			db_printf(
 			    "%6s %5d %5d %5d %8ju %8ju %8ju %8ju\n",
-			    V_netisr_proto[proto].np_name, nwp->nw_len,
+			    netisr_proto[proto].np_name, nwp->nw_len,
 			    nwp->nw_watermark, nwp->nw_qlimit,
 			    nwp->nw_dispatched, nwp->nw_hybrid_dispatched,
 			    nwp->nw_qdrops, nwp->nw_queued);

Modified: projects/vnet/sys/net/netisr.h
==============================================================================
--- projects/vnet/sys/net/netisr.h	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/netisr.h	Fri May  6 13:41:43 2016	(r299173)
@@ -210,6 +210,10 @@ void	netisr_getqlimit(const struct netis
 void	netisr_register(const struct netisr_handler *nhp);
 int	netisr_setqlimit(const struct netisr_handler *nhp, u_int qlimit);
 void	netisr_unregister(const struct netisr_handler *nhp);
+#ifdef VIMAGE
+void	netisr_register_vnet(const struct netisr_handler *nhp);
+void	netisr_unregister_vnet(const struct netisr_handler *nhp);
+#endif
 
 /*
  * Process a packet destined for a protocol, and attempt direct dispatch.

Modified: projects/vnet/sys/net/rtsock.c
==============================================================================
--- projects/vnet/sys/net/rtsock.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/rtsock.c	Fri May  6 13:41:43 2016	(r299173)
@@ -191,20 +191,16 @@ SYSCTL_PROC(_net_route, OID_AUTO, netisr
     "maximum routing socket dispatch queue length");
 
 static void
-rts_init(void)
-{
-	int tmp;
-
-	if (TUNABLE_INT_FETCH("net.route.netisr_maxqlen", &tmp))
-		rtsock_nh.nh_qlimit = tmp;
-}
-SYSINIT(rtsock, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rts_init, 0);
-
-static void
 vnet_rts_init(void)
 {
+	int tmp;
 
-	netisr_register(&rtsock_nh);
+	if (IS_DEFAULT_VNET(curvnet)) {
+		if (TUNABLE_INT_FETCH("net.route.netisr_maxqlen", &tmp))
+			rtsock_nh.nh_qlimit = tmp;
+		netisr_register(&rtsock_nh);
+	} else
+		netisr_register_vnet(&rtsock_nh);
 }
 VNET_SYSINIT(vnet_rtsock, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
     vnet_rts_init, 0);
@@ -213,7 +209,7 @@ static void
 vnet_rts_uninit(void)
 {
 
-	netisr_unregister(&rtsock_nh);
+	netisr_unregister_vnet(&rtsock_nh);
 }
 VNET_SYSUNINIT(vnet_rts_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
     vnet_rts_uninit, 0);

Modified: projects/vnet/sys/net/vnet.c
==============================================================================
--- projects/vnet/sys/net/vnet.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/net/vnet.c	Fri May  6 13:41:43 2016	(r299173)
@@ -309,7 +309,7 @@ SYSINIT(vnet_init_prelink, SI_SUB_VNET_P
     vnet_init_prelink, NULL);
 
 static void
-vnet0_init(void *arg)
+vnet0_init(void *arg __unused)
 {
 
 	/* Warn people before take off - in case we crash early. */
@@ -326,12 +326,12 @@ vnet0_init(void *arg)
 SYSINIT(vnet0_init, SI_SUB_VNET, SI_ORDER_FIRST, vnet0_init, NULL);
 
 static void
-vnet_init_done(void *unused)
+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);
 
 /*
@@ -350,6 +350,16 @@ vnet_data_startup(void *dummy __unused)
 }
 SYSINIT(vnet_data, SI_SUB_KLD, SI_ORDER_FIRST, vnet_data_startup, 0);
 
+/* Dummy VNET_SYSINIT to make sure we reach the final end state. */
+static void
+vnet_sysinit_done(void *unused __unused)
+{
+
+	return;
+}
+VNET_SYSINIT(vnet_sysinit_done, SI_SUB_VNET_DONE, SI_ORDER_ANY,
+    vnet_sysinit_done, NULL);
+
 /*
  * When a module is loaded and requires storage for a virtualized global
  * variable, allocate space from the modspace free list.  This interface
@@ -698,7 +708,7 @@ db_vnet_print(struct vnet *vnet)
 	db_printf(" vnet_data_mem  = %p\n", vnet->vnet_data_mem);
 	db_printf(" vnet_data_base = 0x%jx\n",
 	    (uintmax_t)vnet->vnet_data_base);
-	db_printf(" vnet_state     = %#x\n", vnet->vnet_state);
+	db_printf(" vnet_state     = %#08x\n", vnet->vnet_state);
 	db_printf("\n");
 }
 
@@ -747,7 +757,7 @@ db_show_vnet_print_vs(struct vnet_sysini
 	sym = db_search_symbol((vm_offset_t)vs->func, DB_STGY_PROC, &offset);
 	db_symbol_values(sym, &funcname, NULL);
 	xprint("%s(%p)\n", (vsname != NULL) ? vsname : "", vs);
-	xprint("  0x%08x 0x%08x\n", vs->subsystem, vs->order);
+	xprint("  %#08x %#08x\n", vs->subsystem, vs->order);
 	xprint("  %p(%s)(%p)\n",
 	    vs->func, (funcname != NULL) ? funcname : "", vs->arg);
 #undef xprint

Modified: projects/vnet/sys/netinet/if_ether.c
==============================================================================
--- projects/vnet/sys/netinet/if_ether.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet/if_ether.c	Fri May  6 13:41:43 2016	(r299173)
@@ -1329,10 +1329,12 @@ static void
 vnet_arp_init(void)
 {
 
-	netisr_register(&arp_nh);
-	if (IS_DEFAULT_VNET(curvnet))
+	if (IS_DEFAULT_VNET(curvnet)) {
+		netisr_register(&arp_nh);
 		iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
 		    arp_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
+	} else
+		netisr_register_vnet(&arp_nh);
 }
 VNET_SYSINIT(vnet_arp_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_SECOND,
     vnet_arp_init, 0);
@@ -1346,7 +1348,7 @@ static void
 vnet_arp_destroy(__unused void *arg)
 {
 
-	netisr_unregister(&arp_nh);
+	netisr_unregister_vnet(&arp_nh);
 }
 VNET_SYSUNINIT(vnet_arp_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
     vnet_arp_destroy, NULL);

Modified: projects/vnet/sys/netinet/igmp.c
==============================================================================
--- projects/vnet/sys/netinet/igmp.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet/igmp.c	Fri May  6 13:41:43 2016	(r299173)
@@ -3592,16 +3592,16 @@ igmp_rec_type_to_str(const int type)
 }
 #endif
 
+#ifdef VIMAGE
 static void
 vnet_igmp_init(const void *unused __unused)
 {
 
-	netisr_register(&igmp_nh);
+	netisr_register_vnet(&igmp_nh);
 }
 VNET_SYSINIT(vnet_igmp_init, SI_SUB_PROTO_MC, SI_ORDER_ANY,
     vnet_igmp_init, NULL);
 
-#ifdef VIMAGE
 static void
 vnet_igmp_uninit(const void *unused __unused)
 {
@@ -3609,7 +3609,7 @@ vnet_igmp_uninit(const void *unused __un
 	/* This can happen when we shutdown the entire network stack. */
 	CTR1(KTR_IGMPV3, "%s: tearing down", __func__);
 
-	netisr_unregister(&igmp_nh);
+	netisr_unregister_vnet(&igmp_nh);
 }
 VNET_SYSUNINIT(vnet_igmp_uninit, SI_SUB_PROTO_MC, SI_ORDER_ANY,
     vnet_igmp_uninit, NULL);
@@ -3655,9 +3655,11 @@ igmp_modevent(module_t mod, int type, vo
 		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();

Modified: projects/vnet/sys/netinet/ip_input.c
==============================================================================
--- projects/vnet/sys/netinet/ip_input.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet/ip_input.c	Fri May  6 13:41:43 2016	(r299173)
@@ -331,8 +331,13 @@ ip_init(void)
 		    __func__);
 
 	/* Skip initialization of globals for non-default instances. */
-	if (!IS_DEFAULT_VNET(curvnet))
-		goto out;
+	if (!IS_DEFAULT_VNET(curvnet)) {
+		netisr_register_vnet(&ip_nh);
+#ifdef	RSS
+		netisr_register_vnet(&ip_direct_nh);
+#endif
+		return;
+	}
 
 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
 	if (pr == NULL)
@@ -354,7 +359,6 @@ ip_init(void)
 				ip_protox[pr->pr_protocol] = pr - inetsw;
 		}
 
-out:
 	netisr_register(&ip_nh);
 #ifdef	RSS
 	netisr_register(&ip_direct_nh);
@@ -369,9 +373,9 @@ ip_destroy(void *unused __unused)
 	int error;
 
 #ifdef	RSS
-	netisr_unregister(&ip_direct_nh);
+	netisr_unregister_vnet(&ip_direct_nh);
 #endif
-	netisr_unregister(&ip_nh);
+	netisr_unregister_vnet(&ip_nh);
 
 	if ((error = pfil_head_unregister(&V_inet_pfil_hook)) != 0)
 		printf("%s: WARNING: unable to unregister pfil hook, "

Modified: projects/vnet/sys/netinet6/in6.c
==============================================================================
--- projects/vnet/sys/netinet6/in6.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet6/in6.c	Fri May  6 13:41:43 2016	(r299173)
@@ -2461,7 +2461,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: projects/vnet/sys/netinet6/ip6_input.c
==============================================================================
--- projects/vnet/sys/netinet6/ip6_input.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet6/ip6_input.c	Fri May  6 13:41:43 2016	(r299173)
@@ -218,8 +218,13 @@ ip6_init(void)
 	V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR;
 
 	/* Skip global initialization stuff for non-default instances. */
-	if (!IS_DEFAULT_VNET(curvnet))
-		goto out;
+	if (!IS_DEFAULT_VNET(curvnet)) {
+		netisr_register_vnet(&ip6_nh);
+#ifdef RSS
+		netisr_register_vnet(&ip6_direct_nh);
+#endif
+		return;
+	}
 
 	pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW);
 	if (pr == NULL)
@@ -241,7 +246,6 @@ ip6_init(void)
 				ip6_protox[pr->pr_protocol] = pr - inet6sw;
 		}
 
-out:
 	netisr_register(&ip6_nh);
 #ifdef RSS
 	netisr_register(&ip6_direct_nh);
@@ -315,9 +319,9 @@ ip6_destroy(void *unused __unused)
 	int error;
 
 #ifdef RSS
-	netisr_unregister(&ip6_direct_nh);
+	netisr_unregister_vnet(&ip6_direct_nh);
 #endif
-	netisr_unregister(&ip6_nh);
+	netisr_unregister_vnet(&ip6_nh);
 
 	if ((error = pfil_head_unregister(&V_inet6_pfil_hook)) != 0)
 		printf("%s: WARNING: unable to unregister pfil hook, "

Modified: projects/vnet/sys/netinet6/nd6.c
==============================================================================
--- projects/vnet/sys/netinet6/nd6.c	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet6/nd6.c	Fri May  6 13:41:43 2016	(r299173)
@@ -290,8 +290,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;
+
+	IF_ADDR_RLOCK(ifp);
+	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
+		if (ifa->ifa_addr->sa_family != AF_INET6)
+			continue;
+
+		/* stop DAD processing */
+		nd6_dad_stop(ifa);
+	}
+	IF_ADDR_RUNLOCK(ifp);
 
 	free(nd, M_IP6NDP);
 }
@@ -894,9 +905,6 @@ nd6_timer(void *arg)
 	struct nd_prefix *pr, *npr;
 	struct in6_ifaddr *ia6, *nia6;
 
-	callout_reset(&V_nd6_timer_ch, V_nd6_prune * hz,
-	    nd6_timer, curvnet);
-
 	TAILQ_INIT(&drq);
 
 	/* expire default router list */
@@ -1023,6 +1031,10 @@ nd6_timer(void *arg)
 			prelist_remove(pr);
 		}
 	}
+
+	callout_reset(&V_nd6_timer_ch, V_nd6_prune * hz,
+	    nd6_timer, curvnet);
+
 	CURVNET_RESTORE();
 }
 

Modified: projects/vnet/sys/netinet6/nd6.h
==============================================================================
--- projects/vnet/sys/netinet6/nd6.h	Fri May  6 13:04:45 2016	(r299172)
+++ projects/vnet/sys/netinet6/nd6.h	Fri May  6 13:41:43 2016	(r299173)
@@ -410,7 +410,7 @@ void nd6_init(void);
 void nd6_destroy(void);
 #endif
 struct nd_ifinfo *nd6_ifattach(struct ifnet *);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-projects mailing list