xref: /titanic_53/usr/src/uts/common/os/netstack.c (revision fd00680555e8f4173d02435c3b015e23cb232c49)
1f4b3ec61Sdh155122 /*
2f4b3ec61Sdh155122  * CDDL HEADER START
3f4b3ec61Sdh155122  *
4f4b3ec61Sdh155122  * The contents of this file are subject to the terms of the
5f4b3ec61Sdh155122  * Common Development and Distribution License (the "License").
6f4b3ec61Sdh155122  * You may not use this file except in compliance with the License.
7f4b3ec61Sdh155122  *
8f4b3ec61Sdh155122  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f4b3ec61Sdh155122  * or http://www.opensolaris.org/os/licensing.
10f4b3ec61Sdh155122  * See the License for the specific language governing permissions
11f4b3ec61Sdh155122  * and limitations under the License.
12f4b3ec61Sdh155122  *
13f4b3ec61Sdh155122  * When distributing Covered Code, include this CDDL HEADER in each
14f4b3ec61Sdh155122  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f4b3ec61Sdh155122  * If applicable, add the following below this CDDL HEADER, with the
16f4b3ec61Sdh155122  * fields enclosed by brackets "[]" replaced with your own identifying
17f4b3ec61Sdh155122  * information: Portions Copyright [yyyy] [name of copyright owner]
18f4b3ec61Sdh155122  *
19f4b3ec61Sdh155122  * CDDL HEADER END
20f4b3ec61Sdh155122  */
21f4b3ec61Sdh155122 
22f4b3ec61Sdh155122 /*
23f4b3ec61Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24f4b3ec61Sdh155122  * Use is subject to license terms.
25f4b3ec61Sdh155122  */
26f4b3ec61Sdh155122 
27f4b3ec61Sdh155122 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28f4b3ec61Sdh155122 
29f4b3ec61Sdh155122 #include <sys/param.h>
30f4b3ec61Sdh155122 #include <sys/sysmacros.h>
31f4b3ec61Sdh155122 #include <sys/vm.h>
32f4b3ec61Sdh155122 #include <sys/proc.h>
33f4b3ec61Sdh155122 #include <sys/tuneable.h>
34f4b3ec61Sdh155122 #include <sys/systm.h>
35f4b3ec61Sdh155122 #include <sys/cmn_err.h>
36f4b3ec61Sdh155122 #include <sys/debug.h>
37f4b3ec61Sdh155122 #include <sys/sdt.h>
38f4b3ec61Sdh155122 #include <sys/mutex.h>
39f4b3ec61Sdh155122 #include <sys/bitmap.h>
40f4b3ec61Sdh155122 #include <sys/atomic.h>
41f4b3ec61Sdh155122 #include <sys/kobj.h>
42f4b3ec61Sdh155122 #include <sys/disp.h>
43f4b3ec61Sdh155122 #include <vm/seg_kmem.h>
44f4b3ec61Sdh155122 #include <sys/zone.h>
45f4b3ec61Sdh155122 #include <sys/netstack.h>
46f4b3ec61Sdh155122 
47f4b3ec61Sdh155122 /*
48f4b3ec61Sdh155122  * What we use so that the zones framework can tell us about new zones,
49f4b3ec61Sdh155122  * which we use to create new stacks.
50f4b3ec61Sdh155122  */
51f4b3ec61Sdh155122 static zone_key_t netstack_zone_key;
52f4b3ec61Sdh155122 
53f4b3ec61Sdh155122 static int	netstack_initialized = 0;
54f4b3ec61Sdh155122 
55f4b3ec61Sdh155122 /*
56f4b3ec61Sdh155122  * Track the registered netstacks.
57f4b3ec61Sdh155122  * The global lock protects
58f4b3ec61Sdh155122  * - ns_reg
59f4b3ec61Sdh155122  * - the list starting at netstack_head and following the netstack_next
60f4b3ec61Sdh155122  *   pointers.
61f4b3ec61Sdh155122  */
62f4b3ec61Sdh155122 static kmutex_t netstack_g_lock;
63f4b3ec61Sdh155122 
64f4b3ec61Sdh155122 /*
65f4b3ec61Sdh155122  * Registry of netstacks with their create/shutdown/destory functions.
66f4b3ec61Sdh155122  */
67f4b3ec61Sdh155122 static struct netstack_registry	ns_reg[NS_MAX];
68f4b3ec61Sdh155122 
69f4b3ec61Sdh155122 /*
70f4b3ec61Sdh155122  * Global list of existing stacks.  We use this when a new zone with
71f4b3ec61Sdh155122  * an exclusive IP instance is created.
72f4b3ec61Sdh155122  *
73f4b3ec61Sdh155122  * Note that in some cases a netstack_t needs to stay around after the zone
74f4b3ec61Sdh155122  * has gone away. This is because there might be outstanding references
75f4b3ec61Sdh155122  * (from TCP TIME_WAIT connections, IPsec state, etc). The netstack_t data
76f4b3ec61Sdh155122  * structure and all the foo_stack_t's hanging off of it will be cleaned up
77f4b3ec61Sdh155122  * when the last reference to it is dropped.
78f4b3ec61Sdh155122  * However, the same zone might be rebooted. That is handled using the
79f4b3ec61Sdh155122  * assumption that the zones framework picks a new zoneid each time a zone
80f4b3ec61Sdh155122  * is (re)booted. We assert for that condition in netstack_zone_create().
81f4b3ec61Sdh155122  * Thus the old netstack_t can take its time for things to time out.
82f4b3ec61Sdh155122  */
83f4b3ec61Sdh155122 static netstack_t *netstack_head;
84f4b3ec61Sdh155122 
85f4b3ec61Sdh155122 /*
86f4b3ec61Sdh155122  * To support kstat_create_netstack() using kstat_zone_add we need
87f4b3ec61Sdh155122  * to track both
88f4b3ec61Sdh155122  *  - all zoneids that use the global/shared stack
89f4b3ec61Sdh155122  *  - all kstats that have been added for the shared stack
90f4b3ec61Sdh155122  */
91f4b3ec61Sdh155122 struct shared_zone_list {
92f4b3ec61Sdh155122 	struct shared_zone_list *sz_next;
93f4b3ec61Sdh155122 	zoneid_t		sz_zoneid;
94f4b3ec61Sdh155122 };
95f4b3ec61Sdh155122 
96f4b3ec61Sdh155122 struct shared_kstat_list {
97f4b3ec61Sdh155122 	struct shared_kstat_list *sk_next;
98f4b3ec61Sdh155122 	kstat_t			 *sk_kstat;
99f4b3ec61Sdh155122 };
100f4b3ec61Sdh155122 
101f4b3ec61Sdh155122 static kmutex_t netstack_shared_lock;	/* protects the following two */
102f4b3ec61Sdh155122 static struct shared_zone_list	*netstack_shared_zones;
103f4b3ec61Sdh155122 static struct shared_kstat_list	*netstack_shared_kstats;
104f4b3ec61Sdh155122 
105f4b3ec61Sdh155122 static void	*netstack_zone_create(zoneid_t zoneid);
106f4b3ec61Sdh155122 static void	netstack_zone_shutdown(zoneid_t zoneid, void *arg);
107f4b3ec61Sdh155122 static void	netstack_zone_destroy(zoneid_t zoneid, void *arg);
108f4b3ec61Sdh155122 
109f4b3ec61Sdh155122 static void	netstack_do_create(void);
110f4b3ec61Sdh155122 static void	netstack_do_shutdown(void);
111f4b3ec61Sdh155122 static void	netstack_do_destroy(void);
112f4b3ec61Sdh155122 
113f4b3ec61Sdh155122 static void	netstack_shared_zone_add(zoneid_t zoneid);
114f4b3ec61Sdh155122 static void	netstack_shared_zone_remove(zoneid_t zoneid);
115f4b3ec61Sdh155122 static void	netstack_shared_kstat_add(kstat_t *ks);
116f4b3ec61Sdh155122 static void	netstack_shared_kstat_remove(kstat_t *ks);
117f4b3ec61Sdh155122 
118f4b3ec61Sdh155122 
119f4b3ec61Sdh155122 void
120f4b3ec61Sdh155122 netstack_init(void)
121f4b3ec61Sdh155122 {
122f4b3ec61Sdh155122 	mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL);
123f4b3ec61Sdh155122 	mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL);
124f4b3ec61Sdh155122 
125f4b3ec61Sdh155122 	netstack_initialized = 1;
126f4b3ec61Sdh155122 
127f4b3ec61Sdh155122 	/*
128f4b3ec61Sdh155122 	 * We want to be informed each time a zone is created or
129f4b3ec61Sdh155122 	 * destroyed in the kernel, so we can maintain the
130f4b3ec61Sdh155122 	 * stack instance information.
131f4b3ec61Sdh155122 	 */
132f4b3ec61Sdh155122 	zone_key_create(&netstack_zone_key, netstack_zone_create,
133f4b3ec61Sdh155122 	    netstack_zone_shutdown, netstack_zone_destroy);
134f4b3ec61Sdh155122 }
135f4b3ec61Sdh155122 
136f4b3ec61Sdh155122 /*
137f4b3ec61Sdh155122  * Register a new module with the framework.
138f4b3ec61Sdh155122  * This registers interest in changes to the set of netstacks.
139f4b3ec61Sdh155122  * The createfn and destroyfn are required, but the shutdownfn can be
140f4b3ec61Sdh155122  * NULL.
141f4b3ec61Sdh155122  * Note that due to the current zsd implementation, when the create
142f4b3ec61Sdh155122  * function is called the zone isn't fully present, thus functions
143f4b3ec61Sdh155122  * like zone_find_by_* will fail, hence the create function can not
144f4b3ec61Sdh155122  * use many zones kernel functions including zcmn_err().
145f4b3ec61Sdh155122  */
146f4b3ec61Sdh155122 void
147f4b3ec61Sdh155122 netstack_register(int moduleid,
148f4b3ec61Sdh155122     void *(*module_create)(netstackid_t, netstack_t *),
149f4b3ec61Sdh155122     void (*module_shutdown)(netstackid_t, void *),
150f4b3ec61Sdh155122     void (*module_destroy)(netstackid_t, void *))
151f4b3ec61Sdh155122 {
152f4b3ec61Sdh155122 	netstack_t *ns;
153f4b3ec61Sdh155122 
154f4b3ec61Sdh155122 	ASSERT(netstack_initialized);
155f4b3ec61Sdh155122 	ASSERT(moduleid >= 0 && moduleid < NS_MAX);
156f4b3ec61Sdh155122 	ASSERT(module_create != NULL);
157f4b3ec61Sdh155122 
158f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
159f4b3ec61Sdh155122 	ASSERT(ns_reg[moduleid].nr_create == NULL);
160f4b3ec61Sdh155122 	ASSERT(ns_reg[moduleid].nr_flags == 0);
161f4b3ec61Sdh155122 	ns_reg[moduleid].nr_create = module_create;
162f4b3ec61Sdh155122 	ns_reg[moduleid].nr_shutdown = module_shutdown;
163f4b3ec61Sdh155122 	ns_reg[moduleid].nr_destroy = module_destroy;
164f4b3ec61Sdh155122 	ns_reg[moduleid].nr_flags = NRF_REGISTERED;
165f4b3ec61Sdh155122 
166f4b3ec61Sdh155122 	/*
167f4b3ec61Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
168f4b3ec61Sdh155122 	 * Set CREATE_NEEDED for each of those.
169f4b3ec61Sdh155122 	 * netstacks which have been deleted will have NSS_CREATE_COMPLETED
170f4b3ec61Sdh155122 	 * set, but check NSF_CLOSING to be sure.
171f4b3ec61Sdh155122 	 */
172f4b3ec61Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
173f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
174f4b3ec61Sdh155122 		if (!(ns->netstack_flags & NSF_CLOSING) &&
175f4b3ec61Sdh155122 		    (ns->netstack_m_state[moduleid] & NSS_CREATE_ALL) == 0) {
176f4b3ec61Sdh155122 			ns->netstack_m_state[moduleid] |= NSS_CREATE_NEEDED;
177f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__create__needed,
178f4b3ec61Sdh155122 			    netstack_t *, ns, int, moduleid);
179f4b3ec61Sdh155122 		}
180f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
181f4b3ec61Sdh155122 	}
182f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
183f4b3ec61Sdh155122 
184f4b3ec61Sdh155122 	/*
185f4b3ec61Sdh155122 	 * Call the create function for each stack that has CREATE_NEEDED.
186f4b3ec61Sdh155122 	 * Set CREATE_INPROGRESS, drop lock, and after done,
187f4b3ec61Sdh155122 	 * set CREATE_COMPLETE
188f4b3ec61Sdh155122 	 */
189f4b3ec61Sdh155122 	netstack_do_create();
190f4b3ec61Sdh155122 }
191f4b3ec61Sdh155122 
192f4b3ec61Sdh155122 void
193f4b3ec61Sdh155122 netstack_unregister(int moduleid)
194f4b3ec61Sdh155122 {
195f4b3ec61Sdh155122 	netstack_t *ns;
196f4b3ec61Sdh155122 
197f4b3ec61Sdh155122 	ASSERT(moduleid >= 0 && moduleid < NS_MAX);
198f4b3ec61Sdh155122 
199f4b3ec61Sdh155122 	ASSERT(ns_reg[moduleid].nr_create != NULL);
200f4b3ec61Sdh155122 	ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
201f4b3ec61Sdh155122 
202f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
203f4b3ec61Sdh155122 	/*
204f4b3ec61Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
205f4b3ec61Sdh155122 	 * Set SHUTDOWN_NEEDED and DESTROY_NEEDED for each of those.
206f4b3ec61Sdh155122 	 */
207f4b3ec61Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
208f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
209f4b3ec61Sdh155122 		if (ns_reg[moduleid].nr_shutdown != NULL &&
210f4b3ec61Sdh155122 		    (ns->netstack_m_state[moduleid] & NSS_CREATE_COMPLETED) &&
211f4b3ec61Sdh155122 		    (ns->netstack_m_state[moduleid] & NSS_SHUTDOWN_ALL) == 0) {
212f4b3ec61Sdh155122 			ns->netstack_m_state[moduleid] |= NSS_SHUTDOWN_NEEDED;
213f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__shutdown__needed,
214f4b3ec61Sdh155122 			    netstack_t *, ns, int, moduleid);
215f4b3ec61Sdh155122 		}
216f4b3ec61Sdh155122 		if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) &&
217f4b3ec61Sdh155122 		    ns_reg[moduleid].nr_destroy != NULL &&
218f4b3ec61Sdh155122 		    (ns->netstack_m_state[moduleid] & NSS_CREATE_COMPLETED) &&
219f4b3ec61Sdh155122 		    (ns->netstack_m_state[moduleid] & NSS_DESTROY_ALL) == 0) {
220f4b3ec61Sdh155122 			ns->netstack_m_state[moduleid] |= NSS_DESTROY_NEEDED;
221f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__destroy__needed,
222f4b3ec61Sdh155122 			    netstack_t *, ns, int, moduleid);
223f4b3ec61Sdh155122 		}
224f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
225f4b3ec61Sdh155122 	}
226f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
227f4b3ec61Sdh155122 
228f4b3ec61Sdh155122 	netstack_do_shutdown();
229f4b3ec61Sdh155122 	netstack_do_destroy();
230f4b3ec61Sdh155122 
231f4b3ec61Sdh155122 	/*
232f4b3ec61Sdh155122 	 * Clear the netstack_m_state so that we can handle this module
233f4b3ec61Sdh155122 	 * being loaded again.
234f4b3ec61Sdh155122 	 */
235f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
236f4b3ec61Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
237f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
238f4b3ec61Sdh155122 		if (ns->netstack_m_state[moduleid] & NSS_DESTROY_COMPLETED) {
239f4b3ec61Sdh155122 			ns->netstack_m_state[moduleid] = 0;
240f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__destroy__done,
241f4b3ec61Sdh155122 			    netstack_t *, ns, int, moduleid);
242f4b3ec61Sdh155122 		}
243f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
244f4b3ec61Sdh155122 	}
245f4b3ec61Sdh155122 
246f4b3ec61Sdh155122 	ns_reg[moduleid].nr_create = NULL;
247f4b3ec61Sdh155122 	ns_reg[moduleid].nr_shutdown = NULL;
248f4b3ec61Sdh155122 	ns_reg[moduleid].nr_destroy = NULL;
249f4b3ec61Sdh155122 	ns_reg[moduleid].nr_flags = 0;
250f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
251f4b3ec61Sdh155122 }
252f4b3ec61Sdh155122 
253f4b3ec61Sdh155122 /*
254f4b3ec61Sdh155122  * Lookup and/or allocate a netstack for this zone.
255f4b3ec61Sdh155122  */
256f4b3ec61Sdh155122 static void *
257f4b3ec61Sdh155122 netstack_zone_create(zoneid_t zoneid)
258f4b3ec61Sdh155122 {
259f4b3ec61Sdh155122 	netstackid_t stackid;
260f4b3ec61Sdh155122 	netstack_t *ns;
261f4b3ec61Sdh155122 	netstack_t **nsp;
262f4b3ec61Sdh155122 	zone_t	*zone;
263f4b3ec61Sdh155122 	int i;
264f4b3ec61Sdh155122 
265f4b3ec61Sdh155122 	ASSERT(netstack_initialized);
266f4b3ec61Sdh155122 
267f4b3ec61Sdh155122 	zone = zone_find_by_id_nolock(zoneid);
268f4b3ec61Sdh155122 	ASSERT(zone != NULL);
269f4b3ec61Sdh155122 
270f4b3ec61Sdh155122 	if (zone->zone_flags & ZF_NET_EXCL) {
271f4b3ec61Sdh155122 		stackid = zoneid;
272f4b3ec61Sdh155122 	} else {
273f4b3ec61Sdh155122 		/* Look for the stack instance for the global */
274f4b3ec61Sdh155122 		stackid = GLOBAL_NETSTACKID;
275f4b3ec61Sdh155122 	}
276f4b3ec61Sdh155122 
277f4b3ec61Sdh155122 	/* Allocate even if it isn't needed; simplifies locking */
278f4b3ec61Sdh155122 	ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP);
279f4b3ec61Sdh155122 
280f4b3ec61Sdh155122 	/* Look if there is a matching stack instance */
281f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
282f4b3ec61Sdh155122 	for (nsp = &netstack_head; *nsp != NULL;
283f4b3ec61Sdh155122 	    nsp = &((*nsp)->netstack_next)) {
284f4b3ec61Sdh155122 		if ((*nsp)->netstack_stackid == stackid) {
285f4b3ec61Sdh155122 			/*
286f4b3ec61Sdh155122 			 * Should never find a pre-existing exclusive stack
287f4b3ec61Sdh155122 			 */
288f4b3ec61Sdh155122 			ASSERT(stackid == GLOBAL_NETSTACKID);
289f4b3ec61Sdh155122 			kmem_free(ns, sizeof (netstack_t));
290f4b3ec61Sdh155122 			ns = *nsp;
291f4b3ec61Sdh155122 			mutex_enter(&ns->netstack_lock);
292f4b3ec61Sdh155122 			ns->netstack_numzones++;
293f4b3ec61Sdh155122 			mutex_exit(&ns->netstack_lock);
294f4b3ec61Sdh155122 			mutex_exit(&netstack_g_lock);
295f4b3ec61Sdh155122 			DTRACE_PROBE1(netstack__inc__numzones,
296f4b3ec61Sdh155122 			    netstack_t *, ns);
297f4b3ec61Sdh155122 			/* Record that we have a new shared stack zone */
298f4b3ec61Sdh155122 			netstack_shared_zone_add(zoneid);
299f4b3ec61Sdh155122 			zone->zone_netstack = ns;
300f4b3ec61Sdh155122 			return (ns);
301f4b3ec61Sdh155122 		}
302f4b3ec61Sdh155122 	}
303f4b3ec61Sdh155122 	/* Not found */
304f4b3ec61Sdh155122 	mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL);
305f4b3ec61Sdh155122 	ns->netstack_stackid = zoneid;
306f4b3ec61Sdh155122 	ns->netstack_numzones = 1;
307f4b3ec61Sdh155122 	ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */
308f4b3ec61Sdh155122 	ns->netstack_flags = NSF_UNINIT;
309f4b3ec61Sdh155122 	*nsp = ns;
310f4b3ec61Sdh155122 	zone->zone_netstack = ns;
311f4b3ec61Sdh155122 
312f4b3ec61Sdh155122 	/*
313f4b3ec61Sdh155122 	 * Determine the set of module create functions that need to be
314f4b3ec61Sdh155122 	 * called before we drop the lock.
315f4b3ec61Sdh155122 	 */
316f4b3ec61Sdh155122 	for (i = 0; i < NS_MAX; i++) {
317f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
318f4b3ec61Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
319f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_CREATE_ALL) == 0) {
320f4b3ec61Sdh155122 			ns->netstack_m_state[i] |= NSS_CREATE_NEEDED;
321f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__create__needed,
322f4b3ec61Sdh155122 			    netstack_t *, ns, int, i);
323f4b3ec61Sdh155122 		}
324f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
325f4b3ec61Sdh155122 	}
326f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
327f4b3ec61Sdh155122 
328f4b3ec61Sdh155122 	netstack_do_create();
329f4b3ec61Sdh155122 
330f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
331f4b3ec61Sdh155122 	ns->netstack_flags &= ~NSF_UNINIT;
332f4b3ec61Sdh155122 	mutex_exit(&ns->netstack_lock);
333f4b3ec61Sdh155122 
334f4b3ec61Sdh155122 	return (ns);
335f4b3ec61Sdh155122 }
336f4b3ec61Sdh155122 
337f4b3ec61Sdh155122 /* ARGSUSED */
338f4b3ec61Sdh155122 static void
339f4b3ec61Sdh155122 netstack_zone_shutdown(zoneid_t zoneid, void *arg)
340f4b3ec61Sdh155122 {
341f4b3ec61Sdh155122 	netstack_t *ns = (netstack_t *)arg;
342f4b3ec61Sdh155122 	int i;
343f4b3ec61Sdh155122 
344f4b3ec61Sdh155122 	ASSERT(arg != NULL);
345f4b3ec61Sdh155122 
346f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
347f4b3ec61Sdh155122 	ASSERT(ns->netstack_numzones > 0);
348f4b3ec61Sdh155122 	if (ns->netstack_numzones != 1) {
349f4b3ec61Sdh155122 		/* Stack instance being used by other zone */
350f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
351f4b3ec61Sdh155122 		ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
352f4b3ec61Sdh155122 		return;
353f4b3ec61Sdh155122 	}
354f4b3ec61Sdh155122 	mutex_exit(&ns->netstack_lock);
355f4b3ec61Sdh155122 
356f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
357f4b3ec61Sdh155122 	/*
358f4b3ec61Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
359f4b3ec61Sdh155122 	 * Set SHUTDOWN_NEEDED for each of those.
360f4b3ec61Sdh155122 	 */
361f4b3ec61Sdh155122 	for (i = 0; i < NS_MAX; i++) {
362f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
363f4b3ec61Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
364f4b3ec61Sdh155122 		    ns_reg[i].nr_shutdown != NULL &&
365f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_CREATE_COMPLETED) &&
366f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_SHUTDOWN_ALL) == 0) {
367f4b3ec61Sdh155122 			ns->netstack_m_state[i] |= NSS_SHUTDOWN_NEEDED;
368f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__shutdown__needed,
369f4b3ec61Sdh155122 			    netstack_t *, ns, int, i);
370f4b3ec61Sdh155122 		}
371f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
372f4b3ec61Sdh155122 	}
373f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
374f4b3ec61Sdh155122 
375f4b3ec61Sdh155122 	/* Call the shutdown function for all registered modules */
376f4b3ec61Sdh155122 	netstack_do_shutdown();
377f4b3ec61Sdh155122 }
378f4b3ec61Sdh155122 
379f4b3ec61Sdh155122 /*
380f4b3ec61Sdh155122  * Common routine to release a zone.
381f4b3ec61Sdh155122  * If this was the last zone using the stack instance then prepare to
382f4b3ec61Sdh155122  * have the refcnt dropping to zero free the zone.
383f4b3ec61Sdh155122  */
384f4b3ec61Sdh155122 /* ARGSUSED */
385f4b3ec61Sdh155122 static void
386f4b3ec61Sdh155122 netstack_zone_destroy(zoneid_t zoneid, void *arg)
387f4b3ec61Sdh155122 {
388f4b3ec61Sdh155122 	netstack_t *ns = (netstack_t *)arg;
389f4b3ec61Sdh155122 
390f4b3ec61Sdh155122 	ASSERT(arg != NULL);
391f4b3ec61Sdh155122 
392f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
393f4b3ec61Sdh155122 	ASSERT(ns->netstack_numzones > 0);
394f4b3ec61Sdh155122 	ns->netstack_numzones--;
395f4b3ec61Sdh155122 	if (ns->netstack_numzones != 0) {
396f4b3ec61Sdh155122 		/* Stack instance being used by other zone */
397f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
398f4b3ec61Sdh155122 		ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
399f4b3ec61Sdh155122 		/* Record that we a shared stack zone has gone away */
400f4b3ec61Sdh155122 		netstack_shared_zone_remove(zoneid);
401f4b3ec61Sdh155122 		return;
402f4b3ec61Sdh155122 	}
403f4b3ec61Sdh155122 	/*
404f4b3ec61Sdh155122 	 * Set CLOSING so that netstack_find_by will not find it
405f4b3ec61Sdh155122 	 * and decrement the reference count.
406f4b3ec61Sdh155122 	 */
407f4b3ec61Sdh155122 	ns->netstack_flags |= NSF_CLOSING;
408f4b3ec61Sdh155122 	mutex_exit(&ns->netstack_lock);
409f4b3ec61Sdh155122 	DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns);
410f4b3ec61Sdh155122 	/* No other thread can call zone_destroy for this stack */
411f4b3ec61Sdh155122 
412f4b3ec61Sdh155122 	/*
413f4b3ec61Sdh155122 	 * Decrease refcnt to account for the one in netstack_zone_init()
414f4b3ec61Sdh155122 	 */
415f4b3ec61Sdh155122 	netstack_rele(ns);
416f4b3ec61Sdh155122 }
417f4b3ec61Sdh155122 
418f4b3ec61Sdh155122 /*
419f4b3ec61Sdh155122  * Called when the reference count drops to zero.
420f4b3ec61Sdh155122  * Call the destroy functions for each registered module.
421f4b3ec61Sdh155122  */
422f4b3ec61Sdh155122 static void
423f4b3ec61Sdh155122 netstack_stack_inactive(netstack_t *ns)
424f4b3ec61Sdh155122 {
425f4b3ec61Sdh155122 	int i;
426f4b3ec61Sdh155122 
427f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
428f4b3ec61Sdh155122 	/*
429f4b3ec61Sdh155122 	 * If the shutdown callback wasn't called earlier (e.g., if this is
430f4b3ec61Sdh155122 	 * a netstack shared between multiple zones), then we call it now.
431f4b3ec61Sdh155122 	 */
432f4b3ec61Sdh155122 	for (i = 0; i < NS_MAX; i++) {
433f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
434f4b3ec61Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
435f4b3ec61Sdh155122 		    ns_reg[i].nr_shutdown != NULL &&
436f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_CREATE_COMPLETED) &&
437f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_SHUTDOWN_ALL) == 0) {
438f4b3ec61Sdh155122 			ns->netstack_m_state[i] |= NSS_SHUTDOWN_NEEDED;
439f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__shutdown__needed,
440f4b3ec61Sdh155122 			    netstack_t *, ns, int, i);
441f4b3ec61Sdh155122 		}
442f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
443f4b3ec61Sdh155122 	}
444f4b3ec61Sdh155122 	/*
445f4b3ec61Sdh155122 	 * Determine the set of stacks that exist before we drop the lock.
446f4b3ec61Sdh155122 	 * Set DESTROY_NEEDED for each of those.
447f4b3ec61Sdh155122 	 */
448f4b3ec61Sdh155122 	for (i = 0; i < NS_MAX; i++) {
449f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
450f4b3ec61Sdh155122 		if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
451f4b3ec61Sdh155122 		    ns_reg[i].nr_destroy != NULL &&
452f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_CREATE_COMPLETED) &&
453f4b3ec61Sdh155122 		    (ns->netstack_m_state[i] & NSS_DESTROY_ALL) == 0) {
454f4b3ec61Sdh155122 			ns->netstack_m_state[i] |= NSS_DESTROY_NEEDED;
455f4b3ec61Sdh155122 			DTRACE_PROBE2(netstack__destroy__needed,
456f4b3ec61Sdh155122 			    netstack_t *, ns, int, i);
457f4b3ec61Sdh155122 		}
458f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
459f4b3ec61Sdh155122 	}
460f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
461f4b3ec61Sdh155122 
462f4b3ec61Sdh155122 	netstack_do_shutdown();
463f4b3ec61Sdh155122 	netstack_do_destroy();
464f4b3ec61Sdh155122 }
465f4b3ec61Sdh155122 
466f4b3ec61Sdh155122 /*
467f4b3ec61Sdh155122  * Call the create function for the ns and moduleid if CREATE_NEEDED
468f4b3ec61Sdh155122  * is set.
469f4b3ec61Sdh155122  * When it calls it, it drops the netstack_lock held by the caller,
470f4b3ec61Sdh155122  * and returns true to tell the caller it needs to re-evalute the
471f4b3ec61Sdh155122  * state..
472f4b3ec61Sdh155122  */
473f4b3ec61Sdh155122 static boolean_t
474f4b3ec61Sdh155122 netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid)
475f4b3ec61Sdh155122 {
476f4b3ec61Sdh155122 	void *result;
477f4b3ec61Sdh155122 	netstackid_t stackid;
478f4b3ec61Sdh155122 
479f4b3ec61Sdh155122 	ASSERT(MUTEX_HELD(lockp));
480f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
481f4b3ec61Sdh155122 	if (ns->netstack_m_state[moduleid] & NSS_CREATE_NEEDED) {
482f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] &= ~NSS_CREATE_NEEDED;
483f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] |= NSS_CREATE_INPROGRESS;
484f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__create__inprogress,
485f4b3ec61Sdh155122 		    netstack_t *, ns, int, moduleid);
486f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
487f4b3ec61Sdh155122 		mutex_exit(lockp);
488f4b3ec61Sdh155122 
489f4b3ec61Sdh155122 		ASSERT(ns_reg[moduleid].nr_create != NULL);
490f4b3ec61Sdh155122 		stackid = ns->netstack_stackid;
491f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__create__start,
492f4b3ec61Sdh155122 		    netstackid_t, stackid,
493f4b3ec61Sdh155122 		    netstack_t *, ns);
494f4b3ec61Sdh155122 		result = (ns_reg[moduleid].nr_create)(stackid, ns);
495f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__create__end,
496f4b3ec61Sdh155122 		    void *, result, netstack_t *, ns);
497f4b3ec61Sdh155122 
498f4b3ec61Sdh155122 		ASSERT(result != NULL);
499f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
500f4b3ec61Sdh155122 		ns->netstack_modules[moduleid] = result;
501f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] &= ~NSS_CREATE_INPROGRESS;
502f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] |= NSS_CREATE_COMPLETED;
503f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__create__completed,
504f4b3ec61Sdh155122 		    netstack_t *, ns, int, moduleid);
505f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
506f4b3ec61Sdh155122 		return (B_TRUE);
507f4b3ec61Sdh155122 	} else {
508f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
509f4b3ec61Sdh155122 		return (B_FALSE);
510f4b3ec61Sdh155122 	}
511f4b3ec61Sdh155122 }
512f4b3ec61Sdh155122 
513f4b3ec61Sdh155122 /*
514f4b3ec61Sdh155122  * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED
515f4b3ec61Sdh155122  * is set.
516f4b3ec61Sdh155122  * When it calls it, it drops the netstack_lock held by the caller,
517f4b3ec61Sdh155122  * and returns true to tell the caller it needs to re-evalute the
518f4b3ec61Sdh155122  * state..
519f4b3ec61Sdh155122  */
520f4b3ec61Sdh155122 static boolean_t
521f4b3ec61Sdh155122 netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid)
522f4b3ec61Sdh155122 {
523f4b3ec61Sdh155122 	netstackid_t stackid;
524f4b3ec61Sdh155122 	void * netstack_module;
525f4b3ec61Sdh155122 
526f4b3ec61Sdh155122 	ASSERT(MUTEX_HELD(lockp));
527f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
528f4b3ec61Sdh155122 	if (ns->netstack_m_state[moduleid] & NSS_SHUTDOWN_NEEDED) {
529f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] &= ~NSS_SHUTDOWN_NEEDED;
530f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] |= NSS_SHUTDOWN_INPROGRESS;
531f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__shutdown__inprogress,
532f4b3ec61Sdh155122 		    netstack_t *, ns, int, moduleid);
533f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
534f4b3ec61Sdh155122 		mutex_exit(lockp);
535f4b3ec61Sdh155122 
536f4b3ec61Sdh155122 		ASSERT(ns_reg[moduleid].nr_shutdown != NULL);
537f4b3ec61Sdh155122 		stackid = ns->netstack_stackid;
538f4b3ec61Sdh155122 		netstack_module = ns->netstack_modules[moduleid];
539f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__shutdown__start,
540f4b3ec61Sdh155122 		    netstackid_t, stackid,
541f4b3ec61Sdh155122 		    void *, netstack_module);
542f4b3ec61Sdh155122 		(ns_reg[moduleid].nr_shutdown)(stackid, netstack_module);
543f4b3ec61Sdh155122 		DTRACE_PROBE1(netstack__shutdown__end,
544f4b3ec61Sdh155122 		    netstack_t *, ns);
545f4b3ec61Sdh155122 
546f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
547f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] &= ~NSS_SHUTDOWN_INPROGRESS;
548f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] |= NSS_SHUTDOWN_COMPLETED;
549f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__shutdown__completed,
550f4b3ec61Sdh155122 		    netstack_t *, ns, int, moduleid);
551f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
552f4b3ec61Sdh155122 		return (B_TRUE);
553f4b3ec61Sdh155122 	} else {
554f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
555f4b3ec61Sdh155122 		return (B_FALSE);
556f4b3ec61Sdh155122 	}
557f4b3ec61Sdh155122 }
558f4b3ec61Sdh155122 
559f4b3ec61Sdh155122 /*
560f4b3ec61Sdh155122  * Call the destroy function for the ns and moduleid if DESTROY_NEEDED
561f4b3ec61Sdh155122  * is set.
562f4b3ec61Sdh155122  * When it calls it, it drops the netstack_lock held by the caller,
563f4b3ec61Sdh155122  * and returns true to tell the caller it needs to re-evalute the
564f4b3ec61Sdh155122  * state..
565f4b3ec61Sdh155122  */
566f4b3ec61Sdh155122 static boolean_t
567f4b3ec61Sdh155122 netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid)
568f4b3ec61Sdh155122 {
569f4b3ec61Sdh155122 	netstackid_t stackid;
570f4b3ec61Sdh155122 	void * netstack_module;
571f4b3ec61Sdh155122 
572f4b3ec61Sdh155122 	ASSERT(MUTEX_HELD(lockp));
573f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
574f4b3ec61Sdh155122 	if (ns->netstack_m_state[moduleid] & NSS_DESTROY_NEEDED) {
575f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] &= ~NSS_DESTROY_NEEDED;
576f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] |= NSS_DESTROY_INPROGRESS;
577f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__destroy__inprogress,
578f4b3ec61Sdh155122 		    netstack_t *, ns, int, moduleid);
579f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
580f4b3ec61Sdh155122 		mutex_exit(lockp);
581f4b3ec61Sdh155122 
582f4b3ec61Sdh155122 		/* XXX race against unregister? */
583f4b3ec61Sdh155122 		ASSERT(ns_reg[moduleid].nr_destroy != NULL);
584f4b3ec61Sdh155122 		stackid = ns->netstack_stackid;
585f4b3ec61Sdh155122 		netstack_module = ns->netstack_modules[moduleid];
586f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__destroy__start,
587f4b3ec61Sdh155122 		    netstackid_t, stackid,
588f4b3ec61Sdh155122 		    void *, netstack_module);
589f4b3ec61Sdh155122 		(ns_reg[moduleid].nr_destroy)(stackid, netstack_module);
590f4b3ec61Sdh155122 		DTRACE_PROBE1(netstack__destroy__end,
591f4b3ec61Sdh155122 		    netstack_t *, ns);
592f4b3ec61Sdh155122 
593f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
594f4b3ec61Sdh155122 		ns->netstack_modules[moduleid] = NULL;
595f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] &= ~NSS_DESTROY_INPROGRESS;
596f4b3ec61Sdh155122 		ns->netstack_m_state[moduleid] |= NSS_DESTROY_COMPLETED;
597f4b3ec61Sdh155122 		DTRACE_PROBE2(netstack__destroy__completed,
598f4b3ec61Sdh155122 		    netstack_t *, ns, int, moduleid);
599f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
600f4b3ec61Sdh155122 		return (B_TRUE);
601f4b3ec61Sdh155122 	} else {
602f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
603f4b3ec61Sdh155122 		return (B_FALSE);
604f4b3ec61Sdh155122 	}
605f4b3ec61Sdh155122 }
606f4b3ec61Sdh155122 
607f4b3ec61Sdh155122 static void
608f4b3ec61Sdh155122 apply_loop(netstack_t **headp, kmutex_t *lockp,
609f4b3ec61Sdh155122     boolean_t (*applyfn)(kmutex_t *, netstack_t *, int moduleid))
610f4b3ec61Sdh155122 {
611f4b3ec61Sdh155122 	netstack_t *ns;
612f4b3ec61Sdh155122 	int i;
613f4b3ec61Sdh155122 	boolean_t lock_dropped, result;
614f4b3ec61Sdh155122 
615f4b3ec61Sdh155122 	lock_dropped = B_FALSE;
616f4b3ec61Sdh155122 	ns = *headp;
617f4b3ec61Sdh155122 	while (ns != NULL) {
618f4b3ec61Sdh155122 		for (i = 0; i < NS_MAX; i++) {
619f4b3ec61Sdh155122 			result = (applyfn)(lockp, ns, i);
620f4b3ec61Sdh155122 			if (result) {
621f4b3ec61Sdh155122 #ifdef NS_DEBUG
622f4b3ec61Sdh155122 				(void) printf("netstack_do_apply: "
623f4b3ec61Sdh155122 				    "LD for %p/%d, %d\n",
624f4b3ec61Sdh155122 				    (void *)ns, ns->netstack_stackid, i);
625f4b3ec61Sdh155122 #endif
626f4b3ec61Sdh155122 				lock_dropped = B_TRUE;
627f4b3ec61Sdh155122 				mutex_enter(lockp);
628f4b3ec61Sdh155122 			}
629f4b3ec61Sdh155122 		}
630f4b3ec61Sdh155122 		/*
631f4b3ec61Sdh155122 		 * If at least one applyfn call caused lockp to be dropped,
632f4b3ec61Sdh155122 		 * then we don't follow netstack_next after reacquiring the
633f4b3ec61Sdh155122 		 * lock, even if it is possible to do so without any hazards.
634f4b3ec61Sdh155122 		 * This is because we want the design to allow for the list of
635f4b3ec61Sdh155122 		 * netstacks threaded by netstack_next to change in any
636f4b3ec61Sdh155122 		 * arbitrary way during the time the 'lockp' was dropped.
637f4b3ec61Sdh155122 		 *
638f4b3ec61Sdh155122 		 * It is safe to restart the loop at *headp since
639f4b3ec61Sdh155122 		 * the applyfn changes netstack_m_state as it processes
640f4b3ec61Sdh155122 		 * things, so a subsequent pass through will have no
641f4b3ec61Sdh155122 		 * effect in applyfn, hence the loop will terminate
642f4b3ec61Sdh155122 		 * in at worst O(N^2).
643f4b3ec61Sdh155122 		 */
644f4b3ec61Sdh155122 		if (lock_dropped) {
645f4b3ec61Sdh155122 #ifdef NS_DEBUG
646f4b3ec61Sdh155122 			(void) printf("netstack_do_apply: "
647f4b3ec61Sdh155122 			    "Lock Dropped for %p/%d, %d\n",
648f4b3ec61Sdh155122 			    (void *)ns, ns->netstack_stackid, i);
649f4b3ec61Sdh155122 #endif
650f4b3ec61Sdh155122 			lock_dropped = B_FALSE;
651f4b3ec61Sdh155122 			ns = *headp;
652f4b3ec61Sdh155122 		} else {
653f4b3ec61Sdh155122 			ns = ns->netstack_next;
654f4b3ec61Sdh155122 		}
655f4b3ec61Sdh155122 	}
656f4b3ec61Sdh155122 }
657f4b3ec61Sdh155122 
658f4b3ec61Sdh155122 /* Like above, but in the reverse order of moduleids */
659f4b3ec61Sdh155122 static void
660f4b3ec61Sdh155122 apply_loop_reverse(netstack_t **headp, kmutex_t *lockp,
661f4b3ec61Sdh155122     boolean_t (*applyfn)(kmutex_t *, netstack_t *, int moduleid))
662f4b3ec61Sdh155122 {
663f4b3ec61Sdh155122 	netstack_t *ns;
664f4b3ec61Sdh155122 	int i;
665f4b3ec61Sdh155122 	boolean_t lock_dropped, result;
666f4b3ec61Sdh155122 
667f4b3ec61Sdh155122 	lock_dropped = B_FALSE;
668f4b3ec61Sdh155122 	ns = *headp;
669f4b3ec61Sdh155122 	while (ns != NULL) {
670f4b3ec61Sdh155122 		for (i = NS_MAX-1; i >= 0; i--) {
671f4b3ec61Sdh155122 			result = (applyfn)(lockp, ns, i);
672f4b3ec61Sdh155122 			if (result) {
673f4b3ec61Sdh155122 #ifdef NS_DEBUG
674f4b3ec61Sdh155122 				(void) printf("netstack_do_apply: "
675f4b3ec61Sdh155122 				    "LD for %p/%d, %d\n",
676f4b3ec61Sdh155122 				    (void *)ns, ns->netstack_stackid, i);
677f4b3ec61Sdh155122 #endif
678f4b3ec61Sdh155122 				lock_dropped = B_TRUE;
679f4b3ec61Sdh155122 				mutex_enter(lockp);
680f4b3ec61Sdh155122 			}
681f4b3ec61Sdh155122 		}
682f4b3ec61Sdh155122 		/*
683f4b3ec61Sdh155122 		 * If at least one applyfn call caused lockp to be dropped,
684f4b3ec61Sdh155122 		 * then we don't follow netstack_next after reacquiring the
685f4b3ec61Sdh155122 		 * lock, even if it is possible to do so without any hazards.
686f4b3ec61Sdh155122 		 * This is because we want the design to allow for the list of
687f4b3ec61Sdh155122 		 * netstacks threaded by netstack_next to change in any
688f4b3ec61Sdh155122 		 * arbitrary way during the time the 'lockp' was dropped.
689f4b3ec61Sdh155122 		 *
690f4b3ec61Sdh155122 		 * It is safe to restart the loop at *headp since
691f4b3ec61Sdh155122 		 * the applyfn changes netstack_m_state as it processes
692f4b3ec61Sdh155122 		 * things, so a subsequent pass through will have no
693f4b3ec61Sdh155122 		 * effect in applyfn, hence the loop will terminate
694f4b3ec61Sdh155122 		 * in at worst O(N^2).
695f4b3ec61Sdh155122 		 */
696f4b3ec61Sdh155122 		if (lock_dropped) {
697f4b3ec61Sdh155122 #ifdef NS_DEBUG
698f4b3ec61Sdh155122 			(void) printf("netstack_do_apply: "
699f4b3ec61Sdh155122 			    "Lock Dropped for %p/%d, %d\n",
700f4b3ec61Sdh155122 			    (void *)ns, ns->netstack_stackid, i);
701f4b3ec61Sdh155122 #endif
702f4b3ec61Sdh155122 			lock_dropped = B_FALSE;
703f4b3ec61Sdh155122 			ns = *headp;
704f4b3ec61Sdh155122 		} else {
705f4b3ec61Sdh155122 			ns = ns->netstack_next;
706f4b3ec61Sdh155122 		}
707f4b3ec61Sdh155122 	}
708f4b3ec61Sdh155122 }
709f4b3ec61Sdh155122 
710f4b3ec61Sdh155122 /*
711f4b3ec61Sdh155122  * Apply a function to all module/netstack combinations.
712f4b3ec61Sdh155122  * The applyfn returns true if it had dropped the locks.
713f4b3ec61Sdh155122  */
714f4b3ec61Sdh155122 static void
715f4b3ec61Sdh155122 netstack_do_apply(int reverse,
716f4b3ec61Sdh155122     boolean_t (*applyfn)(kmutex_t *, netstack_t *, int moduleid))
717f4b3ec61Sdh155122 {
718f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
719f4b3ec61Sdh155122 	if (reverse)
720f4b3ec61Sdh155122 		apply_loop_reverse(&netstack_head, &netstack_g_lock, applyfn);
721f4b3ec61Sdh155122 	else
722f4b3ec61Sdh155122 		apply_loop(&netstack_head, &netstack_g_lock, applyfn);
723f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
724f4b3ec61Sdh155122 }
725f4b3ec61Sdh155122 
726f4b3ec61Sdh155122 /*
727f4b3ec61Sdh155122  * Run the create function for all modules x stack combinations
728f4b3ec61Sdh155122  * that have NSS_CREATE_NEEDED set.
729f4b3ec61Sdh155122  *
730f4b3ec61Sdh155122  * Call the create function for each stack that has CREATE_NEEDED.
731f4b3ec61Sdh155122  * Set CREATE_INPROGRESS, drop lock, and after done,
732f4b3ec61Sdh155122  * set CREATE_COMPLETE
733f4b3ec61Sdh155122  */
734f4b3ec61Sdh155122 static void
735f4b3ec61Sdh155122 netstack_do_create(void)
736f4b3ec61Sdh155122 {
737f4b3ec61Sdh155122 	netstack_do_apply(B_FALSE, netstack_apply_create);
738f4b3ec61Sdh155122 }
739f4b3ec61Sdh155122 
740f4b3ec61Sdh155122 /*
741f4b3ec61Sdh155122  * Run the shutdown function for all modules x stack combinations
742f4b3ec61Sdh155122  * that have NSS_SHUTDOWN_NEEDED set.
743f4b3ec61Sdh155122  *
744f4b3ec61Sdh155122  * Call the shutdown function for each stack that has SHUTDOWN_NEEDED.
745f4b3ec61Sdh155122  * Set SHUTDOWN_INPROGRESS, drop lock, and after done,
746f4b3ec61Sdh155122  * set SHUTDOWN_COMPLETE
747f4b3ec61Sdh155122  */
748f4b3ec61Sdh155122 static void
749f4b3ec61Sdh155122 netstack_do_shutdown(void)
750f4b3ec61Sdh155122 {
751f4b3ec61Sdh155122 	netstack_do_apply(B_FALSE, netstack_apply_shutdown);
752f4b3ec61Sdh155122 }
753f4b3ec61Sdh155122 
754f4b3ec61Sdh155122 /*
755f4b3ec61Sdh155122  * Run the destroy function for all modules x stack combinations
756f4b3ec61Sdh155122  * that have NSS_DESTROY_NEEDED set.
757f4b3ec61Sdh155122  *
758f4b3ec61Sdh155122  * Call the destroy function for each stack that has DESTROY_NEEDED.
759f4b3ec61Sdh155122  * Set DESTROY_INPROGRESS, drop lock, and after done,
760f4b3ec61Sdh155122  * set DESTROY_COMPLETE
761f4b3ec61Sdh155122  *
762f4b3ec61Sdh155122  * Since a netstack_t is never reused (when a zone is rebooted it gets
763f4b3ec61Sdh155122  * a new zoneid == netstackid i.e. a new netstack_t is allocated) we leave
764f4b3ec61Sdh155122  * netstack_m_state the way it is i.e. with NSS_DESTROY_COMPLETED set.
765f4b3ec61Sdh155122  */
766f4b3ec61Sdh155122 static void
767f4b3ec61Sdh155122 netstack_do_destroy(void)
768f4b3ec61Sdh155122 {
769f4b3ec61Sdh155122 	/*
770f4b3ec61Sdh155122 	 * Have to walk the moduleids in reverse order since some
771f4b3ec61Sdh155122 	 * modules make implicit assumptions about the order
772f4b3ec61Sdh155122 	 */
773f4b3ec61Sdh155122 	netstack_do_apply(B_TRUE, netstack_apply_destroy);
774f4b3ec61Sdh155122 }
775f4b3ec61Sdh155122 
776f4b3ec61Sdh155122 /*
777f4b3ec61Sdh155122  * Get the stack instance used in caller's zone.
778f4b3ec61Sdh155122  * Increases the reference count, caller must do a netstack_rele.
779f4b3ec61Sdh155122  * It can't be called after zone_destroy() has started.
780f4b3ec61Sdh155122  */
781*fd006805Snordmark netstack_t *
782f4b3ec61Sdh155122 netstack_get_current(void)
783f4b3ec61Sdh155122 {
784f4b3ec61Sdh155122 	netstack_t *ns;
785f4b3ec61Sdh155122 
786f4b3ec61Sdh155122 	ns = curproc->p_zone->zone_netstack;
787f4b3ec61Sdh155122 	ASSERT(ns != NULL);
788f4b3ec61Sdh155122 	if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
789f4b3ec61Sdh155122 		return (NULL);
790f4b3ec61Sdh155122 
791f4b3ec61Sdh155122 	netstack_hold(ns);
792f4b3ec61Sdh155122 
793f4b3ec61Sdh155122 	return (ns);
794f4b3ec61Sdh155122 }
795f4b3ec61Sdh155122 
796f4b3ec61Sdh155122 /*
797f4b3ec61Sdh155122  * Find a stack instance given the cred.
798f4b3ec61Sdh155122  * This is used by the modules to potentially allow for a future when
799f4b3ec61Sdh155122  * something other than the zoneid is used to determine the stack.
800f4b3ec61Sdh155122  */
801f4b3ec61Sdh155122 netstack_t *
802f4b3ec61Sdh155122 netstack_find_by_cred(const cred_t *cr)
803f4b3ec61Sdh155122 {
804f4b3ec61Sdh155122 	zoneid_t zoneid = crgetzoneid(cr);
805f4b3ec61Sdh155122 
806f4b3ec61Sdh155122 	/* Handle the case when cr_zone is NULL */
807f4b3ec61Sdh155122 	if (zoneid == (zoneid_t)-1)
808f4b3ec61Sdh155122 		zoneid = GLOBAL_ZONEID;
809f4b3ec61Sdh155122 
810f4b3ec61Sdh155122 	/* For performance ... */
811f4b3ec61Sdh155122 	if (curproc->p_zone->zone_id == zoneid)
812f4b3ec61Sdh155122 		return (netstack_get_current());
813f4b3ec61Sdh155122 	else
814f4b3ec61Sdh155122 		return (netstack_find_by_zoneid(zoneid));
815f4b3ec61Sdh155122 }
816f4b3ec61Sdh155122 
817f4b3ec61Sdh155122 /*
818f4b3ec61Sdh155122  * Find a stack instance given the zoneid.
819f4b3ec61Sdh155122  * Increases the reference count if found; caller must do a
820f4b3ec61Sdh155122  * netstack_rele().
821f4b3ec61Sdh155122  *
822f4b3ec61Sdh155122  * If there is no exact match then assume the shared stack instance
823f4b3ec61Sdh155122  * matches.
824f4b3ec61Sdh155122  *
825f4b3ec61Sdh155122  * Skip the unitialized ones.
826f4b3ec61Sdh155122  */
827f4b3ec61Sdh155122 netstack_t *
828f4b3ec61Sdh155122 netstack_find_by_zoneid(zoneid_t zoneid)
829f4b3ec61Sdh155122 {
830f4b3ec61Sdh155122 	netstack_t *ns;
831f4b3ec61Sdh155122 	zone_t *zone;
832f4b3ec61Sdh155122 
833f4b3ec61Sdh155122 	zone = zone_find_by_id(zoneid);
834f4b3ec61Sdh155122 
835f4b3ec61Sdh155122 	if (zone == NULL)
836f4b3ec61Sdh155122 		return (NULL);
837f4b3ec61Sdh155122 
838f4b3ec61Sdh155122 	ns = zone->zone_netstack;
839f4b3ec61Sdh155122 	ASSERT(ns != NULL);
840f4b3ec61Sdh155122 	if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
841f4b3ec61Sdh155122 		ns = NULL;
842f4b3ec61Sdh155122 	else
843f4b3ec61Sdh155122 		netstack_hold(ns);
844f4b3ec61Sdh155122 
845f4b3ec61Sdh155122 	zone_rele(zone);
846f4b3ec61Sdh155122 	return (ns);
847f4b3ec61Sdh155122 }
848f4b3ec61Sdh155122 
849f4b3ec61Sdh155122 /*
850f4b3ec61Sdh155122  * Find a stack instance given the zoneid.
851f4b3ec61Sdh155122  * Increases the reference count if found; caller must do a
852f4b3ec61Sdh155122  * netstack_rele().
853f4b3ec61Sdh155122  *
854f4b3ec61Sdh155122  * If there is no exact match then assume the shared stack instance
855f4b3ec61Sdh155122  * matches.
856f4b3ec61Sdh155122  *
857f4b3ec61Sdh155122  * Skip the unitialized ones.
858f4b3ec61Sdh155122  *
859f4b3ec61Sdh155122  * NOTE: The caller must hold zonehash_lock.
860f4b3ec61Sdh155122  */
861f4b3ec61Sdh155122 netstack_t *
862f4b3ec61Sdh155122 netstack_find_by_zoneid_nolock(zoneid_t zoneid)
863f4b3ec61Sdh155122 {
864f4b3ec61Sdh155122 	netstack_t *ns;
865f4b3ec61Sdh155122 	zone_t *zone;
866f4b3ec61Sdh155122 
867f4b3ec61Sdh155122 	zone = zone_find_by_id_nolock(zoneid);
868f4b3ec61Sdh155122 
869f4b3ec61Sdh155122 	if (zone == NULL)
870f4b3ec61Sdh155122 		return (NULL);
871f4b3ec61Sdh155122 
872f4b3ec61Sdh155122 	ns = zone->zone_netstack;
873f4b3ec61Sdh155122 	ASSERT(ns != NULL);
874f4b3ec61Sdh155122 
875f4b3ec61Sdh155122 	if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
876f4b3ec61Sdh155122 		ns = NULL;
877f4b3ec61Sdh155122 	else
878f4b3ec61Sdh155122 		netstack_hold(ns);
879f4b3ec61Sdh155122 
880f4b3ec61Sdh155122 	zone_rele(zone);
881f4b3ec61Sdh155122 	return (ns);
882f4b3ec61Sdh155122 }
883f4b3ec61Sdh155122 
884f4b3ec61Sdh155122 /*
885f4b3ec61Sdh155122  * Find a stack instance given the stackid with exact match?
886f4b3ec61Sdh155122  * Increases the reference count if found; caller must do a
887f4b3ec61Sdh155122  * netstack_rele().
888f4b3ec61Sdh155122  *
889f4b3ec61Sdh155122  * Skip the unitialized ones.
890f4b3ec61Sdh155122  */
891f4b3ec61Sdh155122 netstack_t *
892f4b3ec61Sdh155122 netstack_find_by_stackid(netstackid_t stackid)
893f4b3ec61Sdh155122 {
894f4b3ec61Sdh155122 	netstack_t *ns;
895f4b3ec61Sdh155122 
896f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
897f4b3ec61Sdh155122 	for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
898f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
899f4b3ec61Sdh155122 		if (ns->netstack_stackid == stackid &&
900f4b3ec61Sdh155122 		    !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
901f4b3ec61Sdh155122 			mutex_exit(&ns->netstack_lock);
902f4b3ec61Sdh155122 			netstack_hold(ns);
903f4b3ec61Sdh155122 			mutex_exit(&netstack_g_lock);
904f4b3ec61Sdh155122 			return (ns);
905f4b3ec61Sdh155122 		}
906f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
907f4b3ec61Sdh155122 	}
908f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
909f4b3ec61Sdh155122 	return (NULL);
910f4b3ec61Sdh155122 }
911f4b3ec61Sdh155122 
912f4b3ec61Sdh155122 void
913f4b3ec61Sdh155122 netstack_rele(netstack_t *ns)
914f4b3ec61Sdh155122 {
915f4b3ec61Sdh155122 	netstack_t **nsp;
916f4b3ec61Sdh155122 	boolean_t found;
917f4b3ec61Sdh155122 	int refcnt, numzones;
918f4b3ec61Sdh155122 
919f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
920f4b3ec61Sdh155122 	ASSERT(ns->netstack_refcnt > 0);
921f4b3ec61Sdh155122 	ns->netstack_refcnt--;
922f4b3ec61Sdh155122 	/*
923f4b3ec61Sdh155122 	 * As we drop the lock additional netstack_rele()s can come in
924f4b3ec61Sdh155122 	 * and decrement the refcnt to zero and free the netstack_t.
925f4b3ec61Sdh155122 	 * Store pointers in local variables and if we were not the last
926f4b3ec61Sdh155122 	 * then don't reference the netstack_t after that.
927f4b3ec61Sdh155122 	 */
928f4b3ec61Sdh155122 	refcnt = ns->netstack_refcnt;
929f4b3ec61Sdh155122 	numzones = ns->netstack_numzones;
930f4b3ec61Sdh155122 	DTRACE_PROBE1(netstack__dec__ref, netstack_t *, ns);
931f4b3ec61Sdh155122 	mutex_exit(&ns->netstack_lock);
932f4b3ec61Sdh155122 
933f4b3ec61Sdh155122 	if (refcnt == 0 && numzones == 0) {
934f4b3ec61Sdh155122 		/*
935f4b3ec61Sdh155122 		 * Time to call the destroy functions and free up
936f4b3ec61Sdh155122 		 * the structure
937f4b3ec61Sdh155122 		 */
938f4b3ec61Sdh155122 		netstack_stack_inactive(ns);
939f4b3ec61Sdh155122 
940f4b3ec61Sdh155122 		/* Finally remove from list of netstacks */
941f4b3ec61Sdh155122 		mutex_enter(&netstack_g_lock);
942f4b3ec61Sdh155122 		found = B_FALSE;
943f4b3ec61Sdh155122 		for (nsp = &netstack_head; *nsp != NULL;
944f4b3ec61Sdh155122 		    nsp = &(*nsp)->netstack_next) {
945f4b3ec61Sdh155122 			if (*nsp == ns) {
946f4b3ec61Sdh155122 				*nsp = ns->netstack_next;
947f4b3ec61Sdh155122 				ns->netstack_next = NULL;
948f4b3ec61Sdh155122 				found = B_TRUE;
949f4b3ec61Sdh155122 				break;
950f4b3ec61Sdh155122 			}
951f4b3ec61Sdh155122 		}
952f4b3ec61Sdh155122 		ASSERT(found);
953f4b3ec61Sdh155122 		mutex_exit(&netstack_g_lock);
954f4b3ec61Sdh155122 
955f4b3ec61Sdh155122 		ASSERT(ns->netstack_flags & NSF_CLOSING);
956f4b3ec61Sdh155122 		kmem_free(ns, sizeof (*ns));
957f4b3ec61Sdh155122 	}
958f4b3ec61Sdh155122 }
959f4b3ec61Sdh155122 
960f4b3ec61Sdh155122 void
961f4b3ec61Sdh155122 netstack_hold(netstack_t *ns)
962f4b3ec61Sdh155122 {
963f4b3ec61Sdh155122 	mutex_enter(&ns->netstack_lock);
964f4b3ec61Sdh155122 	ns->netstack_refcnt++;
965f4b3ec61Sdh155122 	ASSERT(ns->netstack_refcnt > 0);
966f4b3ec61Sdh155122 	mutex_exit(&ns->netstack_lock);
967f4b3ec61Sdh155122 	DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
968f4b3ec61Sdh155122 }
969f4b3ec61Sdh155122 
970f4b3ec61Sdh155122 /*
971f4b3ec61Sdh155122  * To support kstat_create_netstack() using kstat_zone_add we need
972f4b3ec61Sdh155122  * to track both
973f4b3ec61Sdh155122  *  - all zoneids that use the global/shared stack
974f4b3ec61Sdh155122  *  - all kstats that have been added for the shared stack
975f4b3ec61Sdh155122  */
976f4b3ec61Sdh155122 kstat_t *
977f4b3ec61Sdh155122 kstat_create_netstack(char *ks_module, int ks_instance, char *ks_name,
978f4b3ec61Sdh155122     char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
979f4b3ec61Sdh155122     netstackid_t ks_netstackid)
980f4b3ec61Sdh155122 {
981f4b3ec61Sdh155122 	kstat_t *ks;
982f4b3ec61Sdh155122 
983f4b3ec61Sdh155122 	if (ks_netstackid == GLOBAL_NETSTACKID) {
984f4b3ec61Sdh155122 		ks = kstat_create_zone(ks_module, ks_instance, ks_name,
985f4b3ec61Sdh155122 		    ks_class, ks_type, ks_ndata, ks_flags, GLOBAL_ZONEID);
986f4b3ec61Sdh155122 		if (ks != NULL)
987f4b3ec61Sdh155122 			netstack_shared_kstat_add(ks);
988f4b3ec61Sdh155122 		return (ks);
989f4b3ec61Sdh155122 	} else {
990f4b3ec61Sdh155122 		zoneid_t zoneid = ks_netstackid;
991f4b3ec61Sdh155122 
992f4b3ec61Sdh155122 		return (kstat_create_zone(ks_module, ks_instance, ks_name,
993f4b3ec61Sdh155122 			ks_class, ks_type, ks_ndata, ks_flags, zoneid));
994f4b3ec61Sdh155122 	}
995f4b3ec61Sdh155122 }
996f4b3ec61Sdh155122 
997f4b3ec61Sdh155122 void
998f4b3ec61Sdh155122 kstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid)
999f4b3ec61Sdh155122 {
1000f4b3ec61Sdh155122 	if (ks_netstackid == GLOBAL_NETSTACKID) {
1001f4b3ec61Sdh155122 		netstack_shared_kstat_remove(ks);
1002f4b3ec61Sdh155122 	}
1003f4b3ec61Sdh155122 	kstat_delete(ks);
1004f4b3ec61Sdh155122 }
1005f4b3ec61Sdh155122 
1006f4b3ec61Sdh155122 static void
1007f4b3ec61Sdh155122 netstack_shared_zone_add(zoneid_t zoneid)
1008f4b3ec61Sdh155122 {
1009f4b3ec61Sdh155122 	struct shared_zone_list *sz;
1010f4b3ec61Sdh155122 	struct shared_kstat_list *sk;
1011f4b3ec61Sdh155122 
1012f4b3ec61Sdh155122 	sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP);
1013f4b3ec61Sdh155122 	sz->sz_zoneid = zoneid;
1014f4b3ec61Sdh155122 
1015f4b3ec61Sdh155122 	/* Insert in list */
1016f4b3ec61Sdh155122 	mutex_enter(&netstack_shared_lock);
1017f4b3ec61Sdh155122 	sz->sz_next = netstack_shared_zones;
1018f4b3ec61Sdh155122 	netstack_shared_zones = sz;
1019f4b3ec61Sdh155122 
1020f4b3ec61Sdh155122 	/*
1021f4b3ec61Sdh155122 	 * Perform kstat_zone_add for each existing shared stack kstat.
1022f4b3ec61Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_add.
1023f4b3ec61Sdh155122 	 */
1024f4b3ec61Sdh155122 	for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
1025f4b3ec61Sdh155122 		kstat_zone_add(sk->sk_kstat, zoneid);
1026f4b3ec61Sdh155122 	}
1027f4b3ec61Sdh155122 	mutex_exit(&netstack_shared_lock);
1028f4b3ec61Sdh155122 }
1029f4b3ec61Sdh155122 
1030f4b3ec61Sdh155122 static void
1031f4b3ec61Sdh155122 netstack_shared_zone_remove(zoneid_t zoneid)
1032f4b3ec61Sdh155122 {
1033f4b3ec61Sdh155122 	struct shared_zone_list **szp, *sz;
1034f4b3ec61Sdh155122 	struct shared_kstat_list *sk;
1035f4b3ec61Sdh155122 
1036f4b3ec61Sdh155122 	/* Find in list */
1037f4b3ec61Sdh155122 	mutex_enter(&netstack_shared_lock);
1038f4b3ec61Sdh155122 	sz = NULL;
1039f4b3ec61Sdh155122 	for (szp = &netstack_shared_zones; *szp != NULL;
1040f4b3ec61Sdh155122 	    szp = &((*szp)->sz_next)) {
1041f4b3ec61Sdh155122 		if ((*szp)->sz_zoneid == zoneid) {
1042f4b3ec61Sdh155122 			sz = *szp;
1043f4b3ec61Sdh155122 			break;
1044f4b3ec61Sdh155122 		}
1045f4b3ec61Sdh155122 	}
1046f4b3ec61Sdh155122 	/* We must find it */
1047f4b3ec61Sdh155122 	ASSERT(sz != NULL);
1048f4b3ec61Sdh155122 	*szp = sz->sz_next;
1049f4b3ec61Sdh155122 	sz->sz_next = NULL;
1050f4b3ec61Sdh155122 
1051f4b3ec61Sdh155122 	/*
1052f4b3ec61Sdh155122 	 * Perform kstat_zone_remove for each existing shared stack kstat.
1053f4b3ec61Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
1054f4b3ec61Sdh155122 	 */
1055f4b3ec61Sdh155122 	for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
1056f4b3ec61Sdh155122 		kstat_zone_remove(sk->sk_kstat, zoneid);
1057f4b3ec61Sdh155122 	}
1058f4b3ec61Sdh155122 	mutex_exit(&netstack_shared_lock);
1059f4b3ec61Sdh155122 
1060f4b3ec61Sdh155122 	kmem_free(sz, sizeof (*sz));
1061f4b3ec61Sdh155122 }
1062f4b3ec61Sdh155122 
1063f4b3ec61Sdh155122 static void
1064f4b3ec61Sdh155122 netstack_shared_kstat_add(kstat_t *ks)
1065f4b3ec61Sdh155122 {
1066f4b3ec61Sdh155122 	struct shared_zone_list *sz;
1067f4b3ec61Sdh155122 	struct shared_kstat_list *sk;
1068f4b3ec61Sdh155122 
1069f4b3ec61Sdh155122 	sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP);
1070f4b3ec61Sdh155122 	sk->sk_kstat = ks;
1071f4b3ec61Sdh155122 
1072f4b3ec61Sdh155122 	/* Insert in list */
1073f4b3ec61Sdh155122 	mutex_enter(&netstack_shared_lock);
1074f4b3ec61Sdh155122 	sk->sk_next = netstack_shared_kstats;
1075f4b3ec61Sdh155122 	netstack_shared_kstats = sk;
1076f4b3ec61Sdh155122 
1077f4b3ec61Sdh155122 	/*
1078f4b3ec61Sdh155122 	 * Perform kstat_zone_add for each existing shared stack zone.
1079f4b3ec61Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_add.
1080f4b3ec61Sdh155122 	 */
1081f4b3ec61Sdh155122 	for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
1082f4b3ec61Sdh155122 		kstat_zone_add(ks, sz->sz_zoneid);
1083f4b3ec61Sdh155122 	}
1084f4b3ec61Sdh155122 	mutex_exit(&netstack_shared_lock);
1085f4b3ec61Sdh155122 }
1086f4b3ec61Sdh155122 
1087f4b3ec61Sdh155122 static void
1088f4b3ec61Sdh155122 netstack_shared_kstat_remove(kstat_t *ks)
1089f4b3ec61Sdh155122 {
1090f4b3ec61Sdh155122 	struct shared_zone_list *sz;
1091f4b3ec61Sdh155122 	struct shared_kstat_list **skp, *sk;
1092f4b3ec61Sdh155122 
1093f4b3ec61Sdh155122 	/* Find in list */
1094f4b3ec61Sdh155122 	mutex_enter(&netstack_shared_lock);
1095f4b3ec61Sdh155122 	sk = NULL;
1096f4b3ec61Sdh155122 	for (skp = &netstack_shared_kstats; *skp != NULL;
1097f4b3ec61Sdh155122 	    skp = &((*skp)->sk_next)) {
1098f4b3ec61Sdh155122 		if ((*skp)->sk_kstat == ks) {
1099f4b3ec61Sdh155122 			sk = *skp;
1100f4b3ec61Sdh155122 			break;
1101f4b3ec61Sdh155122 		}
1102f4b3ec61Sdh155122 	}
1103f4b3ec61Sdh155122 	/* Must find it */
1104f4b3ec61Sdh155122 	ASSERT(sk != NULL);
1105f4b3ec61Sdh155122 	*skp = sk->sk_next;
1106f4b3ec61Sdh155122 	sk->sk_next = NULL;
1107f4b3ec61Sdh155122 
1108f4b3ec61Sdh155122 	/*
1109f4b3ec61Sdh155122 	 * Perform kstat_zone_remove for each existing shared stack kstat.
1110f4b3ec61Sdh155122 	 * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
1111f4b3ec61Sdh155122 	 */
1112f4b3ec61Sdh155122 	for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
1113f4b3ec61Sdh155122 		kstat_zone_remove(ks, sz->sz_zoneid);
1114f4b3ec61Sdh155122 	}
1115f4b3ec61Sdh155122 	mutex_exit(&netstack_shared_lock);
1116f4b3ec61Sdh155122 	kmem_free(sk, sizeof (*sk));
1117f4b3ec61Sdh155122 }
1118f4b3ec61Sdh155122 
1119f4b3ec61Sdh155122 /*
1120f4b3ec61Sdh155122  * If a zoneid is part of the shared zone, return true
1121f4b3ec61Sdh155122  */
1122f4b3ec61Sdh155122 static boolean_t
1123f4b3ec61Sdh155122 netstack_find_shared_zoneid(zoneid_t zoneid)
1124f4b3ec61Sdh155122 {
1125f4b3ec61Sdh155122 	struct shared_zone_list *sz;
1126f4b3ec61Sdh155122 
1127f4b3ec61Sdh155122 	mutex_enter(&netstack_shared_lock);
1128f4b3ec61Sdh155122 	for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
1129f4b3ec61Sdh155122 		if (sz->sz_zoneid == zoneid) {
1130f4b3ec61Sdh155122 			mutex_exit(&netstack_shared_lock);
1131f4b3ec61Sdh155122 			return (B_TRUE);
1132f4b3ec61Sdh155122 		}
1133f4b3ec61Sdh155122 	}
1134f4b3ec61Sdh155122 	mutex_exit(&netstack_shared_lock);
1135f4b3ec61Sdh155122 	return (B_FALSE);
1136f4b3ec61Sdh155122 }
1137f4b3ec61Sdh155122 
1138f4b3ec61Sdh155122 /*
1139f4b3ec61Sdh155122  * Hide the fact that zoneids and netstackids are allocated from
1140f4b3ec61Sdh155122  * the same space in the current implementation.
1141f4b3ec61Sdh155122  * XXX could add checks that the stackid/zoneids are valid...
1142f4b3ec61Sdh155122  */
1143f4b3ec61Sdh155122 zoneid_t
1144f4b3ec61Sdh155122 netstackid_to_zoneid(netstackid_t stackid)
1145f4b3ec61Sdh155122 {
1146f4b3ec61Sdh155122 	return (stackid);
1147f4b3ec61Sdh155122 }
1148f4b3ec61Sdh155122 
1149f4b3ec61Sdh155122 netstackid_t
1150f4b3ec61Sdh155122 zoneid_to_netstackid(zoneid_t zoneid)
1151f4b3ec61Sdh155122 {
1152f4b3ec61Sdh155122 	if (netstack_find_shared_zoneid(zoneid))
1153f4b3ec61Sdh155122 		return (GLOBAL_ZONEID);
1154f4b3ec61Sdh155122 	else
1155f4b3ec61Sdh155122 		return (zoneid);
1156f4b3ec61Sdh155122 }
1157f4b3ec61Sdh155122 
1158f4b3ec61Sdh155122 /*
1159f4b3ec61Sdh155122  * Simplistic support for walking all the handles.
1160f4b3ec61Sdh155122  * Example usage:
1161f4b3ec61Sdh155122  *	netstack_handle_t nh;
1162f4b3ec61Sdh155122  *	netstack_t *ns;
1163f4b3ec61Sdh155122  *
1164f4b3ec61Sdh155122  *	netstack_next_init(&nh);
1165f4b3ec61Sdh155122  *	while ((ns = netstack_next(&nh)) != NULL) {
1166f4b3ec61Sdh155122  *		do something;
1167f4b3ec61Sdh155122  *		netstack_rele(ns);
1168f4b3ec61Sdh155122  *	}
1169f4b3ec61Sdh155122  *	netstack_next_fini(&nh);
1170f4b3ec61Sdh155122  */
1171f4b3ec61Sdh155122 void
1172f4b3ec61Sdh155122 netstack_next_init(netstack_handle_t *handle)
1173f4b3ec61Sdh155122 {
1174f4b3ec61Sdh155122 	*handle = 0;
1175f4b3ec61Sdh155122 }
1176f4b3ec61Sdh155122 
1177f4b3ec61Sdh155122 /* ARGSUSED */
1178f4b3ec61Sdh155122 void
1179f4b3ec61Sdh155122 netstack_next_fini(netstack_handle_t *handle)
1180f4b3ec61Sdh155122 {
1181f4b3ec61Sdh155122 }
1182f4b3ec61Sdh155122 
1183f4b3ec61Sdh155122 netstack_t *
1184f4b3ec61Sdh155122 netstack_next(netstack_handle_t *handle)
1185f4b3ec61Sdh155122 {
1186f4b3ec61Sdh155122 	netstack_t *ns;
1187f4b3ec61Sdh155122 	int i, end;
1188f4b3ec61Sdh155122 
1189f4b3ec61Sdh155122 	end = *handle;
1190f4b3ec61Sdh155122 	/* Walk skipping *handle number of instances */
1191f4b3ec61Sdh155122 
1192f4b3ec61Sdh155122 	/* Look if there is a matching stack instance */
1193f4b3ec61Sdh155122 	mutex_enter(&netstack_g_lock);
1194f4b3ec61Sdh155122 	ns = netstack_head;
1195f4b3ec61Sdh155122 	for (i = 0; i < end; i++) {
1196f4b3ec61Sdh155122 		if (ns == NULL)
1197f4b3ec61Sdh155122 			break;
1198f4b3ec61Sdh155122 		ns = ns->netstack_next;
1199f4b3ec61Sdh155122 	}
1200f4b3ec61Sdh155122 	/* skip those with that aren't really here */
1201f4b3ec61Sdh155122 	while (ns != NULL) {
1202f4b3ec61Sdh155122 		mutex_enter(&ns->netstack_lock);
1203f4b3ec61Sdh155122 		if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
1204f4b3ec61Sdh155122 			mutex_exit(&ns->netstack_lock);
1205f4b3ec61Sdh155122 			break;
1206f4b3ec61Sdh155122 		}
1207f4b3ec61Sdh155122 		mutex_exit(&ns->netstack_lock);
1208f4b3ec61Sdh155122 		end++;
1209f4b3ec61Sdh155122 		ns = ns->netstack_next;
1210f4b3ec61Sdh155122 	}
1211f4b3ec61Sdh155122 	if (ns != NULL) {
1212f4b3ec61Sdh155122 		*handle = end + 1;
1213f4b3ec61Sdh155122 		netstack_hold(ns);
1214f4b3ec61Sdh155122 	}
1215f4b3ec61Sdh155122 	mutex_exit(&netstack_g_lock);
1216f4b3ec61Sdh155122 	return (ns);
1217f4b3ec61Sdh155122 }
1218