xref: /onnv-gate/usr/src/uts/common/os/netstack.c (revision 5880)
13448Sdh155122 /*
23448Sdh155122  * CDDL HEADER START
33448Sdh155122  *
43448Sdh155122  * The contents of this file are subject to the terms of the
53448Sdh155122  * Common Development and Distribution License (the "License").
63448Sdh155122  * You may not use this file except in compliance with the License.
73448Sdh155122  *
83448Sdh155122  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93448Sdh155122  * or http://www.opensolaris.org/os/licensing.
103448Sdh155122  * See the License for the specific language governing permissions
113448Sdh155122  * and limitations under the License.
123448Sdh155122  *
133448Sdh155122  * When distributing Covered Code, include this CDDL HEADER in each
143448Sdh155122  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153448Sdh155122  * If applicable, add the following below this CDDL HEADER, with the
163448Sdh155122  * fields enclosed by brackets "[]" replaced with your own identifying
173448Sdh155122  * information: Portions Copyright [yyyy] [name of copyright owner]
183448Sdh155122  *
193448Sdh155122  * CDDL HEADER END
203448Sdh155122  */
213448Sdh155122 
223448Sdh155122 /*
23*5880Snordmark  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
243448Sdh155122  * Use is subject to license terms.
253448Sdh155122  */
263448Sdh155122 
273448Sdh155122 #pragma ident	"%Z%%M%	%I%	%E% SMI"
283448Sdh155122 
293448Sdh155122 #include <sys/param.h>
303448Sdh155122 #include <sys/sysmacros.h>
313448Sdh155122 #include <sys/vm.h>
323448Sdh155122 #include <sys/proc.h>
333448Sdh155122 #include <sys/tuneable.h>
343448Sdh155122 #include <sys/systm.h>
353448Sdh155122 #include <sys/cmn_err.h>
363448Sdh155122 #include <sys/debug.h>
373448Sdh155122 #include <sys/sdt.h>
383448Sdh155122 #include <sys/mutex.h>
393448Sdh155122 #include <sys/bitmap.h>
403448Sdh155122 #include <sys/atomic.h>
413448Sdh155122 #include <sys/kobj.h>
423448Sdh155122 #include <sys/disp.h>
433448Sdh155122 #include <vm/seg_kmem.h>
443448Sdh155122 #include <sys/zone.h>
453448Sdh155122 #include <sys/netstack.h>
463448Sdh155122 
473448Sdh155122 /*
483448Sdh155122  * What we use so that the zones framework can tell us about new zones,
493448Sdh155122  * which we use to create new stacks.
503448Sdh155122  */
513448Sdh155122 static zone_key_t netstack_zone_key;
523448Sdh155122 
533448Sdh155122 static int	netstack_initialized = 0;
543448Sdh155122 
553448Sdh155122 /*
563448Sdh155122  * Track the registered netstacks.
573448Sdh155122  * The global lock protects
583448Sdh155122  * - ns_reg
593448Sdh155122  * - the list starting at netstack_head and following the netstack_next
603448Sdh155122  *   pointers.
613448Sdh155122  */
623448Sdh155122 static kmutex_t netstack_g_lock;
633448Sdh155122 
643448Sdh155122 /*
653448Sdh155122  * Registry of netstacks with their create/shutdown/destory functions.
663448Sdh155122  */
673448Sdh155122 static struct netstack_registry	ns_reg[NS_MAX];
683448Sdh155122 
693448Sdh155122 /*
703448Sdh155122  * Global list of existing stacks.  We use this when a new zone with
713448Sdh155122  * an exclusive IP instance is created.
723448Sdh155122  *
733448Sdh155122  * Note that in some cases a netstack_t needs to stay around after the zone
743448Sdh155122  * has gone away. This is because there might be outstanding references
753448Sdh155122  * (from TCP TIME_WAIT connections, IPsec state, etc). The netstack_t data
763448Sdh155122  * structure and all the foo_stack_t's hanging off of it will be cleaned up
773448Sdh155122  * when the last reference to it is dropped.
783448Sdh155122  * However, the same zone might be rebooted. That is handled using the
793448Sdh155122  * assumption that the zones framework picks a new zoneid each time a zone
803448Sdh155122  * is (re)booted. We assert for that condition in netstack_zone_create().
813448Sdh155122  * Thus the old netstack_t can take its time for things to time out.
823448Sdh155122  */
833448Sdh155122 static netstack_t *netstack_head;
843448Sdh155122 
853448Sdh155122 /*
863448Sdh155122  * To support kstat_create_netstack() using kstat_zone_add we need
873448Sdh155122  * to track both
883448Sdh155122  *  - all zoneids that use the global/shared stack
893448Sdh155122  *  - all kstats that have been added for the shared stack
903448Sdh155122  */
913448Sdh155122 struct shared_zone_list {
923448Sdh155122 	struct shared_zone_list *sz_next;
933448Sdh155122 	zoneid_t		sz_zoneid;
943448Sdh155122 };
953448Sdh155122 
963448Sdh155122 struct shared_kstat_list {
973448Sdh155122 	struct shared_kstat_list *sk_next;
983448Sdh155122 	kstat_t			 *sk_kstat;
993448Sdh155122 };
1003448Sdh155122 
1013448Sdh155122 static kmutex_t netstack_shared_lock;	/* protects the following two */
1023448Sdh155122 static struct shared_zone_list	*netstack_shared_zones;
1033448Sdh155122 static struct shared_kstat_list	*netstack_shared_kstats;
1043448Sdh155122 
1053448Sdh155122 static void	*netstack_zone_create(zoneid_t zoneid);
1063448Sdh155122 static void	netstack_zone_shutdown(zoneid_t zoneid, void *arg);
1073448Sdh155122 static void	netstack_zone_destroy(zoneid_t zoneid, void *arg);
1083448Sdh155122 
1093448Sdh155122 static void	netstack_shared_zone_add(zoneid_t zoneid);
1103448Sdh155122 static void	netstack_shared_zone_remove(zoneid_t zoneid);
1113448Sdh155122 static void	netstack_shared_kstat_add(kstat_t *ks);
1123448Sdh155122 static void	netstack_shared_kstat_remove(kstat_t *ks);
1133448Sdh155122 
1144287Snordmark typedef boolean_t applyfn_t(kmutex_t *, netstack_t *, int);
1153448Sdh155122 
116*5880Snordmark static void	apply_all_netstacks(int, applyfn_t *);
117*5880Snordmark static void	apply_all_modules(netstack_t *, applyfn_t *);
118*5880Snordmark static void	apply_all_modules_reverse(netstack_t *, applyfn_t *);
119*5880Snordmark static boolean_t netstack_apply_create(kmutex_t *, netstack_t *, int);
120*5880Snordmark static boolean_t netstack_apply_shutdown(kmutex_t *, netstack_t *, int);
121*5880Snordmark static boolean_t netstack_apply_destroy(kmutex_t *, netstack_t *, int);
122*5880Snordmark static boolean_t wait_for_zone_creator(netstack_t *, kmutex_t *);
123*5880Snordmark static boolean_t wait_for_nms_inprogress(netstack_t *, nm_state_t *,
124*5880Snordmark     kmutex_t *);
125*5880Snordmark 
1263448Sdh155122 void
1273448Sdh155122 netstack_init(void)
1283448Sdh155122 {
1293448Sdh155122 	mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL);
1303448Sdh155122 	mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL);
1313448Sdh155122 
1323448Sdh155122 	netstack_initialized = 1;
1333448Sdh155122 
1343448Sdh155122 	/*
1353448Sdh155122 	 * We want to be informed each time a zone is created or
1363448Sdh155122 	 * destroyed in the kernel, so we can maintain the
1373448Sdh155122 	 * stack instance information.
1383448Sdh155122 	 */
1393448Sdh155122 	zone_key_create(&netstack_zone_key, netstack_zone_create,
1403448Sdh155122 	    netstack_zone_shutdown, netstack_zone_destroy);
1413448Sdh155122 }
1423448Sdh155122 
1433448Sdh155122 /*
1443448Sdh155122  * Register a new module with the framework.
1453448Sdh155122  * This registers interest in changes to the set of netstacks.
1463448Sdh155122  * The createfn and destroyfn are required, but the shutdownfn can be
1473448Sdh155122  * NULL.
1483448Sdh155122  * Note that due to the current zsd implementation, when the create
1493448Sdh155122  * function is called the zone isn't fully present, thus functions
1503448Sdh155122  * like zone_find_by_* will fail, hence the create function can not
1513448Sdh155122  * use many zones kernel functions including zcmn_err().
1523448Sdh155122  */
1533448Sdh155122 void
1543448Sdh155122 netstack_register(int moduleid,
1553448Sdh155122     void *(*module_create)(netstackid_t, netstack_t *),
1563448Sdh155122     void (*module_shutdown)(netstackid_t, void *),
1573448Sdh155122     void (*module_destroy)(netstackid_t, void *))
1583448Sdh155122 {
1593448Sdh155122 	netstack_t *ns;
1603448Sdh155122 
1613448Sdh155122 	ASSERT(netstack_initialized);
1623448Sdh155122 	ASSERT(moduleid >= 0 && moduleid < NS_MAX);
1633448Sdh155122 	ASSERT(module_create != NULL);
1643448Sdh155122 
165*5880Snordmark 	/*
166*5880Snordmark 	 * Make instances created after this point in time run the create
167*5880Snordmark 	 * callback.
168*5880Snordmark 	 */
1693448Sdh155122 	mutex_enter(&netstack_g_lock);
1703448Sdh155122 	ASSERT(ns_reg[moduleid].nr_create == NULL);
1713448Sdh155122 	ASSERT(ns_reg[moduleid].nr_flags == 0);
1723448Sdh155122 	ns_reg[moduleid].nr_create = module_create;
1733448Sdh155122 	ns_reg[moduleid].nr_shutdown = module_shutdown;
1743448Sdh155122 	ns_reg[moduleid].nr_destroy = module_destroy;
1753448Sdh155122 	ns_reg[moduleid].nr_flags = NRF_REGISTERED;
1763448Sdh155122 
1773448Sdh155122 	/*
1783448Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
179*5880Snordmark 	 * Set NSS_CREATE_NEEDED for each of those.
1803448Sdh155122 	 * netstacks which have been deleted will have NSS_CREATE_COMPLETED
1813448Sdh155122 	 * set, but check NSF_CLOSING to be sure.
1823448Sdh155122 	 */
1833448Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
184*5880Snordmark 		nm_state_t *nms = &ns->netstack_m_state[moduleid];
185*5880Snordmark 
1863448Sdh155122 		mutex_enter(&ns->netstack_lock);
1873448Sdh155122 		if (!(ns->netstack_flags & NSF_CLOSING) &&
188*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_ALL) == 0) {
189*5880Snordmark 			nms->nms_flags |= NSS_CREATE_NEEDED;
1903448Sdh155122 			DTRACE_PROBE2(netstack__create__needed,
1913448Sdh155122 			    netstack_t *, ns, int, moduleid);
1923448Sdh155122 		}
1933448Sdh155122 		mutex_exit(&ns->netstack_lock);
1943448Sdh155122 	}
1953448Sdh155122 	mutex_exit(&netstack_g_lock);
1963448Sdh155122 
1973448Sdh155122 	/*
198*5880Snordmark 	 * At this point in time a new instance can be created or an instance
199*5880Snordmark 	 * can be destroyed, or some other module can register or unregister.
200*5880Snordmark 	 * Make sure we either run all the create functions for this moduleid
201*5880Snordmark 	 * or we wait for any other creators for this moduleid.
2023448Sdh155122 	 */
203*5880Snordmark 	apply_all_netstacks(moduleid, netstack_apply_create);
2043448Sdh155122 }
2053448Sdh155122 
2063448Sdh155122 void
2073448Sdh155122 netstack_unregister(int moduleid)
2083448Sdh155122 {
2093448Sdh155122 	netstack_t *ns;
2103448Sdh155122 
2113448Sdh155122 	ASSERT(moduleid >= 0 && moduleid < NS_MAX);
2123448Sdh155122 
2133448Sdh155122 	ASSERT(ns_reg[moduleid].nr_create != NULL);
2143448Sdh155122 	ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
2153448Sdh155122 
2163448Sdh155122 	mutex_enter(&netstack_g_lock);
2173448Sdh155122 	/*
2183448Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
219*5880Snordmark 	 * Set NSS_SHUTDOWN_NEEDED and NSS_DESTROY_NEEDED for each of those.
220*5880Snordmark 	 * That ensures that when we return all the callbacks for existing
221*5880Snordmark 	 * instances have completed. And since we set NRF_DYING no new
222*5880Snordmark 	 * instances can use this module.
2233448Sdh155122 	 */
2243448Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
225*5880Snordmark 		nm_state_t *nms = &ns->netstack_m_state[moduleid];
226*5880Snordmark 
2273448Sdh155122 		mutex_enter(&ns->netstack_lock);
2283448Sdh155122 		if (ns_reg[moduleid].nr_shutdown != NULL &&
229*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_COMPLETED) &&
230*5880Snordmark 		    (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
231*5880Snordmark 			nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
2323448Sdh155122 			DTRACE_PROBE2(netstack__shutdown__needed,
2333448Sdh155122 			    netstack_t *, ns, int, moduleid);
2343448Sdh155122 		}
2353448Sdh155122 		if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) &&
2363448Sdh155122 		    ns_reg[moduleid].nr_destroy != NULL &&
237*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_COMPLETED) &&
238*5880Snordmark 		    (nms->nms_flags & NSS_DESTROY_ALL) == 0) {
239*5880Snordmark 			nms->nms_flags |= NSS_DESTROY_NEEDED;
2403448Sdh155122 			DTRACE_PROBE2(netstack__destroy__needed,
2413448Sdh155122 			    netstack_t *, ns, int, moduleid);
2423448Sdh155122 		}
2433448Sdh155122 		mutex_exit(&ns->netstack_lock);
2443448Sdh155122 	}
245*5880Snordmark 	/*
246*5880Snordmark 	 * Prevent any new netstack from calling the registered create
247*5880Snordmark 	 * function, while keeping the function pointers in place until the
248*5880Snordmark 	 * shutdown and destroy callbacks are complete.
249*5880Snordmark 	 */
250*5880Snordmark 	ns_reg[moduleid].nr_flags |= NRF_DYING;
2513448Sdh155122 	mutex_exit(&netstack_g_lock);
2523448Sdh155122 
253*5880Snordmark 	apply_all_netstacks(moduleid, netstack_apply_shutdown);
254*5880Snordmark 	apply_all_netstacks(moduleid, netstack_apply_destroy);
2553448Sdh155122 
2563448Sdh155122 	/*
257*5880Snordmark 	 * Clear the nms_flags so that we can handle this module
2583448Sdh155122 	 * being loaded again.
259*5880Snordmark 	 * Also remove the registered functions.
2603448Sdh155122 	 */
2613448Sdh155122 	mutex_enter(&netstack_g_lock);
262*5880Snordmark 	ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
263*5880Snordmark 	ASSERT(ns_reg[moduleid].nr_flags & NRF_DYING);
2643448Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
265*5880Snordmark 		nm_state_t *nms = &ns->netstack_m_state[moduleid];
266*5880Snordmark 
2673448Sdh155122 		mutex_enter(&ns->netstack_lock);
268*5880Snordmark 		if (nms->nms_flags & NSS_DESTROY_COMPLETED) {
269*5880Snordmark 			nms->nms_flags = 0;
2703448Sdh155122 			DTRACE_PROBE2(netstack__destroy__done,
2713448Sdh155122 			    netstack_t *, ns, int, moduleid);
2723448Sdh155122 		}
2733448Sdh155122 		mutex_exit(&ns->netstack_lock);
2743448Sdh155122 	}
2753448Sdh155122 
2763448Sdh155122 	ns_reg[moduleid].nr_create = NULL;
2773448Sdh155122 	ns_reg[moduleid].nr_shutdown = NULL;
2783448Sdh155122 	ns_reg[moduleid].nr_destroy = NULL;
2793448Sdh155122 	ns_reg[moduleid].nr_flags = 0;
2803448Sdh155122 	mutex_exit(&netstack_g_lock);
2813448Sdh155122 }
2823448Sdh155122 
2833448Sdh155122 /*
2843448Sdh155122  * Lookup and/or allocate a netstack for this zone.
2853448Sdh155122  */
2863448Sdh155122 static void *
2873448Sdh155122 netstack_zone_create(zoneid_t zoneid)
2883448Sdh155122 {
2893448Sdh155122 	netstackid_t stackid;
2903448Sdh155122 	netstack_t *ns;
2913448Sdh155122 	netstack_t **nsp;
2923448Sdh155122 	zone_t	*zone;
2933448Sdh155122 	int i;
2943448Sdh155122 
2953448Sdh155122 	ASSERT(netstack_initialized);
2963448Sdh155122 
2973448Sdh155122 	zone = zone_find_by_id_nolock(zoneid);
2983448Sdh155122 	ASSERT(zone != NULL);
2993448Sdh155122 
3003448Sdh155122 	if (zone->zone_flags & ZF_NET_EXCL) {
3013448Sdh155122 		stackid = zoneid;
3023448Sdh155122 	} else {
3033448Sdh155122 		/* Look for the stack instance for the global */
3043448Sdh155122 		stackid = GLOBAL_NETSTACKID;
3053448Sdh155122 	}
3063448Sdh155122 
3073448Sdh155122 	/* Allocate even if it isn't needed; simplifies locking */
3083448Sdh155122 	ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP);
3093448Sdh155122 
3103448Sdh155122 	/* Look if there is a matching stack instance */
3113448Sdh155122 	mutex_enter(&netstack_g_lock);
3123448Sdh155122 	for (nsp = &netstack_head; *nsp != NULL;
3133448Sdh155122 	    nsp = &((*nsp)->netstack_next)) {
3143448Sdh155122 		if ((*nsp)->netstack_stackid == stackid) {
3153448Sdh155122 			/*
3163448Sdh155122 			 * Should never find a pre-existing exclusive stack
3173448Sdh155122 			 */
3183448Sdh155122 			ASSERT(stackid == GLOBAL_NETSTACKID);
3193448Sdh155122 			kmem_free(ns, sizeof (netstack_t));
3203448Sdh155122 			ns = *nsp;
3213448Sdh155122 			mutex_enter(&ns->netstack_lock);
3223448Sdh155122 			ns->netstack_numzones++;
3233448Sdh155122 			mutex_exit(&ns->netstack_lock);
3243448Sdh155122 			mutex_exit(&netstack_g_lock);
3253448Sdh155122 			DTRACE_PROBE1(netstack__inc__numzones,
3263448Sdh155122 			    netstack_t *, ns);
3273448Sdh155122 			/* Record that we have a new shared stack zone */
3283448Sdh155122 			netstack_shared_zone_add(zoneid);
3293448Sdh155122 			zone->zone_netstack = ns;
3303448Sdh155122 			return (ns);
3313448Sdh155122 		}
3323448Sdh155122 	}
3333448Sdh155122 	/* Not found */
3343448Sdh155122 	mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL);
335*5880Snordmark 	cv_init(&ns->netstack_cv, NULL, CV_DEFAULT, NULL);
3363448Sdh155122 	ns->netstack_stackid = zoneid;
3373448Sdh155122 	ns->netstack_numzones = 1;
3383448Sdh155122 	ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */
3393448Sdh155122 	ns->netstack_flags = NSF_UNINIT;
3403448Sdh155122 	*nsp = ns;
3413448Sdh155122 	zone->zone_netstack = ns;
3423448Sdh155122 
343*5880Snordmark 	mutex_enter(&ns->netstack_lock);
344*5880Snordmark 	/*
345*5880Snordmark 	 * Mark this netstack as having a CREATE running so
346*5880Snordmark 	 * any netstack_register/netstack_unregister waits for
347*5880Snordmark 	 * the existing create callbacks to complete in moduleid order
348*5880Snordmark 	 */
349*5880Snordmark 	ns->netstack_flags |= NSF_ZONE_CREATE;
350*5880Snordmark 
3513448Sdh155122 	/*
3523448Sdh155122 	 * Determine the set of module create functions that need to be
3533448Sdh155122 	 * called before we drop the lock.
354*5880Snordmark 	 * Set NSS_CREATE_NEEDED for each of those.
355*5880Snordmark 	 * Skip any with NRF_DYING set, since those are in the process of
356*5880Snordmark 	 * going away, by checking for flags being exactly NRF_REGISTERED.
3573448Sdh155122 	 */
3583448Sdh155122 	for (i = 0; i < NS_MAX; i++) {
359*5880Snordmark 		nm_state_t *nms = &ns->netstack_m_state[i];
360*5880Snordmark 
361*5880Snordmark 		cv_init(&nms->nms_cv, NULL, CV_DEFAULT, NULL);
362*5880Snordmark 
363*5880Snordmark 		if ((ns_reg[i].nr_flags == NRF_REGISTERED) &&
364*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_ALL) == 0) {
365*5880Snordmark 			nms->nms_flags |= NSS_CREATE_NEEDED;
3663448Sdh155122 			DTRACE_PROBE2(netstack__create__needed,
3673448Sdh155122 			    netstack_t *, ns, int, i);
3683448Sdh155122 		}
3693448Sdh155122 	}
370*5880Snordmark 	mutex_exit(&ns->netstack_lock);
3713448Sdh155122 	mutex_exit(&netstack_g_lock);
3723448Sdh155122 
373*5880Snordmark 	apply_all_modules(ns, netstack_apply_create);
3743448Sdh155122 
375*5880Snordmark 	/* Tell any waiting netstack_register/netstack_unregister to proceed */
3763448Sdh155122 	mutex_enter(&ns->netstack_lock);
3773448Sdh155122 	ns->netstack_flags &= ~NSF_UNINIT;
378*5880Snordmark 	ASSERT(ns->netstack_flags & NSF_ZONE_CREATE);
379*5880Snordmark 	ns->netstack_flags &= ~NSF_ZONE_CREATE;
380*5880Snordmark 	cv_broadcast(&ns->netstack_cv);
3813448Sdh155122 	mutex_exit(&ns->netstack_lock);
3823448Sdh155122 
3833448Sdh155122 	return (ns);
3843448Sdh155122 }
3853448Sdh155122 
3863448Sdh155122 /* ARGSUSED */
3873448Sdh155122 static void
3883448Sdh155122 netstack_zone_shutdown(zoneid_t zoneid, void *arg)
3893448Sdh155122 {
3903448Sdh155122 	netstack_t *ns = (netstack_t *)arg;
3913448Sdh155122 	int i;
3923448Sdh155122 
3933448Sdh155122 	ASSERT(arg != NULL);
3943448Sdh155122 
3953448Sdh155122 	mutex_enter(&ns->netstack_lock);
3963448Sdh155122 	ASSERT(ns->netstack_numzones > 0);
3973448Sdh155122 	if (ns->netstack_numzones != 1) {
3983448Sdh155122 		/* Stack instance being used by other zone */
3993448Sdh155122 		mutex_exit(&ns->netstack_lock);
4003448Sdh155122 		ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
4013448Sdh155122 		return;
4023448Sdh155122 	}
4033448Sdh155122 	mutex_exit(&ns->netstack_lock);
4043448Sdh155122 
4053448Sdh155122 	mutex_enter(&netstack_g_lock);
406*5880Snordmark 	mutex_enter(&ns->netstack_lock);
407*5880Snordmark 	/*
408*5880Snordmark 	 * Mark this netstack as having a SHUTDOWN running so
409*5880Snordmark 	 * any netstack_register/netstack_unregister waits for
410*5880Snordmark 	 * the existing create callbacks to complete in moduleid order
411*5880Snordmark 	 */
412*5880Snordmark 	ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
413*5880Snordmark 	ns->netstack_flags |= NSF_ZONE_SHUTDOWN;
414*5880Snordmark 
4153448Sdh155122 	/*
4163448Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
417*5880Snordmark 	 * Set NSS_SHUTDOWN_NEEDED for each of those.
4183448Sdh155122 	 */
4193448Sdh155122 	for (i = 0; i < NS_MAX; i++) {
420*5880Snordmark 		nm_state_t *nms = &ns->netstack_m_state[i];
421*5880Snordmark 
4223448Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
4233448Sdh155122 		    ns_reg[i].nr_shutdown != NULL &&
424*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_COMPLETED) &&
425*5880Snordmark 		    (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
426*5880Snordmark 			nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
4273448Sdh155122 			DTRACE_PROBE2(netstack__shutdown__needed,
4283448Sdh155122 			    netstack_t *, ns, int, i);
4293448Sdh155122 		}
4303448Sdh155122 	}
431*5880Snordmark 	mutex_exit(&ns->netstack_lock);
4323448Sdh155122 	mutex_exit(&netstack_g_lock);
4333448Sdh155122 
4344287Snordmark 	/*
4354287Snordmark 	 * Call the shutdown function for all registered modules for this
4364287Snordmark 	 * netstack.
4374287Snordmark 	 */
438*5880Snordmark 	apply_all_modules(ns, netstack_apply_shutdown);
439*5880Snordmark 
440*5880Snordmark 	/* Tell any waiting netstack_register/netstack_unregister to proceed */
441*5880Snordmark 	mutex_enter(&ns->netstack_lock);
442*5880Snordmark 	ASSERT(ns->netstack_flags & NSF_ZONE_SHUTDOWN);
443*5880Snordmark 	ns->netstack_flags &= ~NSF_ZONE_SHUTDOWN;
444*5880Snordmark 	cv_broadcast(&ns->netstack_cv);
445*5880Snordmark 	mutex_exit(&ns->netstack_lock);
4463448Sdh155122 }
4473448Sdh155122 
4483448Sdh155122 /*
4493448Sdh155122  * Common routine to release a zone.
4503448Sdh155122  * If this was the last zone using the stack instance then prepare to
4513448Sdh155122  * have the refcnt dropping to zero free the zone.
4523448Sdh155122  */
4533448Sdh155122 /* ARGSUSED */
4543448Sdh155122 static void
4553448Sdh155122 netstack_zone_destroy(zoneid_t zoneid, void *arg)
4563448Sdh155122 {
4573448Sdh155122 	netstack_t *ns = (netstack_t *)arg;
4583448Sdh155122 
4593448Sdh155122 	ASSERT(arg != NULL);
4603448Sdh155122 
4613448Sdh155122 	mutex_enter(&ns->netstack_lock);
4623448Sdh155122 	ASSERT(ns->netstack_numzones > 0);
4633448Sdh155122 	ns->netstack_numzones--;
4643448Sdh155122 	if (ns->netstack_numzones != 0) {
4653448Sdh155122 		/* Stack instance being used by other zone */
4663448Sdh155122 		mutex_exit(&ns->netstack_lock);
4673448Sdh155122 		ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
4683448Sdh155122 		/* Record that we a shared stack zone has gone away */
4693448Sdh155122 		netstack_shared_zone_remove(zoneid);
4703448Sdh155122 		return;
4713448Sdh155122 	}
4723448Sdh155122 	/*
4734287Snordmark 	 * Set CLOSING so that netstack_find_by will not find it.
4743448Sdh155122 	 */
4753448Sdh155122 	ns->netstack_flags |= NSF_CLOSING;
4763448Sdh155122 	mutex_exit(&ns->netstack_lock);
4773448Sdh155122 	DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns);
4783448Sdh155122 	/* No other thread can call zone_destroy for this stack */
4793448Sdh155122 
4803448Sdh155122 	/*
4813448Sdh155122 	 * Decrease refcnt to account for the one in netstack_zone_init()
4823448Sdh155122 	 */
4833448Sdh155122 	netstack_rele(ns);
4843448Sdh155122 }
4853448Sdh155122 
4863448Sdh155122 /*
4873448Sdh155122  * Called when the reference count drops to zero.
4883448Sdh155122  * Call the destroy functions for each registered module.
4893448Sdh155122  */
4903448Sdh155122 static void
4913448Sdh155122 netstack_stack_inactive(netstack_t *ns)
4923448Sdh155122 {
4933448Sdh155122 	int i;
4943448Sdh155122 
4953448Sdh155122 	mutex_enter(&netstack_g_lock);
496*5880Snordmark 	mutex_enter(&ns->netstack_lock);
497*5880Snordmark 	/*
498*5880Snordmark 	 * Mark this netstack as having a DESTROY running so
499*5880Snordmark 	 * any netstack_register/netstack_unregister waits for
500*5880Snordmark 	 * the existing destroy callbacks to complete in reverse moduleid order
501*5880Snordmark 	 */
502*5880Snordmark 	ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
503*5880Snordmark 	ns->netstack_flags |= NSF_ZONE_DESTROY;
5043448Sdh155122 	/*
5053448Sdh155122 	 * If the shutdown callback wasn't called earlier (e.g., if this is
506*5880Snordmark 	 * a netstack shared between multiple zones), then we schedule it now.
507*5880Snordmark 	 *
508*5880Snordmark 	 * Determine the set of stacks that exist before we drop the lock.
509*5880Snordmark 	 * Set NSS_DESTROY_NEEDED for each of those. That
510*5880Snordmark 	 * ensures that when we return all the callbacks for existing
511*5880Snordmark 	 * instances have completed.
5123448Sdh155122 	 */
5133448Sdh155122 	for (i = 0; i < NS_MAX; i++) {
514*5880Snordmark 		nm_state_t *nms = &ns->netstack_m_state[i];
515*5880Snordmark 
5163448Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
5173448Sdh155122 		    ns_reg[i].nr_shutdown != NULL &&
518*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_COMPLETED) &&
519*5880Snordmark 		    (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
520*5880Snordmark 			nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
5213448Sdh155122 			DTRACE_PROBE2(netstack__shutdown__needed,
5223448Sdh155122 			    netstack_t *, ns, int, i);
5233448Sdh155122 		}
524*5880Snordmark 
5253448Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
5263448Sdh155122 		    ns_reg[i].nr_destroy != NULL &&
527*5880Snordmark 		    (nms->nms_flags & NSS_CREATE_COMPLETED) &&
528*5880Snordmark 		    (nms->nms_flags & NSS_DESTROY_ALL) == 0) {
529*5880Snordmark 			nms->nms_flags |= NSS_DESTROY_NEEDED;
5303448Sdh155122 			DTRACE_PROBE2(netstack__destroy__needed,
5313448Sdh155122 			    netstack_t *, ns, int, i);
5323448Sdh155122 		}
5333448Sdh155122 	}
534*5880Snordmark 	mutex_exit(&ns->netstack_lock);
5353448Sdh155122 	mutex_exit(&netstack_g_lock);
5363448Sdh155122 
5374287Snordmark 	/*
5384287Snordmark 	 * Call the shutdown and destroy functions for all registered modules
5394287Snordmark 	 * for this netstack.
540*5880Snordmark 	 *
541*5880Snordmark 	 * Since there are some ordering dependencies between the modules we
542*5880Snordmark 	 * tear them down in the reverse order of what was used to create them.
543*5880Snordmark 	 *
544*5880Snordmark 	 * Since a netstack_t is never reused (when a zone is rebooted it gets
545*5880Snordmark 	 * a new zoneid == netstackid i.e. a new netstack_t is allocated) we
546*5880Snordmark 	 * leave nms_flags the way it is i.e. with NSS_DESTROY_COMPLETED set.
547*5880Snordmark 	 * That is different than in the netstack_unregister() case.
5484287Snordmark 	 */
549*5880Snordmark 	apply_all_modules(ns, netstack_apply_shutdown);
550*5880Snordmark 	apply_all_modules_reverse(ns, netstack_apply_destroy);
5513448Sdh155122 
552*5880Snordmark 	/* Tell any waiting netstack_register/netstack_unregister to proceed */
5533448Sdh155122 	mutex_enter(&ns->netstack_lock);
554*5880Snordmark 	ASSERT(ns->netstack_flags & NSF_ZONE_DESTROY);
555*5880Snordmark 	ns->netstack_flags &= ~NSF_ZONE_DESTROY;
556*5880Snordmark 	cv_broadcast(&ns->netstack_cv);
557*5880Snordmark 	mutex_exit(&ns->netstack_lock);
5583448Sdh155122 }
5593448Sdh155122 
5604287Snordmark /*
5614287Snordmark  * Apply a function to all netstacks for a particular moduleid.
5624287Snordmark  *
563*5880Snordmark  * If there is any zone activity (due to a zone being created, shutdown,
564*5880Snordmark  * or destroyed) we wait for that to complete before we proceed. This ensures
565*5880Snordmark  * that the moduleids are processed in order when a zone is created or
566*5880Snordmark  * destroyed.
567*5880Snordmark  *
5684287Snordmark  * The applyfn has to drop netstack_g_lock if it does some work.
569*5880Snordmark  * In that case we don't follow netstack_next,
570*5880Snordmark  * even if it is possible to do so without any hazards. This is
5714287Snordmark  * because we want the design to allow for the list of netstacks threaded
5724287Snordmark  * by netstack_next to change in any arbitrary way during the time the
5734287Snordmark  * lock was dropped.
5744287Snordmark  *
5754287Snordmark  * It is safe to restart the loop at netstack_head since the applyfn
5764287Snordmark  * changes netstack_m_state as it processes things, so a subsequent
5774287Snordmark  * pass through will have no effect in applyfn, hence the loop will terminate
5784287Snordmark  * in at worst O(N^2).
5794287Snordmark  */
5803448Sdh155122 static void
5814287Snordmark apply_all_netstacks(int moduleid, applyfn_t *applyfn)
5823448Sdh155122 {
5833448Sdh155122 	netstack_t *ns;
5843448Sdh155122 
5854287Snordmark 	mutex_enter(&netstack_g_lock);
5864287Snordmark 	ns = netstack_head;
5873448Sdh155122 	while (ns != NULL) {
588*5880Snordmark 		if (wait_for_zone_creator(ns, &netstack_g_lock)) {
5894287Snordmark 			/* Lock dropped - restart at head */
590*5880Snordmark 			ns = netstack_head;
591*5880Snordmark 		} else if ((applyfn)(&netstack_g_lock, ns, moduleid)) {
592*5880Snordmark 			/* Lock dropped - restart at head */
5934287Snordmark 			ns = netstack_head;
5943448Sdh155122 		} else {
5953448Sdh155122 			ns = ns->netstack_next;
5963448Sdh155122 		}
5973448Sdh155122 	}
5984287Snordmark 	mutex_exit(&netstack_g_lock);
5993448Sdh155122 }
6003448Sdh155122 
6013448Sdh155122 /*
6024287Snordmark  * Apply a function to all moduleids for a particular netstack.
6034287Snordmark  *
6044287Snordmark  * Since the netstack linkage doesn't matter in this case we can
6054287Snordmark  * ignore whether the function drops the lock.
6064287Snordmark  */
6074287Snordmark static void
6084287Snordmark apply_all_modules(netstack_t *ns, applyfn_t *applyfn)
6094287Snordmark {
6104287Snordmark 	int i;
6114287Snordmark 
6124287Snordmark 	mutex_enter(&netstack_g_lock);
6134287Snordmark 	for (i = 0; i < NS_MAX; i++) {
614*5880Snordmark 		/*
615*5880Snordmark 		 * We don't care whether the lock was dropped
616*5880Snordmark 		 * since we are not iterating over netstack_head.
617*5880Snordmark 		 */
618*5880Snordmark 		(void) (applyfn)(&netstack_g_lock, ns, i);
6194287Snordmark 	}
6204287Snordmark 	mutex_exit(&netstack_g_lock);
6214287Snordmark }
6224287Snordmark 
6234287Snordmark /* Like the above but in reverse moduleid order */
6244287Snordmark static void
6254287Snordmark apply_all_modules_reverse(netstack_t *ns, applyfn_t *applyfn)
6264287Snordmark {
6274287Snordmark 	int i;
6284287Snordmark 
6294287Snordmark 	mutex_enter(&netstack_g_lock);
6304287Snordmark 	for (i = NS_MAX-1; i >= 0; i--) {
631*5880Snordmark 		/*
632*5880Snordmark 		 * We don't care whether the lock was dropped
633*5880Snordmark 		 * since we are not iterating over netstack_head.
634*5880Snordmark 		 */
635*5880Snordmark 		(void) (applyfn)(&netstack_g_lock, ns, i);
6364287Snordmark 	}
6374287Snordmark 	mutex_exit(&netstack_g_lock);
6384287Snordmark }
6394287Snordmark 
6404287Snordmark /*
641*5880Snordmark  * Call the create function for the ns and moduleid if CREATE_NEEDED
642*5880Snordmark  * is set.
643*5880Snordmark  * If some other thread gets here first and sets *_INPROGRESS, then
644*5880Snordmark  * we wait for that thread to complete so that we can ensure that
645*5880Snordmark  * all the callbacks are done when we've looped over all netstacks/moduleids.
6464287Snordmark  *
647*5880Snordmark  * When we call the create function, we temporarily drop the netstack_lock
648*5880Snordmark  * held by the caller, and return true to tell the caller it needs to
649*5880Snordmark  * re-evalute the state.
6503448Sdh155122  */
651*5880Snordmark static boolean_t
652*5880Snordmark netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid)
6533448Sdh155122 {
654*5880Snordmark 	void *result;
655*5880Snordmark 	netstackid_t stackid;
656*5880Snordmark 	nm_state_t *nms = &ns->netstack_m_state[moduleid];
657*5880Snordmark 	boolean_t dropped = B_FALSE;
658*5880Snordmark 
659*5880Snordmark 	ASSERT(MUTEX_HELD(lockp));
660*5880Snordmark 	mutex_enter(&ns->netstack_lock);
661*5880Snordmark 
662*5880Snordmark 	if (wait_for_nms_inprogress(ns, nms, lockp))
663*5880Snordmark 		dropped = B_TRUE;
664*5880Snordmark 
665*5880Snordmark 	if (nms->nms_flags & NSS_CREATE_NEEDED) {
666*5880Snordmark 		nms->nms_flags &= ~NSS_CREATE_NEEDED;
667*5880Snordmark 		nms->nms_flags |= NSS_CREATE_INPROGRESS;
668*5880Snordmark 		DTRACE_PROBE2(netstack__create__inprogress,
669*5880Snordmark 		    netstack_t *, ns, int, moduleid);
670*5880Snordmark 		mutex_exit(&ns->netstack_lock);
671*5880Snordmark 		mutex_exit(lockp);
672*5880Snordmark 		dropped = B_TRUE;
673*5880Snordmark 
674*5880Snordmark 		ASSERT(ns_reg[moduleid].nr_create != NULL);
675*5880Snordmark 		stackid = ns->netstack_stackid;
676*5880Snordmark 		DTRACE_PROBE2(netstack__create__start,
677*5880Snordmark 		    netstackid_t, stackid,
678*5880Snordmark 		    netstack_t *, ns);
679*5880Snordmark 		result = (ns_reg[moduleid].nr_create)(stackid, ns);
680*5880Snordmark 		DTRACE_PROBE2(netstack__create__end,
681*5880Snordmark 		    void *, result, netstack_t *, ns);
682*5880Snordmark 
683*5880Snordmark 		ASSERT(result != NULL);
684*5880Snordmark 		mutex_enter(lockp);
685*5880Snordmark 		mutex_enter(&ns->netstack_lock);
686*5880Snordmark 		ns->netstack_modules[moduleid] = result;
687*5880Snordmark 		nms->nms_flags &= ~NSS_CREATE_INPROGRESS;
688*5880Snordmark 		nms->nms_flags |= NSS_CREATE_COMPLETED;
689*5880Snordmark 		cv_broadcast(&nms->nms_cv);
690*5880Snordmark 		DTRACE_PROBE2(netstack__create__completed,
691*5880Snordmark 		    netstack_t *, ns, int, moduleid);
692*5880Snordmark 		mutex_exit(&ns->netstack_lock);
693*5880Snordmark 		return (dropped);
6944287Snordmark 	} else {
695*5880Snordmark 		mutex_exit(&ns->netstack_lock);
696*5880Snordmark 		return (dropped);
697*5880Snordmark 	}
698*5880Snordmark }
699*5880Snordmark 
700*5880Snordmark /*
701*5880Snordmark  * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED
702*5880Snordmark  * is set.
703*5880Snordmark  * If some other thread gets here first and sets *_INPROGRESS, then
704*5880Snordmark  * we wait for that thread to complete so that we can ensure that
705*5880Snordmark  * all the callbacks are done when we've looped over all netstacks/moduleids.
706*5880Snordmark  *
707*5880Snordmark  * When we call the shutdown function, we temporarily drop the netstack_lock
708*5880Snordmark  * held by the caller, and return true to tell the caller it needs to
709*5880Snordmark  * re-evalute the state.
710*5880Snordmark  */
711*5880Snordmark static boolean_t
712*5880Snordmark netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid)
713*5880Snordmark {
714*5880Snordmark 	netstackid_t stackid;
715*5880Snordmark 	void * netstack_module;
716*5880Snordmark 	nm_state_t *nms = &ns->netstack_m_state[moduleid];
717*5880Snordmark 	boolean_t dropped = B_FALSE;
718*5880Snordmark 
719*5880Snordmark 	ASSERT(MUTEX_HELD(lockp));
720*5880Snordmark 	mutex_enter(&ns->netstack_lock);
721*5880Snordmark 
722*5880Snordmark 	if (wait_for_nms_inprogress(ns, nms, lockp))
723*5880Snordmark 		dropped = B_TRUE;
7244287Snordmark 
725*5880Snordmark 	if (nms->nms_flags & NSS_SHUTDOWN_NEEDED) {
726*5880Snordmark 		nms->nms_flags &= ~NSS_SHUTDOWN_NEEDED;
727*5880Snordmark 		nms->nms_flags |= NSS_SHUTDOWN_INPROGRESS;
728*5880Snordmark 		DTRACE_PROBE2(netstack__shutdown__inprogress,
729*5880Snordmark 		    netstack_t *, ns, int, moduleid);
730*5880Snordmark 		mutex_exit(&ns->netstack_lock);
731*5880Snordmark 		mutex_exit(lockp);
732*5880Snordmark 		dropped = B_TRUE;
733*5880Snordmark 
734*5880Snordmark 		ASSERT(ns_reg[moduleid].nr_shutdown != NULL);
735*5880Snordmark 		stackid = ns->netstack_stackid;
736*5880Snordmark 		netstack_module = ns->netstack_modules[moduleid];
737*5880Snordmark 		DTRACE_PROBE2(netstack__shutdown__start,
738*5880Snordmark 		    netstackid_t, stackid,
739*5880Snordmark 		    void *, netstack_module);
740*5880Snordmark 		(ns_reg[moduleid].nr_shutdown)(stackid, netstack_module);
741*5880Snordmark 		DTRACE_PROBE1(netstack__shutdown__end,
742*5880Snordmark 		    netstack_t *, ns);
743*5880Snordmark 
744*5880Snordmark 		mutex_enter(lockp);
745*5880Snordmark 		mutex_enter(&ns->netstack_lock);
746*5880Snordmark 		nms->nms_flags &= ~NSS_SHUTDOWN_INPROGRESS;
747*5880Snordmark 		nms->nms_flags |= NSS_SHUTDOWN_COMPLETED;
748*5880Snordmark 		cv_broadcast(&nms->nms_cv);
749*5880Snordmark 		DTRACE_PROBE2(netstack__shutdown__completed,
750*5880Snordmark 		    netstack_t *, ns, int, moduleid);
751*5880Snordmark 		mutex_exit(&ns->netstack_lock);
752*5880Snordmark 		return (dropped);
753*5880Snordmark 	} else {
754*5880Snordmark 		mutex_exit(&ns->netstack_lock);
755*5880Snordmark 		return (dropped);
7564287Snordmark 	}
7573448Sdh155122 }
7583448Sdh155122 
7593448Sdh155122 /*
760*5880Snordmark  * Call the destroy function for the ns and moduleid if DESTROY_NEEDED
761*5880Snordmark  * is set.
762*5880Snordmark  * If some other thread gets here first and sets *_INPROGRESS, then
763*5880Snordmark  * we wait for that thread to complete so that we can ensure that
764*5880Snordmark  * all the callbacks are done when we've looped over all netstacks/moduleids.
7653448Sdh155122  *
766*5880Snordmark  * When we call the destroy function, we temporarily drop the netstack_lock
767*5880Snordmark  * held by the caller, and return true to tell the caller it needs to
768*5880Snordmark  * re-evalute the state.
7693448Sdh155122  */
770*5880Snordmark static boolean_t
771*5880Snordmark netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid)
7723448Sdh155122 {
773*5880Snordmark 	netstackid_t stackid;
774*5880Snordmark 	void * netstack_module;
775*5880Snordmark 	nm_state_t *nms = &ns->netstack_m_state[moduleid];
776*5880Snordmark 	boolean_t dropped = B_FALSE;
777*5880Snordmark 
778*5880Snordmark 	ASSERT(MUTEX_HELD(lockp));
779*5880Snordmark 	mutex_enter(&ns->netstack_lock);
780*5880Snordmark 
781*5880Snordmark 	if (wait_for_nms_inprogress(ns, nms, lockp))
782*5880Snordmark 		dropped = B_TRUE;
783*5880Snordmark 
784*5880Snordmark 	if (nms->nms_flags & NSS_DESTROY_NEEDED) {
785*5880Snordmark 		nms->nms_flags &= ~NSS_DESTROY_NEEDED;
786*5880Snordmark 		nms->nms_flags |= NSS_DESTROY_INPROGRESS;
787*5880Snordmark 		DTRACE_PROBE2(netstack__destroy__inprogress,
788*5880Snordmark 		    netstack_t *, ns, int, moduleid);
789*5880Snordmark 		mutex_exit(&ns->netstack_lock);
790*5880Snordmark 		mutex_exit(lockp);
791*5880Snordmark 		dropped = B_TRUE;
792*5880Snordmark 
793*5880Snordmark 		ASSERT(ns_reg[moduleid].nr_destroy != NULL);
794*5880Snordmark 		stackid = ns->netstack_stackid;
795*5880Snordmark 		netstack_module = ns->netstack_modules[moduleid];
796*5880Snordmark 		DTRACE_PROBE2(netstack__destroy__start,
797*5880Snordmark 		    netstackid_t, stackid,
798*5880Snordmark 		    void *, netstack_module);
799*5880Snordmark 		(ns_reg[moduleid].nr_destroy)(stackid, netstack_module);
800*5880Snordmark 		DTRACE_PROBE1(netstack__destroy__end,
801*5880Snordmark 		    netstack_t *, ns);
802*5880Snordmark 
803*5880Snordmark 		mutex_enter(lockp);
804*5880Snordmark 		mutex_enter(&ns->netstack_lock);
805*5880Snordmark 		ns->netstack_modules[moduleid] = NULL;
806*5880Snordmark 		nms->nms_flags &= ~NSS_DESTROY_INPROGRESS;
807*5880Snordmark 		nms->nms_flags |= NSS_DESTROY_COMPLETED;
808*5880Snordmark 		cv_broadcast(&nms->nms_cv);
809*5880Snordmark 		DTRACE_PROBE2(netstack__destroy__completed,
810*5880Snordmark 		    netstack_t *, ns, int, moduleid);
811*5880Snordmark 		mutex_exit(&ns->netstack_lock);
812*5880Snordmark 		return (dropped);
813*5880Snordmark 	} else {
814*5880Snordmark 		mutex_exit(&ns->netstack_lock);
815*5880Snordmark 		return (dropped);
816*5880Snordmark 	}
8173448Sdh155122 }
8183448Sdh155122 
8193448Sdh155122 /*
820*5880Snordmark  * If somebody  is creating the netstack (due to a new zone being created)
821*5880Snordmark  * then we wait for them to complete. This ensures that any additional
822*5880Snordmark  * netstack_register() doesn't cause the create functions to run out of
823*5880Snordmark  * order.
824*5880Snordmark  * Note that we do not need such a global wait in the case of the shutdown
825*5880Snordmark  * and destroy callbacks, since in that case it is sufficient for both
826*5880Snordmark  * threads to set NEEDED and wait for INPROGRESS to ensure ordering.
827*5880Snordmark  * Returns true if lockp was temporarily dropped while waiting.
8283448Sdh155122  */
829*5880Snordmark static boolean_t
830*5880Snordmark wait_for_zone_creator(netstack_t *ns, kmutex_t *lockp)
8313448Sdh155122 {
832*5880Snordmark 	boolean_t dropped = B_FALSE;
833*5880Snordmark 
834*5880Snordmark 	mutex_enter(&ns->netstack_lock);
835*5880Snordmark 	while (ns->netstack_flags & NSF_ZONE_CREATE) {
836*5880Snordmark 		DTRACE_PROBE1(netstack__wait__zone__inprogress,
837*5880Snordmark 		    netstack_t *, ns);
838*5880Snordmark 		if (lockp != NULL) {
839*5880Snordmark 			dropped = B_TRUE;
840*5880Snordmark 			mutex_exit(lockp);
841*5880Snordmark 		}
842*5880Snordmark 		cv_wait(&ns->netstack_cv, &ns->netstack_lock);
843*5880Snordmark 		if (lockp != NULL) {
844*5880Snordmark 			/* First drop netstack_lock to preserve order */
845*5880Snordmark 			mutex_exit(&ns->netstack_lock);
846*5880Snordmark 			mutex_enter(lockp);
847*5880Snordmark 			mutex_enter(&ns->netstack_lock);
848*5880Snordmark 		}
849*5880Snordmark 	}
850*5880Snordmark 	mutex_exit(&ns->netstack_lock);
851*5880Snordmark 	return (dropped);
8523448Sdh155122 }
8533448Sdh155122 
8543448Sdh155122 /*
855*5880Snordmark  * Wait for any INPROGRESS flag to be cleared for the netstack/moduleid
856*5880Snordmark  * combination.
857*5880Snordmark  * Returns true if lockp was temporarily dropped while waiting.
8583448Sdh155122  */
859*5880Snordmark static boolean_t
860*5880Snordmark wait_for_nms_inprogress(netstack_t *ns, nm_state_t *nms, kmutex_t *lockp)
8613448Sdh155122 {
862*5880Snordmark 	boolean_t dropped = B_FALSE;
863*5880Snordmark 
864*5880Snordmark 	while (nms->nms_flags & NSS_ALL_INPROGRESS) {
865*5880Snordmark 		DTRACE_PROBE2(netstack__wait__nms__inprogress,
866*5880Snordmark 		    netstack_t *, ns, nm_state_t *, nms);
867*5880Snordmark 		if (lockp != NULL) {
868*5880Snordmark 			dropped = B_TRUE;
869*5880Snordmark 			mutex_exit(lockp);
870*5880Snordmark 		}
871*5880Snordmark 		cv_wait(&nms->nms_cv, &ns->netstack_lock);
872*5880Snordmark 		if (lockp != NULL) {
873*5880Snordmark 			/* First drop netstack_lock to preserve order */
874*5880Snordmark 			mutex_exit(&ns->netstack_lock);
875*5880Snordmark 			mutex_enter(lockp);
876*5880Snordmark 			mutex_enter(&ns->netstack_lock);
877*5880Snordmark 		}
878*5880Snordmark 	}
879*5880Snordmark 	return (dropped);
8803448Sdh155122 }
8813448Sdh155122 
8823448Sdh155122 /*
8833448Sdh155122  * Get the stack instance used in caller's zone.
8843448Sdh155122  * Increases the reference count, caller must do a netstack_rele.
8853448Sdh155122  * It can't be called after zone_destroy() has started.
8863448Sdh155122  */
8874136Snordmark netstack_t *
8883448Sdh155122 netstack_get_current(void)
8893448Sdh155122 {
8903448Sdh155122 	netstack_t *ns;
8913448Sdh155122 
8923448Sdh155122 	ns = curproc->p_zone->zone_netstack;
8933448Sdh155122 	ASSERT(ns != NULL);
8943448Sdh155122 	if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
8953448Sdh155122 		return (NULL);
8963448Sdh155122 
8973448Sdh155122 	netstack_hold(ns);
8983448Sdh155122 
8993448Sdh155122 	return (ns);
9003448Sdh155122 }
9013448Sdh155122 
9023448Sdh155122 /*
9033448Sdh155122  * Find a stack instance given the cred.
9043448Sdh155122  * This is used by the modules to potentially allow for a future when
9053448Sdh155122  * something other than the zoneid is used to determine the stack.
9063448Sdh155122  */
9073448Sdh155122 netstack_t *
9083448Sdh155122 netstack_find_by_cred(const cred_t *cr)
9093448Sdh155122 {
9103448Sdh155122 	zoneid_t zoneid = crgetzoneid(cr);
9113448Sdh155122 
9123448Sdh155122 	/* Handle the case when cr_zone is NULL */
9133448Sdh155122 	if (zoneid == (zoneid_t)-1)
9143448Sdh155122 		zoneid = GLOBAL_ZONEID;
9153448Sdh155122 
9163448Sdh155122 	/* For performance ... */
9173448Sdh155122 	if (curproc->p_zone->zone_id == zoneid)
9183448Sdh155122 		return (netstack_get_current());
9193448Sdh155122 	else
9203448Sdh155122 		return (netstack_find_by_zoneid(zoneid));
9213448Sdh155122 }
9223448Sdh155122 
9233448Sdh155122 /*
9243448Sdh155122  * Find a stack instance given the zoneid.
9253448Sdh155122  * Increases the reference count if found; caller must do a
9263448Sdh155122  * netstack_rele().
9273448Sdh155122  *
9283448Sdh155122  * If there is no exact match then assume the shared stack instance
9293448Sdh155122  * matches.
9303448Sdh155122  *
9313448Sdh155122  * Skip the unitialized ones.
9323448Sdh155122  */
9333448Sdh155122 netstack_t *
9343448Sdh155122 netstack_find_by_zoneid(zoneid_t zoneid)
9353448Sdh155122 {
9363448Sdh155122 	netstack_t *ns;
9373448Sdh155122 	zone_t *zone;
9383448Sdh155122 
9393448Sdh155122 	zone = zone_find_by_id(zoneid);
9403448Sdh155122 
9413448Sdh155122 	if (zone == NULL)
9423448Sdh155122 		return (NULL);
9433448Sdh155122 
9443448Sdh155122 	ns = zone->zone_netstack;
9453448Sdh155122 	ASSERT(ns != NULL);
9463448Sdh155122 	if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
9473448Sdh155122 		ns = NULL;
9483448Sdh155122 	else
9493448Sdh155122 		netstack_hold(ns);
9503448Sdh155122 
9513448Sdh155122 	zone_rele(zone);
9523448Sdh155122 	return (ns);
9533448Sdh155122 }
9543448Sdh155122 
9553448Sdh155122 /*
956*5880Snordmark  * Find a stack instance given the zoneid. Can only be called from
957*5880Snordmark  * the create callback. See the comments in zone_find_by_id_nolock why
958*5880Snordmark  * that limitation exists.
959*5880Snordmark  *
9603448Sdh155122  * Increases the reference count if found; caller must do a
9613448Sdh155122  * netstack_rele().
9623448Sdh155122  *
9633448Sdh155122  * If there is no exact match then assume the shared stack instance
9643448Sdh155122  * matches.
9653448Sdh155122  *
9663448Sdh155122  * Skip the unitialized ones.
9673448Sdh155122  */
9683448Sdh155122 netstack_t *
9693448Sdh155122 netstack_find_by_zoneid_nolock(zoneid_t zoneid)
9703448Sdh155122 {
9713448Sdh155122 	netstack_t *ns;
9723448Sdh155122 	zone_t *zone;
9733448Sdh155122 
9743448Sdh155122 	zone = zone_find_by_id_nolock(zoneid);
9753448Sdh155122 
9763448Sdh155122 	if (zone == NULL)
9773448Sdh155122 		return (NULL);
9783448Sdh155122 
9793448Sdh155122 	ns = zone->zone_netstack;
9803448Sdh155122 	ASSERT(ns != NULL);
9813448Sdh155122 
9823448Sdh155122 	if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
9833448Sdh155122 		ns = NULL;
9843448Sdh155122 	else
9853448Sdh155122 		netstack_hold(ns);
9863448Sdh155122 
987*5880Snordmark 	/* zone_find_by_id_nolock does not have a hold on the zone */
9883448Sdh155122 	return (ns);
9893448Sdh155122 }
9903448Sdh155122 
9913448Sdh155122 /*
9923448Sdh155122  * Find a stack instance given the stackid with exact match?
9933448Sdh155122  * Increases the reference count if found; caller must do a
9943448Sdh155122  * netstack_rele().
9953448Sdh155122  *
9963448Sdh155122  * Skip the unitialized ones.
9973448Sdh155122  */
9983448Sdh155122 netstack_t *
9993448Sdh155122 netstack_find_by_stackid(netstackid_t stackid)
10003448Sdh155122 {
10013448Sdh155122 	netstack_t *ns;
10023448Sdh155122 
10033448Sdh155122 	mutex_enter(&netstack_g_lock);
10043448Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
10053448Sdh155122 		mutex_enter(&ns->netstack_lock);
10063448Sdh155122 		if (ns->netstack_stackid == stackid &&
10073448Sdh155122 		    !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
10083448Sdh155122 			mutex_exit(&ns->netstack_lock);
10093448Sdh155122 			netstack_hold(ns);
10103448Sdh155122 			mutex_exit(&netstack_g_lock);
10113448Sdh155122 			return (ns);
10123448Sdh155122 		}
10133448Sdh155122 		mutex_exit(&ns->netstack_lock);
10143448Sdh155122 	}
10153448Sdh155122 	mutex_exit(&netstack_g_lock);
10163448Sdh155122 	return (NULL);
10173448Sdh155122 }
10183448Sdh155122 
10193448Sdh155122 void
10203448Sdh155122 netstack_rele(netstack_t *ns)
10213448Sdh155122 {
10223448Sdh155122 	netstack_t **nsp;
10233448Sdh155122 	boolean_t found;
10243448Sdh155122 	int refcnt, numzones;
1025*5880Snordmark 	int i;
10263448Sdh155122 
10273448Sdh155122 	mutex_enter(&ns->netstack_lock);
10283448Sdh155122 	ASSERT(ns->netstack_refcnt > 0);
10293448Sdh155122 	ns->netstack_refcnt--;
10303448Sdh155122 	/*
10313448Sdh155122 	 * As we drop the lock additional netstack_rele()s can come in
10323448Sdh155122 	 * and decrement the refcnt to zero and free the netstack_t.
10333448Sdh155122 	 * Store pointers in local variables and if we were not the last
10343448Sdh155122 	 * then don't reference the netstack_t after that.
10353448Sdh155122 	 */
10363448Sdh155122 	refcnt = ns->netstack_refcnt;
10373448Sdh155122 	numzones = ns->netstack_numzones;
10383448Sdh155122 	DTRACE_PROBE1(netstack__dec__ref, netstack_t *, ns);
10393448Sdh155122 	mutex_exit(&ns->netstack_lock);
10403448Sdh155122 
10413448Sdh155122 	if (refcnt == 0 && numzones == 0) {
10423448Sdh155122 		/*
10433448Sdh155122 		 * Time to call the destroy functions and free up
10443448Sdh155122 		 * the structure
10453448Sdh155122 		 */
10463448Sdh155122 		netstack_stack_inactive(ns);
10473448Sdh155122 
10484287Snordmark 		/* Make sure nothing increased the references */
10494287Snordmark 		ASSERT(ns->netstack_refcnt == 0);
10504287Snordmark 		ASSERT(ns->netstack_numzones == 0);
10514287Snordmark 
10523448Sdh155122 		/* Finally remove from list of netstacks */
10533448Sdh155122 		mutex_enter(&netstack_g_lock);
10543448Sdh155122 		found = B_FALSE;
10553448Sdh155122 		for (nsp = &netstack_head; *nsp != NULL;
10563448Sdh155122 		    nsp = &(*nsp)->netstack_next) {
10573448Sdh155122 			if (*nsp == ns) {
10583448Sdh155122 				*nsp = ns->netstack_next;
10593448Sdh155122 				ns->netstack_next = NULL;
10603448Sdh155122 				found = B_TRUE;
10613448Sdh155122 				break;
10623448Sdh155122 			}
10633448Sdh155122 		}
10643448Sdh155122 		ASSERT(found);
10653448Sdh155122 		mutex_exit(&netstack_g_lock);
10663448Sdh155122 
10674287Snordmark 		/* Make sure nothing increased the references */
10684287Snordmark 		ASSERT(ns->netstack_refcnt == 0);
10694287Snordmark 		ASSERT(ns->netstack_numzones == 0);
10704287Snordmark 
10713448Sdh155122 		ASSERT(ns->netstack_flags & NSF_CLOSING);
1072*5880Snordmark 
1073*5880Snordmark 		for (i = 0; i < NS_MAX; i++) {
1074*5880Snordmark 			nm_state_t *nms = &ns->netstack_m_state[i];
1075*5880Snordmark 
1076*5880Snordmark 			cv_destroy(&nms->nms_cv);
1077*5880Snordmark 		}
1078*5880Snordmark 		mutex_destroy(&ns->netstack_lock);
1079*5880Snordmark 		cv_destroy(&ns->netstack_cv);
10803448Sdh155122 		kmem_free(ns, sizeof (*ns));
10813448Sdh155122 	}
10823448Sdh155122 }
10833448Sdh155122 
10843448Sdh155122 void
10853448Sdh155122 netstack_hold(netstack_t *ns)
10863448Sdh155122 {
10873448Sdh155122 	mutex_enter(&ns->netstack_lock);
10883448Sdh155122 	ns->netstack_refcnt++;
10893448Sdh155122 	ASSERT(ns->netstack_refcnt > 0);
10903448Sdh155122 	mutex_exit(&ns->netstack_lock);
10913448Sdh155122 	DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
10923448Sdh155122 }
10933448Sdh155122 
10943448Sdh155122 /*
10953448Sdh155122  * To support kstat_create_netstack() using kstat_zone_add we need
10963448Sdh155122  * to track both
10973448Sdh155122  *  - all zoneids that use the global/shared stack
10983448Sdh155122  *  - all kstats that have been added for the shared stack
10993448Sdh155122  */
11003448Sdh155122 kstat_t *
11013448Sdh155122 kstat_create_netstack(char *ks_module, int ks_instance, char *ks_name,
11023448Sdh155122     char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
11033448Sdh155122     netstackid_t ks_netstackid)
11043448Sdh155122 {
11053448Sdh155122 	kstat_t *ks;
11063448Sdh155122 
11073448Sdh155122 	if (ks_netstackid == GLOBAL_NETSTACKID) {
11083448Sdh155122 		ks = kstat_create_zone(ks_module, ks_instance, ks_name,
11093448Sdh155122 		    ks_class, ks_type, ks_ndata, ks_flags, GLOBAL_ZONEID);
11103448Sdh155122 		if (ks != NULL)
11113448Sdh155122 			netstack_shared_kstat_add(ks);
11123448Sdh155122 		return (ks);
11133448Sdh155122 	} else {
11143448Sdh155122 		zoneid_t zoneid = ks_netstackid;
11153448Sdh155122 
11163448Sdh155122 		return (kstat_create_zone(ks_module, ks_instance, ks_name,
1117*5880Snordmark 		    ks_class, ks_type, ks_ndata, ks_flags, zoneid));
11183448Sdh155122 	}
11193448Sdh155122 }
11203448Sdh155122 
11213448Sdh155122 void
11223448Sdh155122 kstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid)
11233448Sdh155122 {
11243448Sdh155122 	if (ks_netstackid == GLOBAL_NETSTACKID) {
11253448Sdh155122 		netstack_shared_kstat_remove(ks);
11263448Sdh155122 	}
11273448Sdh155122 	kstat_delete(ks);
11283448Sdh155122 }
11293448Sdh155122 
11303448Sdh155122 static void
11313448Sdh155122 netstack_shared_zone_add(zoneid_t zoneid)
11323448Sdh155122 {
11333448Sdh155122 	struct shared_zone_list *sz;
11343448Sdh155122 	struct shared_kstat_list *sk;
11353448Sdh155122 
11363448Sdh155122 	sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP);
11373448Sdh155122 	sz->sz_zoneid = zoneid;
11383448Sdh155122 
11393448Sdh155122 	/* Insert in list */
11403448Sdh155122 	mutex_enter(&netstack_shared_lock);
11413448Sdh155122 	sz->sz_next = netstack_shared_zones;
11423448Sdh155122 	netstack_shared_zones = sz;
11433448Sdh155122 
11443448Sdh155122 	/*
11453448Sdh155122 	 * Perform kstat_zone_add for each existing shared stack kstat.
11463448Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_add.
11473448Sdh155122 	 */
11483448Sdh155122 	for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
11493448Sdh155122 		kstat_zone_add(sk->sk_kstat, zoneid);
11503448Sdh155122 	}
11513448Sdh155122 	mutex_exit(&netstack_shared_lock);
11523448Sdh155122 }
11533448Sdh155122 
11543448Sdh155122 static void
11553448Sdh155122 netstack_shared_zone_remove(zoneid_t zoneid)
11563448Sdh155122 {
11573448Sdh155122 	struct shared_zone_list **szp, *sz;
11583448Sdh155122 	struct shared_kstat_list *sk;
11593448Sdh155122 
11603448Sdh155122 	/* Find in list */
11613448Sdh155122 	mutex_enter(&netstack_shared_lock);
11623448Sdh155122 	sz = NULL;
11633448Sdh155122 	for (szp = &netstack_shared_zones; *szp != NULL;
11643448Sdh155122 	    szp = &((*szp)->sz_next)) {
11653448Sdh155122 		if ((*szp)->sz_zoneid == zoneid) {
11663448Sdh155122 			sz = *szp;
11673448Sdh155122 			break;
11683448Sdh155122 		}
11693448Sdh155122 	}
11703448Sdh155122 	/* We must find it */
11713448Sdh155122 	ASSERT(sz != NULL);
11723448Sdh155122 	*szp = sz->sz_next;
11733448Sdh155122 	sz->sz_next = NULL;
11743448Sdh155122 
11753448Sdh155122 	/*
11763448Sdh155122 	 * Perform kstat_zone_remove for each existing shared stack kstat.
11773448Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
11783448Sdh155122 	 */
11793448Sdh155122 	for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
11803448Sdh155122 		kstat_zone_remove(sk->sk_kstat, zoneid);
11813448Sdh155122 	}
11823448Sdh155122 	mutex_exit(&netstack_shared_lock);
11833448Sdh155122 
11843448Sdh155122 	kmem_free(sz, sizeof (*sz));
11853448Sdh155122 }
11863448Sdh155122 
11873448Sdh155122 static void
11883448Sdh155122 netstack_shared_kstat_add(kstat_t *ks)
11893448Sdh155122 {
11903448Sdh155122 	struct shared_zone_list *sz;
11913448Sdh155122 	struct shared_kstat_list *sk;
11923448Sdh155122 
11933448Sdh155122 	sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP);
11943448Sdh155122 	sk->sk_kstat = ks;
11953448Sdh155122 
11963448Sdh155122 	/* Insert in list */
11973448Sdh155122 	mutex_enter(&netstack_shared_lock);
11983448Sdh155122 	sk->sk_next = netstack_shared_kstats;
11993448Sdh155122 	netstack_shared_kstats = sk;
12003448Sdh155122 
12013448Sdh155122 	/*
12023448Sdh155122 	 * Perform kstat_zone_add for each existing shared stack zone.
12033448Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_add.
12043448Sdh155122 	 */
12053448Sdh155122 	for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
12063448Sdh155122 		kstat_zone_add(ks, sz->sz_zoneid);
12073448Sdh155122 	}
12083448Sdh155122 	mutex_exit(&netstack_shared_lock);
12093448Sdh155122 }
12103448Sdh155122 
12113448Sdh155122 static void
12123448Sdh155122 netstack_shared_kstat_remove(kstat_t *ks)
12133448Sdh155122 {
12143448Sdh155122 	struct shared_zone_list *sz;
12153448Sdh155122 	struct shared_kstat_list **skp, *sk;
12163448Sdh155122 
12173448Sdh155122 	/* Find in list */
12183448Sdh155122 	mutex_enter(&netstack_shared_lock);
12193448Sdh155122 	sk = NULL;
12203448Sdh155122 	for (skp = &netstack_shared_kstats; *skp != NULL;
12213448Sdh155122 	    skp = &((*skp)->sk_next)) {
12223448Sdh155122 		if ((*skp)->sk_kstat == ks) {
12233448Sdh155122 			sk = *skp;
12243448Sdh155122 			break;
12253448Sdh155122 		}
12263448Sdh155122 	}
12273448Sdh155122 	/* Must find it */
12283448Sdh155122 	ASSERT(sk != NULL);
12293448Sdh155122 	*skp = sk->sk_next;
12303448Sdh155122 	sk->sk_next = NULL;
12313448Sdh155122 
12323448Sdh155122 	/*
12333448Sdh155122 	 * Perform kstat_zone_remove for each existing shared stack kstat.
12343448Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
12353448Sdh155122 	 */
12363448Sdh155122 	for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
12373448Sdh155122 		kstat_zone_remove(ks, sz->sz_zoneid);
12383448Sdh155122 	}
12393448Sdh155122 	mutex_exit(&netstack_shared_lock);
12403448Sdh155122 	kmem_free(sk, sizeof (*sk));
12413448Sdh155122 }
12423448Sdh155122 
12433448Sdh155122 /*
12443448Sdh155122  * If a zoneid is part of the shared zone, return true
12453448Sdh155122  */
12463448Sdh155122 static boolean_t
12473448Sdh155122 netstack_find_shared_zoneid(zoneid_t zoneid)
12483448Sdh155122 {
12493448Sdh155122 	struct shared_zone_list *sz;
12503448Sdh155122 
12513448Sdh155122 	mutex_enter(&netstack_shared_lock);
12523448Sdh155122 	for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
12533448Sdh155122 		if (sz->sz_zoneid == zoneid) {
12543448Sdh155122 			mutex_exit(&netstack_shared_lock);
12553448Sdh155122 			return (B_TRUE);
12563448Sdh155122 		}
12573448Sdh155122 	}
12583448Sdh155122 	mutex_exit(&netstack_shared_lock);
12593448Sdh155122 	return (B_FALSE);
12603448Sdh155122 }
12613448Sdh155122 
12623448Sdh155122 /*
12633448Sdh155122  * Hide the fact that zoneids and netstackids are allocated from
12643448Sdh155122  * the same space in the current implementation.
1265*5880Snordmark  * We currently do not check that the stackid/zoneids are valid, since there
1266*5880Snordmark  * is no need for that. But this should only be done for ids that are
1267*5880Snordmark  * valid.
12683448Sdh155122  */
12693448Sdh155122 zoneid_t
12703448Sdh155122 netstackid_to_zoneid(netstackid_t stackid)
12713448Sdh155122 {
12723448Sdh155122 	return (stackid);
12733448Sdh155122 }
12743448Sdh155122 
12753448Sdh155122 netstackid_t
12763448Sdh155122 zoneid_to_netstackid(zoneid_t zoneid)
12773448Sdh155122 {
12783448Sdh155122 	if (netstack_find_shared_zoneid(zoneid))
12793448Sdh155122 		return (GLOBAL_ZONEID);
12803448Sdh155122 	else
12813448Sdh155122 		return (zoneid);
12823448Sdh155122 }
12833448Sdh155122 
12843448Sdh155122 /*
12853448Sdh155122  * Simplistic support for walking all the handles.
12863448Sdh155122  * Example usage:
12873448Sdh155122  *	netstack_handle_t nh;
12883448Sdh155122  *	netstack_t *ns;
12893448Sdh155122  *
12903448Sdh155122  *	netstack_next_init(&nh);
12913448Sdh155122  *	while ((ns = netstack_next(&nh)) != NULL) {
12923448Sdh155122  *		do something;
12933448Sdh155122  *		netstack_rele(ns);
12943448Sdh155122  *	}
12953448Sdh155122  *	netstack_next_fini(&nh);
12963448Sdh155122  */
12973448Sdh155122 void
12983448Sdh155122 netstack_next_init(netstack_handle_t *handle)
12993448Sdh155122 {
13003448Sdh155122 	*handle = 0;
13013448Sdh155122 }
13023448Sdh155122 
13033448Sdh155122 /* ARGSUSED */
13043448Sdh155122 void
13053448Sdh155122 netstack_next_fini(netstack_handle_t *handle)
13063448Sdh155122 {
13073448Sdh155122 }
13083448Sdh155122 
13093448Sdh155122 netstack_t *
13103448Sdh155122 netstack_next(netstack_handle_t *handle)
13113448Sdh155122 {
13123448Sdh155122 	netstack_t *ns;
13133448Sdh155122 	int i, end;
13143448Sdh155122 
13153448Sdh155122 	end = *handle;
13163448Sdh155122 	/* Walk skipping *handle number of instances */
13173448Sdh155122 
13183448Sdh155122 	/* Look if there is a matching stack instance */
13193448Sdh155122 	mutex_enter(&netstack_g_lock);
13203448Sdh155122 	ns = netstack_head;
13213448Sdh155122 	for (i = 0; i < end; i++) {
13223448Sdh155122 		if (ns == NULL)
13233448Sdh155122 			break;
13243448Sdh155122 		ns = ns->netstack_next;
13253448Sdh155122 	}
13263448Sdh155122 	/* skip those with that aren't really here */
13273448Sdh155122 	while (ns != NULL) {
13283448Sdh155122 		mutex_enter(&ns->netstack_lock);
13293448Sdh155122 		if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
13303448Sdh155122 			mutex_exit(&ns->netstack_lock);
13313448Sdh155122 			break;
13323448Sdh155122 		}
13333448Sdh155122 		mutex_exit(&ns->netstack_lock);
13343448Sdh155122 		end++;
13353448Sdh155122 		ns = ns->netstack_next;
13363448Sdh155122 	}
13373448Sdh155122 	if (ns != NULL) {
13383448Sdh155122 		*handle = end + 1;
13393448Sdh155122 		netstack_hold(ns);
13403448Sdh155122 	}
13413448Sdh155122 	mutex_exit(&netstack_g_lock);
13423448Sdh155122 	return (ns);
13433448Sdh155122 }
1344