xref: /onnv-gate/usr/src/uts/common/io/neti_stack.c (revision 7513:18aa777d3f09)
1*7513SDarren.Reed@Sun.COM /*
2*7513SDarren.Reed@Sun.COM  * CDDL HEADER START
3*7513SDarren.Reed@Sun.COM  *
4*7513SDarren.Reed@Sun.COM  * The contents of this file are subject to the terms of the
5*7513SDarren.Reed@Sun.COM  * Common Development and Distribution License (the "License").
6*7513SDarren.Reed@Sun.COM  * You may not use this file except in compliance with the License.
7*7513SDarren.Reed@Sun.COM  *
8*7513SDarren.Reed@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7513SDarren.Reed@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7513SDarren.Reed@Sun.COM  * See the License for the specific language governing permissions
11*7513SDarren.Reed@Sun.COM  * and limitations under the License.
12*7513SDarren.Reed@Sun.COM  *
13*7513SDarren.Reed@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7513SDarren.Reed@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7513SDarren.Reed@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7513SDarren.Reed@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7513SDarren.Reed@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7513SDarren.Reed@Sun.COM  *
19*7513SDarren.Reed@Sun.COM  * CDDL HEADER END
20*7513SDarren.Reed@Sun.COM  */
21*7513SDarren.Reed@Sun.COM /*
22*7513SDarren.Reed@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7513SDarren.Reed@Sun.COM  * Use is subject to license terms.
24*7513SDarren.Reed@Sun.COM  */
25*7513SDarren.Reed@Sun.COM 
26*7513SDarren.Reed@Sun.COM #include <sys/param.h>
27*7513SDarren.Reed@Sun.COM #include <sys/atomic.h>
28*7513SDarren.Reed@Sun.COM #include <sys/kmem.h>
29*7513SDarren.Reed@Sun.COM #include <sys/rwlock.h>
30*7513SDarren.Reed@Sun.COM #include <sys/errno.h>
31*7513SDarren.Reed@Sun.COM #include <sys/queue.h>
32*7513SDarren.Reed@Sun.COM #include <sys/sunddi.h>
33*7513SDarren.Reed@Sun.COM #include <inet/common.h>
34*7513SDarren.Reed@Sun.COM #include <inet/led.h>
35*7513SDarren.Reed@Sun.COM #include <inet/ip.h>
36*7513SDarren.Reed@Sun.COM #include <sys/neti.h>
37*7513SDarren.Reed@Sun.COM #include <sys/zone.h>
38*7513SDarren.Reed@Sun.COM #include <sys/sdt.h>
39*7513SDarren.Reed@Sun.COM 
40*7513SDarren.Reed@Sun.COM 
41*7513SDarren.Reed@Sun.COM typedef boolean_t napplyfn_t(kmutex_t *, neti_stack_t *, void *);
42*7513SDarren.Reed@Sun.COM 
43*7513SDarren.Reed@Sun.COM static void *neti_stack_init(netstackid_t stackid, netstack_t *ns);
44*7513SDarren.Reed@Sun.COM static void neti_stack_fini(netstackid_t stackid, void *arg);
45*7513SDarren.Reed@Sun.COM static net_instance_int_t *net_instance_int_create(net_instance_t *nin,
46*7513SDarren.Reed@Sun.COM     net_instance_int_t *parent);
47*7513SDarren.Reed@Sun.COM static void neti_stack_shutdown(netstackid_t stackid, void *arg);
48*7513SDarren.Reed@Sun.COM static void net_instance_int_free(net_instance_int_t *nini);
49*7513SDarren.Reed@Sun.COM 
50*7513SDarren.Reed@Sun.COM static boolean_t neti_stack_apply_create(kmutex_t *, neti_stack_t *, void *);
51*7513SDarren.Reed@Sun.COM static boolean_t neti_stack_apply_destroy(kmutex_t *, neti_stack_t *, void *);
52*7513SDarren.Reed@Sun.COM static boolean_t neti_stack_apply_shutdown(kmutex_t *, neti_stack_t *, void *);
53*7513SDarren.Reed@Sun.COM static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *);
54*7513SDarren.Reed@Sun.COM static void neti_apply_all_stacks(void *, napplyfn_t *);
55*7513SDarren.Reed@Sun.COM static boolean_t wait_for_nini_inprogress(neti_stack_t *, kmutex_t *,
56*7513SDarren.Reed@Sun.COM     net_instance_int_t *, uint32_t);
57*7513SDarren.Reed@Sun.COM 
58*7513SDarren.Reed@Sun.COM static nini_head_t neti_instance_list;
59*7513SDarren.Reed@Sun.COM static neti_stack_head_t neti_stack_list;
60*7513SDarren.Reed@Sun.COM static kmutex_t neti_stack_lock;
61*7513SDarren.Reed@Sun.COM 
62*7513SDarren.Reed@Sun.COM void
63*7513SDarren.Reed@Sun.COM neti_init()
64*7513SDarren.Reed@Sun.COM {
65*7513SDarren.Reed@Sun.COM 	mutex_init(&neti_stack_lock, NULL, MUTEX_DRIVER, NULL);
66*7513SDarren.Reed@Sun.COM 
67*7513SDarren.Reed@Sun.COM 	LIST_INIT(&neti_instance_list);
68*7513SDarren.Reed@Sun.COM 	LIST_INIT(&neti_stack_list);
69*7513SDarren.Reed@Sun.COM 	/*
70*7513SDarren.Reed@Sun.COM 	 * We want to be informed each time a netstack is created or
71*7513SDarren.Reed@Sun.COM 	 * destroyed in the kernel.
72*7513SDarren.Reed@Sun.COM 	 */
73*7513SDarren.Reed@Sun.COM 	netstack_register(NS_NETI, neti_stack_init, neti_stack_shutdown,
74*7513SDarren.Reed@Sun.COM 	    neti_stack_fini);
75*7513SDarren.Reed@Sun.COM }
76*7513SDarren.Reed@Sun.COM 
77*7513SDarren.Reed@Sun.COM void
78*7513SDarren.Reed@Sun.COM neti_fini()
79*7513SDarren.Reed@Sun.COM {
80*7513SDarren.Reed@Sun.COM 	ASSERT(LIST_EMPTY(&neti_instance_list));
81*7513SDarren.Reed@Sun.COM 	ASSERT(LIST_EMPTY(&neti_stack_list));
82*7513SDarren.Reed@Sun.COM 
83*7513SDarren.Reed@Sun.COM 	netstack_unregister(NS_NETI);
84*7513SDarren.Reed@Sun.COM 
85*7513SDarren.Reed@Sun.COM 	mutex_destroy(&neti_stack_lock);
86*7513SDarren.Reed@Sun.COM }
87*7513SDarren.Reed@Sun.COM 
88*7513SDarren.Reed@Sun.COM /*
89*7513SDarren.Reed@Sun.COM  * Initialize the neti stack instance.  Because this is called out of the
90*7513SDarren.Reed@Sun.COM  * netstack framework, it is not possible for it to be called twice with
91*7513SDarren.Reed@Sun.COM  * the same values for (stackid,ns).  The same also applies to the other
92*7513SDarren.Reed@Sun.COM  * two functions used with netstack_register: neti_stack_shutdown and
93*7513SDarren.Reed@Sun.COM  * neti_stack_fini.
94*7513SDarren.Reed@Sun.COM  */
95*7513SDarren.Reed@Sun.COM static void *
96*7513SDarren.Reed@Sun.COM neti_stack_init(netstackid_t stackid, netstack_t *ns)
97*7513SDarren.Reed@Sun.COM {
98*7513SDarren.Reed@Sun.COM 	net_instance_int_t *dup;
99*7513SDarren.Reed@Sun.COM 	net_instance_int_t *n;
100*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
101*7513SDarren.Reed@Sun.COM 
102*7513SDarren.Reed@Sun.COM 	nts = kmem_zalloc(sizeof (*nts), KM_SLEEP);
103*7513SDarren.Reed@Sun.COM 	LIST_INIT(&nts->nts_instances);
104*7513SDarren.Reed@Sun.COM 	nts->nts_id = (netid_t)stackid;
105*7513SDarren.Reed@Sun.COM 	nts->nts_stackid = stackid;
106*7513SDarren.Reed@Sun.COM 	nts->nts_netstack = ns;
107*7513SDarren.Reed@Sun.COM 	nts->nts_zoneid = netstackid_to_zoneid(stackid);
108*7513SDarren.Reed@Sun.COM 	nts->nts_flags = NSF_ZONE_CREATE;
109*7513SDarren.Reed@Sun.COM 	cv_init(&nts->nts_cv, NULL, CV_DRIVER, NULL);
110*7513SDarren.Reed@Sun.COM 	mutex_init(&nts->nts_lock, NULL, MUTEX_DRIVER, NULL);
111*7513SDarren.Reed@Sun.COM 
112*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
113*7513SDarren.Reed@Sun.COM 	LIST_INSERT_HEAD(&neti_stack_list, nts, nts_next);
114*7513SDarren.Reed@Sun.COM 
115*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(n, &neti_instance_list, nini_next) {
116*7513SDarren.Reed@Sun.COM 		/*
117*7513SDarren.Reed@Sun.COM 		 * This function returns with the NSS_CREATE_NEEDED flag
118*7513SDarren.Reed@Sun.COM 		 * set in "dup", so it is adequately prepared for the
119*7513SDarren.Reed@Sun.COM 		 * upcoming apply.
120*7513SDarren.Reed@Sun.COM 		 */
121*7513SDarren.Reed@Sun.COM 		dup = net_instance_int_create(n->nini_instance, n);
122*7513SDarren.Reed@Sun.COM 
123*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
124*7513SDarren.Reed@Sun.COM 		LIST_INSERT_HEAD(&nts->nts_instances, dup, nini_next);
125*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
126*7513SDarren.Reed@Sun.COM 	}
127*7513SDarren.Reed@Sun.COM 
128*7513SDarren.Reed@Sun.COM 	neti_apply_all_instances(nts, neti_stack_apply_create);
129*7513SDarren.Reed@Sun.COM 
130*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
131*7513SDarren.Reed@Sun.COM 	nts->nts_flags &= ~NSF_ZONE_CREATE;
132*7513SDarren.Reed@Sun.COM 	cv_signal(&nts->nts_cv);
133*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
134*7513SDarren.Reed@Sun.COM 
135*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
136*7513SDarren.Reed@Sun.COM 
137*7513SDarren.Reed@Sun.COM 	return (nts);
138*7513SDarren.Reed@Sun.COM }
139*7513SDarren.Reed@Sun.COM 
140*7513SDarren.Reed@Sun.COM /*
141*7513SDarren.Reed@Sun.COM  * Run the shutdown for all of the hooks.
142*7513SDarren.Reed@Sun.COM  */
143*7513SDarren.Reed@Sun.COM /*ARGSUSED*/
144*7513SDarren.Reed@Sun.COM static void
145*7513SDarren.Reed@Sun.COM neti_stack_shutdown(netstackid_t stackid, void *arg)
146*7513SDarren.Reed@Sun.COM {
147*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts = arg;
148*7513SDarren.Reed@Sun.COM 	net_instance_int_t *n;
149*7513SDarren.Reed@Sun.COM 	struct net_data *nd;
150*7513SDarren.Reed@Sun.COM 
151*7513SDarren.Reed@Sun.COM 	ASSERT(nts != NULL);
152*7513SDarren.Reed@Sun.COM 
153*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
154*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
155*7513SDarren.Reed@Sun.COM 	/*
156*7513SDarren.Reed@Sun.COM 	 * Walk through all of the protocol stacks and mark them as shutting
157*7513SDarren.Reed@Sun.COM 	 * down.
158*7513SDarren.Reed@Sun.COM 	 */
159*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
160*7513SDarren.Reed@Sun.COM 		nd->netd_condemned = 1;
161*7513SDarren.Reed@Sun.COM 	}
162*7513SDarren.Reed@Sun.COM 
163*7513SDarren.Reed@Sun.COM 	/*
164*7513SDarren.Reed@Sun.COM 	 * Now proceed to see which callbacks are waiting to hear about the
165*7513SDarren.Reed@Sun.COM 	 * impending shutdown...
166*7513SDarren.Reed@Sun.COM 	 */
167*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(n, &nts->nts_instances, nini_next) {
168*7513SDarren.Reed@Sun.COM 		if (n->nini_instance->nin_shutdown == NULL) {
169*7513SDarren.Reed@Sun.COM 			/*
170*7513SDarren.Reed@Sun.COM 			 * If there is no shutdown function registered,
171*7513SDarren.Reed@Sun.COM 			 * fake that we have completed it.
172*7513SDarren.Reed@Sun.COM 			 */
173*7513SDarren.Reed@Sun.COM 			n->nini_flags |= NSS_SHUTDOWN_COMPLETED;
174*7513SDarren.Reed@Sun.COM 			continue;
175*7513SDarren.Reed@Sun.COM 		}
176*7513SDarren.Reed@Sun.COM 
177*7513SDarren.Reed@Sun.COM 		/*
178*7513SDarren.Reed@Sun.COM 		 * We need to ensure that we don't try and shutdown something
179*7513SDarren.Reed@Sun.COM 		 * that is already in the process of being shutdown or
180*7513SDarren.Reed@Sun.COM 		 * destroyed. If it is still being created, that's ok, the
181*7513SDarren.Reed@Sun.COM 		 * shtudown flag is added to the mix of things to do.
182*7513SDarren.Reed@Sun.COM 		 */
183*7513SDarren.Reed@Sun.COM 		if ((n->nini_flags & (NSS_DESTROY_ALL|NSS_SHUTDOWN_ALL)) == 0)
184*7513SDarren.Reed@Sun.COM 			n->nini_flags |= NSS_SHUTDOWN_NEEDED;
185*7513SDarren.Reed@Sun.COM 	}
186*7513SDarren.Reed@Sun.COM 	nts->nts_flags |= NSF_ZONE_SHUTDOWN;
187*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
188*7513SDarren.Reed@Sun.COM 
189*7513SDarren.Reed@Sun.COM 	neti_apply_all_instances(nts, neti_stack_apply_shutdown);
190*7513SDarren.Reed@Sun.COM 
191*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
192*7513SDarren.Reed@Sun.COM 
193*7513SDarren.Reed@Sun.COM 	nts->nts_netstack = NULL;
194*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
195*7513SDarren.Reed@Sun.COM 
196*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
197*7513SDarren.Reed@Sun.COM 	ASSERT(nts != NULL);
198*7513SDarren.Reed@Sun.COM }
199*7513SDarren.Reed@Sun.COM 
200*7513SDarren.Reed@Sun.COM /*
201*7513SDarren.Reed@Sun.COM  * Free the neti stack instance.
202*7513SDarren.Reed@Sun.COM  * This function relies on the netstack framework only calling the _destroy
203*7513SDarren.Reed@Sun.COM  * callback once for each stackid.  The netstack framework also provides us
204*7513SDarren.Reed@Sun.COM  * with assurance that nobody else will be doing any work (_create, _shutdown)
205*7513SDarren.Reed@Sun.COM  * on it, so there is no need to set and use flags to guard against
206*7513SDarren.Reed@Sun.COM  * simultaneous execution (ie. no need to set NSF_CLOSING.)
207*7513SDarren.Reed@Sun.COM  *  What is required, however, is to make sure that we don't corrupt the
208*7513SDarren.Reed@Sun.COM  * list of neti_stack_t's for other code that walks it.
209*7513SDarren.Reed@Sun.COM  */
210*7513SDarren.Reed@Sun.COM /*ARGSUSED*/
211*7513SDarren.Reed@Sun.COM static void
212*7513SDarren.Reed@Sun.COM neti_stack_fini(netstackid_t stackid, void *arg)
213*7513SDarren.Reed@Sun.COM {
214*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts = arg;
215*7513SDarren.Reed@Sun.COM 	net_instance_int_t *n;
216*7513SDarren.Reed@Sun.COM 	struct net_data *nd;
217*7513SDarren.Reed@Sun.COM 
218*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
219*7513SDarren.Reed@Sun.COM 	LIST_REMOVE(nts, nts_next);
220*7513SDarren.Reed@Sun.COM 
221*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
222*7513SDarren.Reed@Sun.COM 	nts->nts_flags |= NSF_ZONE_DESTROY;
223*7513SDarren.Reed@Sun.COM 	/*
224*7513SDarren.Reed@Sun.COM 	 * Walk through all of the protocol stacks and mark them as being
225*7513SDarren.Reed@Sun.COM 	 * destroyed.
226*7513SDarren.Reed@Sun.COM 	 */
227*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
228*7513SDarren.Reed@Sun.COM 		nd->netd_condemned = 2;
229*7513SDarren.Reed@Sun.COM 	}
230*7513SDarren.Reed@Sun.COM 
231*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(n, &nts->nts_instances, nini_next) {
232*7513SDarren.Reed@Sun.COM 		ASSERT((n->nini_flags & NSS_SHUTDOWN_ALL) != 0);
233*7513SDarren.Reed@Sun.COM 		if (n->nini_instance->nin_shutdown == NULL)
234*7513SDarren.Reed@Sun.COM 			continue;
235*7513SDarren.Reed@Sun.COM 		if ((n->nini_flags & NSS_DESTROY_ALL) == 0)
236*7513SDarren.Reed@Sun.COM 			n->nini_flags |= NSS_DESTROY_NEEDED;
237*7513SDarren.Reed@Sun.COM 	}
238*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
239*7513SDarren.Reed@Sun.COM 
240*7513SDarren.Reed@Sun.COM 	neti_apply_all_instances(nts, neti_stack_apply_destroy);
241*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
242*7513SDarren.Reed@Sun.COM 
243*7513SDarren.Reed@Sun.COM 	while (!LIST_EMPTY(&nts->nts_instances)) {
244*7513SDarren.Reed@Sun.COM 		n = LIST_FIRST(&nts->nts_instances);
245*7513SDarren.Reed@Sun.COM 		LIST_REMOVE(n, nini_next);
246*7513SDarren.Reed@Sun.COM 
247*7513SDarren.Reed@Sun.COM 		net_instance_int_free(n);
248*7513SDarren.Reed@Sun.COM 	}
249*7513SDarren.Reed@Sun.COM 
250*7513SDarren.Reed@Sun.COM 	ASSERT(LIST_EMPTY(&nts->nts_netd_head));
251*7513SDarren.Reed@Sun.COM 
252*7513SDarren.Reed@Sun.COM 	mutex_destroy(&nts->nts_lock);
253*7513SDarren.Reed@Sun.COM 	cv_destroy(&nts->nts_cv);
254*7513SDarren.Reed@Sun.COM 
255*7513SDarren.Reed@Sun.COM 	kmem_free(nts, sizeof (*nts));
256*7513SDarren.Reed@Sun.COM }
257*7513SDarren.Reed@Sun.COM 
258*7513SDarren.Reed@Sun.COM static net_instance_int_t *
259*7513SDarren.Reed@Sun.COM net_instance_int_create(net_instance_t *nin, net_instance_int_t *parent)
260*7513SDarren.Reed@Sun.COM {
261*7513SDarren.Reed@Sun.COM 	net_instance_int_t *nini;
262*7513SDarren.Reed@Sun.COM 
263*7513SDarren.Reed@Sun.COM 	nini = kmem_zalloc(sizeof (net_instance_int_t), KM_SLEEP);
264*7513SDarren.Reed@Sun.COM 	nini->nini_instance = nin;
265*7513SDarren.Reed@Sun.COM 	nini->nini_parent = parent;
266*7513SDarren.Reed@Sun.COM 	if (parent != NULL) {
267*7513SDarren.Reed@Sun.COM 		/*
268*7513SDarren.Reed@Sun.COM 		 * If the parent pointer is non-NULL then we take that as
269*7513SDarren.Reed@Sun.COM 		 * an indication that the net_instance_int_t is being
270*7513SDarren.Reed@Sun.COM 		 * created for an active instance and there will expect
271*7513SDarren.Reed@Sun.COM 		 * the create function to be called.  In contrast, if
272*7513SDarren.Reed@Sun.COM 		 * parent is NULL then this code assumes the object is
273*7513SDarren.Reed@Sun.COM 		 * being prepared for insertion onto the master list of
274*7513SDarren.Reed@Sun.COM 		 * callbacks to be called when an instance is created, etc.
275*7513SDarren.Reed@Sun.COM 		 */
276*7513SDarren.Reed@Sun.COM 		parent->nini_ref++;
277*7513SDarren.Reed@Sun.COM 		nini->nini_flags |= NSS_CREATE_NEEDED;
278*7513SDarren.Reed@Sun.COM 	}
279*7513SDarren.Reed@Sun.COM 
280*7513SDarren.Reed@Sun.COM 	cv_init(&nini->nini_cv, NULL, CV_DRIVER, NULL);
281*7513SDarren.Reed@Sun.COM 
282*7513SDarren.Reed@Sun.COM 	return (nini);
283*7513SDarren.Reed@Sun.COM }
284*7513SDarren.Reed@Sun.COM 
285*7513SDarren.Reed@Sun.COM static void
286*7513SDarren.Reed@Sun.COM net_instance_int_free(net_instance_int_t *nini)
287*7513SDarren.Reed@Sun.COM {
288*7513SDarren.Reed@Sun.COM 
289*7513SDarren.Reed@Sun.COM 	cv_destroy(&nini->nini_cv);
290*7513SDarren.Reed@Sun.COM 
291*7513SDarren.Reed@Sun.COM 	if (nini->nini_parent != NULL)
292*7513SDarren.Reed@Sun.COM 		nini->nini_parent->nini_ref--;
293*7513SDarren.Reed@Sun.COM 
294*7513SDarren.Reed@Sun.COM 	ASSERT(nini->nini_ref == 0);
295*7513SDarren.Reed@Sun.COM 	kmem_free(nini, sizeof (*nini));
296*7513SDarren.Reed@Sun.COM }
297*7513SDarren.Reed@Sun.COM 
298*7513SDarren.Reed@Sun.COM net_instance_t *
299*7513SDarren.Reed@Sun.COM net_instance_alloc(const int version)
300*7513SDarren.Reed@Sun.COM {
301*7513SDarren.Reed@Sun.COM 	net_instance_t *nin;
302*7513SDarren.Reed@Sun.COM 
303*7513SDarren.Reed@Sun.COM 	if (version != NETINFO_VERSION)
304*7513SDarren.Reed@Sun.COM 		return (NULL);
305*7513SDarren.Reed@Sun.COM 
306*7513SDarren.Reed@Sun.COM 	nin = kmem_zalloc(sizeof (net_instance_t), KM_SLEEP);
307*7513SDarren.Reed@Sun.COM 	nin->nin_version = version;
308*7513SDarren.Reed@Sun.COM 
309*7513SDarren.Reed@Sun.COM 	return (nin);
310*7513SDarren.Reed@Sun.COM }
311*7513SDarren.Reed@Sun.COM 
312*7513SDarren.Reed@Sun.COM void
313*7513SDarren.Reed@Sun.COM net_instance_free(net_instance_t *nin)
314*7513SDarren.Reed@Sun.COM {
315*7513SDarren.Reed@Sun.COM 	kmem_free(nin, sizeof (*nin));
316*7513SDarren.Reed@Sun.COM }
317*7513SDarren.Reed@Sun.COM 
318*7513SDarren.Reed@Sun.COM int
319*7513SDarren.Reed@Sun.COM net_instance_register(net_instance_t *nin)
320*7513SDarren.Reed@Sun.COM {
321*7513SDarren.Reed@Sun.COM 	net_instance_int_t *parent;
322*7513SDarren.Reed@Sun.COM 	net_instance_int_t *tmp;
323*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
324*7513SDarren.Reed@Sun.COM 
325*7513SDarren.Reed@Sun.COM 	ASSERT(nin->nin_name != NULL);
326*7513SDarren.Reed@Sun.COM 
327*7513SDarren.Reed@Sun.COM 	if (nin->nin_create == NULL || nin->nin_destroy == NULL)
328*7513SDarren.Reed@Sun.COM 		return (DDI_FAILURE);
329*7513SDarren.Reed@Sun.COM 
330*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
331*7513SDarren.Reed@Sun.COM 	/*
332*7513SDarren.Reed@Sun.COM 	 * Search for duplicate, either on the global list or on any
333*7513SDarren.Reed@Sun.COM 	 * of the known instances.
334*7513SDarren.Reed@Sun.COM 	 */
335*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
336*7513SDarren.Reed@Sun.COM 		if (strcmp(nin->nin_name, tmp->nini_instance->nin_name) == 0) {
337*7513SDarren.Reed@Sun.COM 			mutex_exit(&neti_stack_lock);
338*7513SDarren.Reed@Sun.COM 			return (DDI_FAILURE);
339*7513SDarren.Reed@Sun.COM 		}
340*7513SDarren.Reed@Sun.COM 	}
341*7513SDarren.Reed@Sun.COM 
342*7513SDarren.Reed@Sun.COM 	/*
343*7513SDarren.Reed@Sun.COM 	 * Now insert and activate.
344*7513SDarren.Reed@Sun.COM 	 */
345*7513SDarren.Reed@Sun.COM 	parent = net_instance_int_create(nin, NULL);
346*7513SDarren.Reed@Sun.COM 	ASSERT(parent != NULL);
347*7513SDarren.Reed@Sun.COM 	LIST_INSERT_HEAD(&neti_instance_list, parent, nini_next);
348*7513SDarren.Reed@Sun.COM 
349*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
350*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
351*7513SDarren.Reed@Sun.COM 		/*
352*7513SDarren.Reed@Sun.COM 		 * If shutdown of the zone has begun then do not add a new
353*7513SDarren.Reed@Sun.COM 		 * instance of the object being registered.
354*7513SDarren.Reed@Sun.COM 		 */
355*7513SDarren.Reed@Sun.COM 		if ((nts->nts_flags & NSF_ZONE_SHUTDOWN) ||
356*7513SDarren.Reed@Sun.COM 		    (nts->nts_netstack == NULL)) {
357*7513SDarren.Reed@Sun.COM 			mutex_exit(&nts->nts_lock);
358*7513SDarren.Reed@Sun.COM 			continue;
359*7513SDarren.Reed@Sun.COM 		}
360*7513SDarren.Reed@Sun.COM 		/*
361*7513SDarren.Reed@Sun.COM 		 * This function returns with the NSS_CREATE_NEEDED flag
362*7513SDarren.Reed@Sun.COM 		 * set in "dup", so it is adequately prepared for the
363*7513SDarren.Reed@Sun.COM 		 * upcoming apply.
364*7513SDarren.Reed@Sun.COM 		 */
365*7513SDarren.Reed@Sun.COM 		tmp = net_instance_int_create(nin, parent);
366*7513SDarren.Reed@Sun.COM 		ASSERT(tmp != NULL);
367*7513SDarren.Reed@Sun.COM 		LIST_INSERT_HEAD(&nts->nts_instances, tmp, nini_next);
368*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
369*7513SDarren.Reed@Sun.COM 
370*7513SDarren.Reed@Sun.COM 	}
371*7513SDarren.Reed@Sun.COM 
372*7513SDarren.Reed@Sun.COM 	neti_apply_all_stacks(parent, neti_stack_apply_create);
373*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
374*7513SDarren.Reed@Sun.COM 
375*7513SDarren.Reed@Sun.COM 	return (DDI_SUCCESS);
376*7513SDarren.Reed@Sun.COM }
377*7513SDarren.Reed@Sun.COM 
378*7513SDarren.Reed@Sun.COM /*
379*7513SDarren.Reed@Sun.COM  * While net_instance_register() isn't likely to be racing against itself,
380*7513SDarren.Reed@Sun.COM  * net_instance_unregister() can be entered from various directions that
381*7513SDarren.Reed@Sun.COM  * can compete: shutdown of a zone, unloading of a module (and it calling
382*7513SDarren.Reed@Sun.COM  * _unregister() as part of that) and the module doing an _unregister()
383*7513SDarren.Reed@Sun.COM  * anyway.
384*7513SDarren.Reed@Sun.COM  */
385*7513SDarren.Reed@Sun.COM int
386*7513SDarren.Reed@Sun.COM net_instance_unregister(net_instance_t *nin)
387*7513SDarren.Reed@Sun.COM {
388*7513SDarren.Reed@Sun.COM 	net_instance_int_t *parent;
389*7513SDarren.Reed@Sun.COM 	net_instance_int_t *tmp;
390*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
391*7513SDarren.Reed@Sun.COM 
392*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
393*7513SDarren.Reed@Sun.COM 
394*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
395*7513SDarren.Reed@Sun.COM 		if (strcmp(tmp->nini_instance->nin_name, nin->nin_name) == 0) {
396*7513SDarren.Reed@Sun.COM 			LIST_REMOVE(tmp, nini_next);
397*7513SDarren.Reed@Sun.COM 			break;
398*7513SDarren.Reed@Sun.COM 		}
399*7513SDarren.Reed@Sun.COM 	}
400*7513SDarren.Reed@Sun.COM 
401*7513SDarren.Reed@Sun.COM 	if (tmp == NULL) {
402*7513SDarren.Reed@Sun.COM 		mutex_exit(&neti_stack_lock);
403*7513SDarren.Reed@Sun.COM 		return (DDI_FAILURE);
404*7513SDarren.Reed@Sun.COM 	}
405*7513SDarren.Reed@Sun.COM 	parent = tmp;
406*7513SDarren.Reed@Sun.COM 
407*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
408*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
409*7513SDarren.Reed@Sun.COM 		LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
410*7513SDarren.Reed@Sun.COM 			if (tmp->nini_parent != parent)
411*7513SDarren.Reed@Sun.COM 				continue;
412*7513SDarren.Reed@Sun.COM 			/*
413*7513SDarren.Reed@Sun.COM 			 * Netstack difference:
414*7513SDarren.Reed@Sun.COM 			 * In netstack.c, there is a check for
415*7513SDarren.Reed@Sun.COM 			 * NSS_CREATE_COMPLETED before setting the other
416*7513SDarren.Reed@Sun.COM 			 * _NEEDED flags.  If we consider that a list
417*7513SDarren.Reed@Sun.COM 			 * member must always have at least the _CREATE_NEEDED
418*7513SDarren.Reed@Sun.COM 			 * flag set and that wait_for_nini_inprogress will
419*7513SDarren.Reed@Sun.COM 			 * also wait for that flag to be cleared in both of
420*7513SDarren.Reed@Sun.COM 			 * the shutdown and destroy apply functions.
421*7513SDarren.Reed@Sun.COM 			 *
422*7513SDarren.Reed@Sun.COM 			 * It is possible to optimize out the case where
423*7513SDarren.Reed@Sun.COM 			 * all three _NEEDED flags are set to being able
424*7513SDarren.Reed@Sun.COM 			 * to pretend everything has been done and just
425*7513SDarren.Reed@Sun.COM 			 * set all three _COMPLETE flags.  This makes a
426*7513SDarren.Reed@Sun.COM 			 * special case that we then need to consider in
427*7513SDarren.Reed@Sun.COM 			 * other locations, so for the sake of simplicity,
428*7513SDarren.Reed@Sun.COM 			 * we leave it as it is.
429*7513SDarren.Reed@Sun.COM 			 */
430*7513SDarren.Reed@Sun.COM 			if ((tmp->nini_flags & NSS_SHUTDOWN_ALL) == 0)
431*7513SDarren.Reed@Sun.COM 				tmp->nini_flags |= NSS_SHUTDOWN_NEEDED;
432*7513SDarren.Reed@Sun.COM 			if ((tmp->nini_flags & NSS_DESTROY_ALL) == 0)
433*7513SDarren.Reed@Sun.COM 				tmp->nini_flags |= NSS_DESTROY_NEEDED;
434*7513SDarren.Reed@Sun.COM 		}
435*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
436*7513SDarren.Reed@Sun.COM 	}
437*7513SDarren.Reed@Sun.COM 
438*7513SDarren.Reed@Sun.COM 	/*
439*7513SDarren.Reed@Sun.COM 	 * Each of these functions ensures that the requisite _COMPLETED
440*7513SDarren.Reed@Sun.COM 	 * flag is present before calling the apply function. So we are
441*7513SDarren.Reed@Sun.COM 	 * guaranteed to have NSS_CREATE_COMPLETED|NSS_SHUTDOWN_COMPLETED
442*7513SDarren.Reed@Sun.COM 	 * both set after the first call here and when the second completes,
443*7513SDarren.Reed@Sun.COM 	 * NSS_DESTROY_COMPLETED is also set.
444*7513SDarren.Reed@Sun.COM 	 */
445*7513SDarren.Reed@Sun.COM 	neti_apply_all_stacks(parent, neti_stack_apply_shutdown);
446*7513SDarren.Reed@Sun.COM 	neti_apply_all_stacks(parent, neti_stack_apply_destroy);
447*7513SDarren.Reed@Sun.COM 
448*7513SDarren.Reed@Sun.COM 	/*
449*7513SDarren.Reed@Sun.COM 	 * Remove the instance callback information from each stack.
450*7513SDarren.Reed@Sun.COM 	 */
451*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
452*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
453*7513SDarren.Reed@Sun.COM 		LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
454*7513SDarren.Reed@Sun.COM 			if ((tmp->nini_parent == parent) &&
455*7513SDarren.Reed@Sun.COM 			    (tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) &&
456*7513SDarren.Reed@Sun.COM 			    (tmp->nini_flags & NSS_DESTROY_COMPLETED)) {
457*7513SDarren.Reed@Sun.COM 				/*
458*7513SDarren.Reed@Sun.COM 				 * There should only be one entry that has a
459*7513SDarren.Reed@Sun.COM 				 * matching nini_parent so there is no need to
460*7513SDarren.Reed@Sun.COM 				 * worry about continuing a loop where we are
461*7513SDarren.Reed@Sun.COM 				 * free'ing the structure holding the 'next'
462*7513SDarren.Reed@Sun.COM 				 * pointer.
463*7513SDarren.Reed@Sun.COM 				 */
464*7513SDarren.Reed@Sun.COM 				LIST_REMOVE(tmp, nini_next);
465*7513SDarren.Reed@Sun.COM 				net_instance_int_free(tmp);
466*7513SDarren.Reed@Sun.COM 				break;
467*7513SDarren.Reed@Sun.COM 			}
468*7513SDarren.Reed@Sun.COM 		}
469*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
470*7513SDarren.Reed@Sun.COM 	}
471*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
472*7513SDarren.Reed@Sun.COM 
473*7513SDarren.Reed@Sun.COM 	net_instance_int_free(parent);
474*7513SDarren.Reed@Sun.COM 
475*7513SDarren.Reed@Sun.COM 	return (DDI_SUCCESS);
476*7513SDarren.Reed@Sun.COM }
477*7513SDarren.Reed@Sun.COM 
478*7513SDarren.Reed@Sun.COM static void
479*7513SDarren.Reed@Sun.COM neti_apply_all_instances(neti_stack_t *nts, napplyfn_t *applyfn)
480*7513SDarren.Reed@Sun.COM {
481*7513SDarren.Reed@Sun.COM 	net_instance_int_t *n;
482*7513SDarren.Reed@Sun.COM 
483*7513SDarren.Reed@Sun.COM 	ASSERT(mutex_owned(&neti_stack_lock));
484*7513SDarren.Reed@Sun.COM 
485*7513SDarren.Reed@Sun.COM 	n = LIST_FIRST(&nts->nts_instances);
486*7513SDarren.Reed@Sun.COM 	while (n != NULL) {
487*7513SDarren.Reed@Sun.COM 		if ((applyfn)(&neti_stack_lock, nts, n->nini_parent)) {
488*7513SDarren.Reed@Sun.COM 			/* Lock dropped - restart at head */
489*7513SDarren.Reed@Sun.COM 			n = LIST_FIRST(&nts->nts_instances);
490*7513SDarren.Reed@Sun.COM 		} else {
491*7513SDarren.Reed@Sun.COM 			n = LIST_NEXT(n, nini_next);
492*7513SDarren.Reed@Sun.COM 		}
493*7513SDarren.Reed@Sun.COM 	}
494*7513SDarren.Reed@Sun.COM }
495*7513SDarren.Reed@Sun.COM 
496*7513SDarren.Reed@Sun.COM static void
497*7513SDarren.Reed@Sun.COM neti_apply_all_stacks(void *parent, napplyfn_t *applyfn)
498*7513SDarren.Reed@Sun.COM {
499*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
500*7513SDarren.Reed@Sun.COM 
501*7513SDarren.Reed@Sun.COM 	ASSERT(mutex_owned(&neti_stack_lock));
502*7513SDarren.Reed@Sun.COM 
503*7513SDarren.Reed@Sun.COM 	nts = LIST_FIRST(&neti_stack_list);
504*7513SDarren.Reed@Sun.COM 	while (nts != NULL) {
505*7513SDarren.Reed@Sun.COM 		/*
506*7513SDarren.Reed@Sun.COM 		 * This function differs, in that it doesn't have a call to
507*7513SDarren.Reed@Sun.COM 		 * a "wait_creator" call, from the zsd/netstack code.  The
508*7513SDarren.Reed@Sun.COM 		 * waiting is pushed into the apply functions which cause
509*7513SDarren.Reed@Sun.COM 		 * the waiting to be done in wait_for_nini_progress with
510*7513SDarren.Reed@Sun.COM 		 * the passing in of cmask.
511*7513SDarren.Reed@Sun.COM 		 */
512*7513SDarren.Reed@Sun.COM 		if ((applyfn)(&neti_stack_lock, nts, parent)) {
513*7513SDarren.Reed@Sun.COM 			/* Lock dropped - restart at head */
514*7513SDarren.Reed@Sun.COM 			nts = LIST_FIRST(&neti_stack_list);
515*7513SDarren.Reed@Sun.COM 		} else {
516*7513SDarren.Reed@Sun.COM 			nts = LIST_NEXT(nts, nts_next);
517*7513SDarren.Reed@Sun.COM 		}
518*7513SDarren.Reed@Sun.COM 	}
519*7513SDarren.Reed@Sun.COM }
520*7513SDarren.Reed@Sun.COM 
521*7513SDarren.Reed@Sun.COM static boolean_t
522*7513SDarren.Reed@Sun.COM neti_stack_apply_create(kmutex_t *lockp, neti_stack_t *nts, void *parent)
523*7513SDarren.Reed@Sun.COM {
524*7513SDarren.Reed@Sun.COM 	void *result;
525*7513SDarren.Reed@Sun.COM 	boolean_t dropped = B_FALSE;
526*7513SDarren.Reed@Sun.COM 	net_instance_int_t *tmp;
527*7513SDarren.Reed@Sun.COM 	net_instance_t *nin;
528*7513SDarren.Reed@Sun.COM 
529*7513SDarren.Reed@Sun.COM 	ASSERT(parent != NULL);
530*7513SDarren.Reed@Sun.COM 	ASSERT(lockp != NULL);
531*7513SDarren.Reed@Sun.COM 	ASSERT(mutex_owned(lockp));
532*7513SDarren.Reed@Sun.COM 
533*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
534*7513SDarren.Reed@Sun.COM 
535*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
536*7513SDarren.Reed@Sun.COM 		if (tmp->nini_parent == parent)
537*7513SDarren.Reed@Sun.COM 			break;
538*7513SDarren.Reed@Sun.COM 	}
539*7513SDarren.Reed@Sun.COM 	if (tmp == NULL) {
540*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
541*7513SDarren.Reed@Sun.COM 		return (dropped);
542*7513SDarren.Reed@Sun.COM 	}
543*7513SDarren.Reed@Sun.COM 
544*7513SDarren.Reed@Sun.COM 	if (wait_for_nini_inprogress(nts, lockp, tmp, 0))
545*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
546*7513SDarren.Reed@Sun.COM 
547*7513SDarren.Reed@Sun.COM 	if (tmp->nini_flags & NSS_CREATE_NEEDED) {
548*7513SDarren.Reed@Sun.COM 		nin = tmp->nini_instance;
549*7513SDarren.Reed@Sun.COM 		tmp->nini_flags &= ~NSS_CREATE_NEEDED;
550*7513SDarren.Reed@Sun.COM 		tmp->nini_flags |= NSS_CREATE_INPROGRESS;
551*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__create__inprogress,
552*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, tmp);
553*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
554*7513SDarren.Reed@Sun.COM 		mutex_exit(lockp);
555*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
556*7513SDarren.Reed@Sun.COM 
557*7513SDarren.Reed@Sun.COM 		ASSERT(tmp->nini_created == NULL);
558*7513SDarren.Reed@Sun.COM 		ASSERT(nin->nin_create != NULL);
559*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__create__start,
560*7513SDarren.Reed@Sun.COM 		    netstackid_t, nts->nts_id,
561*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts);
562*7513SDarren.Reed@Sun.COM 		result = (nin->nin_create)(nts->nts_id);
563*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__create__end,
564*7513SDarren.Reed@Sun.COM 		    void *, result, neti_stack_t *, nts);
565*7513SDarren.Reed@Sun.COM 
566*7513SDarren.Reed@Sun.COM 		ASSERT(result != NULL);
567*7513SDarren.Reed@Sun.COM 		mutex_enter(lockp);
568*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
569*7513SDarren.Reed@Sun.COM 		tmp->nini_created = result;
570*7513SDarren.Reed@Sun.COM 		tmp->nini_flags &= ~NSS_CREATE_INPROGRESS;
571*7513SDarren.Reed@Sun.COM 		tmp->nini_flags |= NSS_CREATE_COMPLETED;
572*7513SDarren.Reed@Sun.COM 		cv_broadcast(&tmp->nini_cv);
573*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__create__completed,
574*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, tmp);
575*7513SDarren.Reed@Sun.COM 	}
576*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
577*7513SDarren.Reed@Sun.COM 	return (dropped);
578*7513SDarren.Reed@Sun.COM }
579*7513SDarren.Reed@Sun.COM 
580*7513SDarren.Reed@Sun.COM 
581*7513SDarren.Reed@Sun.COM static boolean_t
582*7513SDarren.Reed@Sun.COM neti_stack_apply_shutdown(kmutex_t *lockp, neti_stack_t *nts, void *parent)
583*7513SDarren.Reed@Sun.COM {
584*7513SDarren.Reed@Sun.COM 	boolean_t dropped = B_FALSE;
585*7513SDarren.Reed@Sun.COM 	net_instance_int_t *tmp;
586*7513SDarren.Reed@Sun.COM 	net_instance_t *nin;
587*7513SDarren.Reed@Sun.COM 
588*7513SDarren.Reed@Sun.COM 	ASSERT(parent != NULL);
589*7513SDarren.Reed@Sun.COM 	ASSERT(lockp != NULL);
590*7513SDarren.Reed@Sun.COM 	ASSERT(mutex_owned(lockp));
591*7513SDarren.Reed@Sun.COM 
592*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
593*7513SDarren.Reed@Sun.COM 
594*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
595*7513SDarren.Reed@Sun.COM 		if (tmp->nini_parent == parent)
596*7513SDarren.Reed@Sun.COM 			break;
597*7513SDarren.Reed@Sun.COM 	}
598*7513SDarren.Reed@Sun.COM 	if (tmp == NULL) {
599*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
600*7513SDarren.Reed@Sun.COM 		return (dropped);
601*7513SDarren.Reed@Sun.COM 	}
602*7513SDarren.Reed@Sun.COM 
603*7513SDarren.Reed@Sun.COM 	if (wait_for_nini_inprogress(nts, lockp, tmp, NSS_CREATE_NEEDED))
604*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
605*7513SDarren.Reed@Sun.COM 
606*7513SDarren.Reed@Sun.COM 	nin = tmp->nini_instance;
607*7513SDarren.Reed@Sun.COM 	if (nin->nin_shutdown == NULL) {
608*7513SDarren.Reed@Sun.COM 		/*
609*7513SDarren.Reed@Sun.COM 		 * If there is no shutdown function, fake having completed it.
610*7513SDarren.Reed@Sun.COM 		 */
611*7513SDarren.Reed@Sun.COM 		if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) {
612*7513SDarren.Reed@Sun.COM 			tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
613*7513SDarren.Reed@Sun.COM 			tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
614*7513SDarren.Reed@Sun.COM 		}
615*7513SDarren.Reed@Sun.COM 
616*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
617*7513SDarren.Reed@Sun.COM 		return (dropped);
618*7513SDarren.Reed@Sun.COM 	}
619*7513SDarren.Reed@Sun.COM 
620*7513SDarren.Reed@Sun.COM 	if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) {
621*7513SDarren.Reed@Sun.COM 		ASSERT((tmp->nini_flags & NSS_CREATE_COMPLETED) != 0);
622*7513SDarren.Reed@Sun.COM 		tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
623*7513SDarren.Reed@Sun.COM 		tmp->nini_flags |= NSS_SHUTDOWN_INPROGRESS;
624*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__shutdown__inprogress,
625*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, tmp);
626*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
627*7513SDarren.Reed@Sun.COM 		mutex_exit(lockp);
628*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
629*7513SDarren.Reed@Sun.COM 
630*7513SDarren.Reed@Sun.COM 		ASSERT(nin->nin_shutdown != NULL);
631*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__shutdown__start,
632*7513SDarren.Reed@Sun.COM 		    netstackid_t, nts->nts_id,
633*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts);
634*7513SDarren.Reed@Sun.COM 		(nin->nin_shutdown)(nts->nts_id, tmp->nini_created);
635*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE1(neti__stack__shutdown__end,
636*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts);
637*7513SDarren.Reed@Sun.COM 
638*7513SDarren.Reed@Sun.COM 		mutex_enter(lockp);
639*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
640*7513SDarren.Reed@Sun.COM 		tmp->nini_flags &= ~NSS_SHUTDOWN_INPROGRESS;
641*7513SDarren.Reed@Sun.COM 		tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
642*7513SDarren.Reed@Sun.COM 		cv_broadcast(&tmp->nini_cv);
643*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__shutdown__completed,
644*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, tmp);
645*7513SDarren.Reed@Sun.COM 	}
646*7513SDarren.Reed@Sun.COM 	ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
647*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
648*7513SDarren.Reed@Sun.COM 	return (dropped);
649*7513SDarren.Reed@Sun.COM }
650*7513SDarren.Reed@Sun.COM 
651*7513SDarren.Reed@Sun.COM static boolean_t
652*7513SDarren.Reed@Sun.COM neti_stack_apply_destroy(kmutex_t *lockp, neti_stack_t *nts, void *parent)
653*7513SDarren.Reed@Sun.COM {
654*7513SDarren.Reed@Sun.COM 	boolean_t dropped = B_FALSE;
655*7513SDarren.Reed@Sun.COM 	net_instance_int_t *tmp;
656*7513SDarren.Reed@Sun.COM 	net_instance_t *nin;
657*7513SDarren.Reed@Sun.COM 
658*7513SDarren.Reed@Sun.COM 	ASSERT(parent != NULL);
659*7513SDarren.Reed@Sun.COM 	ASSERT(lockp != NULL);
660*7513SDarren.Reed@Sun.COM 	ASSERT(mutex_owned(lockp));
661*7513SDarren.Reed@Sun.COM 
662*7513SDarren.Reed@Sun.COM 	mutex_enter(&nts->nts_lock);
663*7513SDarren.Reed@Sun.COM 
664*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
665*7513SDarren.Reed@Sun.COM 		if (tmp->nini_parent == parent)
666*7513SDarren.Reed@Sun.COM 			break;
667*7513SDarren.Reed@Sun.COM 	}
668*7513SDarren.Reed@Sun.COM 	if (tmp == NULL) {
669*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
670*7513SDarren.Reed@Sun.COM 		return (dropped);
671*7513SDarren.Reed@Sun.COM 	}
672*7513SDarren.Reed@Sun.COM 
673*7513SDarren.Reed@Sun.COM 	/*
674*7513SDarren.Reed@Sun.COM 	 * We pause here so that when we continue we know that we're the
675*7513SDarren.Reed@Sun.COM 	 * only one doing anything active with this node.
676*7513SDarren.Reed@Sun.COM 	 */
677*7513SDarren.Reed@Sun.COM 	if (wait_for_nini_inprogress(nts, lockp, tmp,
678*7513SDarren.Reed@Sun.COM 	    NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED))
679*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
680*7513SDarren.Reed@Sun.COM 
681*7513SDarren.Reed@Sun.COM 	if (tmp->nini_flags & NSS_DESTROY_NEEDED) {
682*7513SDarren.Reed@Sun.COM 		ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
683*7513SDarren.Reed@Sun.COM 		nin = tmp->nini_instance;
684*7513SDarren.Reed@Sun.COM 		tmp->nini_flags &= ~NSS_DESTROY_NEEDED;
685*7513SDarren.Reed@Sun.COM 		tmp->nini_flags |= NSS_DESTROY_INPROGRESS;
686*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__destroy__inprogress,
687*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, tmp);
688*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
689*7513SDarren.Reed@Sun.COM 		mutex_exit(lockp);
690*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
691*7513SDarren.Reed@Sun.COM 
692*7513SDarren.Reed@Sun.COM 		ASSERT(nin->nin_destroy != NULL);
693*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__destroy__start,
694*7513SDarren.Reed@Sun.COM 		    netstackid_t, nts->nts_id,
695*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts);
696*7513SDarren.Reed@Sun.COM 		(nin->nin_destroy)(nts->nts_id, tmp->nini_created);
697*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE1(neti__stack__destroy__end,
698*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts);
699*7513SDarren.Reed@Sun.COM 
700*7513SDarren.Reed@Sun.COM 		mutex_enter(lockp);
701*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
702*7513SDarren.Reed@Sun.COM 		tmp->nini_flags &= ~NSS_DESTROY_INPROGRESS;
703*7513SDarren.Reed@Sun.COM 		tmp->nini_flags |= NSS_DESTROY_COMPLETED;
704*7513SDarren.Reed@Sun.COM 		cv_broadcast(&tmp->nini_cv);
705*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(neti__stack__destroy__completed,
706*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, tmp);
707*7513SDarren.Reed@Sun.COM 	}
708*7513SDarren.Reed@Sun.COM 	mutex_exit(&nts->nts_lock);
709*7513SDarren.Reed@Sun.COM 	return (dropped);
710*7513SDarren.Reed@Sun.COM }
711*7513SDarren.Reed@Sun.COM 
712*7513SDarren.Reed@Sun.COM static boolean_t
713*7513SDarren.Reed@Sun.COM wait_for_nini_inprogress(neti_stack_t *nts, kmutex_t *lockp,
714*7513SDarren.Reed@Sun.COM     net_instance_int_t *nini, uint32_t cmask)
715*7513SDarren.Reed@Sun.COM {
716*7513SDarren.Reed@Sun.COM 	boolean_t dropped = B_FALSE;
717*7513SDarren.Reed@Sun.COM 
718*7513SDarren.Reed@Sun.COM 	ASSERT(lockp != NULL);
719*7513SDarren.Reed@Sun.COM 	ASSERT(mutex_owned(lockp));
720*7513SDarren.Reed@Sun.COM 
721*7513SDarren.Reed@Sun.COM 	while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) {
722*7513SDarren.Reed@Sun.COM 		DTRACE_PROBE2(netstack__wait__nms__inprogress,
723*7513SDarren.Reed@Sun.COM 		    neti_stack_t *, nts, net_instance_int_t *, nini);
724*7513SDarren.Reed@Sun.COM 		dropped = B_TRUE;
725*7513SDarren.Reed@Sun.COM 		mutex_exit(lockp);
726*7513SDarren.Reed@Sun.COM 
727*7513SDarren.Reed@Sun.COM 		cv_wait(&nini->nini_cv, &nts->nts_lock);
728*7513SDarren.Reed@Sun.COM 
729*7513SDarren.Reed@Sun.COM 		/* First drop netstack_lock to preserve order */
730*7513SDarren.Reed@Sun.COM 		mutex_exit(&nts->nts_lock);
731*7513SDarren.Reed@Sun.COM 		mutex_enter(lockp);
732*7513SDarren.Reed@Sun.COM 		mutex_enter(&nts->nts_lock);
733*7513SDarren.Reed@Sun.COM 	}
734*7513SDarren.Reed@Sun.COM 	return (dropped);
735*7513SDarren.Reed@Sun.COM }
736*7513SDarren.Reed@Sun.COM 
737*7513SDarren.Reed@Sun.COM /* ======================================================================= */
738*7513SDarren.Reed@Sun.COM 
739*7513SDarren.Reed@Sun.COM netid_t
740*7513SDarren.Reed@Sun.COM net_zoneidtonetid(zoneid_t zoneid)
741*7513SDarren.Reed@Sun.COM {
742*7513SDarren.Reed@Sun.COM 
743*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
744*7513SDarren.Reed@Sun.COM 
745*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
746*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
747*7513SDarren.Reed@Sun.COM 		if (nts->nts_zoneid == zoneid) {
748*7513SDarren.Reed@Sun.COM 			mutex_exit(&neti_stack_lock);
749*7513SDarren.Reed@Sun.COM 			return (nts->nts_id);
750*7513SDarren.Reed@Sun.COM 		}
751*7513SDarren.Reed@Sun.COM 	}
752*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
753*7513SDarren.Reed@Sun.COM 
754*7513SDarren.Reed@Sun.COM 	return (-1);
755*7513SDarren.Reed@Sun.COM }
756*7513SDarren.Reed@Sun.COM 
757*7513SDarren.Reed@Sun.COM zoneid_t
758*7513SDarren.Reed@Sun.COM net_getzoneidbynetid(netid_t netid)
759*7513SDarren.Reed@Sun.COM {
760*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
761*7513SDarren.Reed@Sun.COM 
762*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
763*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
764*7513SDarren.Reed@Sun.COM 		if (nts->nts_id == netid) {
765*7513SDarren.Reed@Sun.COM 			mutex_exit(&neti_stack_lock);
766*7513SDarren.Reed@Sun.COM 			return (nts->nts_zoneid);
767*7513SDarren.Reed@Sun.COM 		}
768*7513SDarren.Reed@Sun.COM 	}
769*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
770*7513SDarren.Reed@Sun.COM 
771*7513SDarren.Reed@Sun.COM 	return (-1);
772*7513SDarren.Reed@Sun.COM }
773*7513SDarren.Reed@Sun.COM 
774*7513SDarren.Reed@Sun.COM netstackid_t
775*7513SDarren.Reed@Sun.COM net_getnetstackidbynetid(netid_t netid)
776*7513SDarren.Reed@Sun.COM {
777*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
778*7513SDarren.Reed@Sun.COM 
779*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
780*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
781*7513SDarren.Reed@Sun.COM 		if (nts->nts_id == netid) {
782*7513SDarren.Reed@Sun.COM 			mutex_exit(&neti_stack_lock);
783*7513SDarren.Reed@Sun.COM 			return (nts->nts_stackid);
784*7513SDarren.Reed@Sun.COM 		}
785*7513SDarren.Reed@Sun.COM 	}
786*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
787*7513SDarren.Reed@Sun.COM 
788*7513SDarren.Reed@Sun.COM 	return (-1);
789*7513SDarren.Reed@Sun.COM }
790*7513SDarren.Reed@Sun.COM 
791*7513SDarren.Reed@Sun.COM netid_t
792*7513SDarren.Reed@Sun.COM net_getnetidbynetstackid(netstackid_t netstackid)
793*7513SDarren.Reed@Sun.COM {
794*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
795*7513SDarren.Reed@Sun.COM 
796*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
797*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
798*7513SDarren.Reed@Sun.COM 		if (nts->nts_stackid == netstackid) {
799*7513SDarren.Reed@Sun.COM 			mutex_exit(&neti_stack_lock);
800*7513SDarren.Reed@Sun.COM 			return (nts->nts_id);
801*7513SDarren.Reed@Sun.COM 		}
802*7513SDarren.Reed@Sun.COM 	}
803*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
804*7513SDarren.Reed@Sun.COM 
805*7513SDarren.Reed@Sun.COM 	return (-1);
806*7513SDarren.Reed@Sun.COM }
807*7513SDarren.Reed@Sun.COM 
808*7513SDarren.Reed@Sun.COM neti_stack_t *
809*7513SDarren.Reed@Sun.COM net_getnetistackbyid(netid_t netid)
810*7513SDarren.Reed@Sun.COM {
811*7513SDarren.Reed@Sun.COM 	neti_stack_t *nts;
812*7513SDarren.Reed@Sun.COM 
813*7513SDarren.Reed@Sun.COM 	mutex_enter(&neti_stack_lock);
814*7513SDarren.Reed@Sun.COM 	LIST_FOREACH(nts, &neti_stack_list, nts_next) {
815*7513SDarren.Reed@Sun.COM 		if (nts->nts_id == netid) {
816*7513SDarren.Reed@Sun.COM 			mutex_exit(&neti_stack_lock);
817*7513SDarren.Reed@Sun.COM 			return (nts);
818*7513SDarren.Reed@Sun.COM 		}
819*7513SDarren.Reed@Sun.COM 	}
820*7513SDarren.Reed@Sun.COM 	mutex_exit(&neti_stack_lock);
821*7513SDarren.Reed@Sun.COM 
822*7513SDarren.Reed@Sun.COM 	return (NULL);
823*7513SDarren.Reed@Sun.COM }
824*7513SDarren.Reed@Sun.COM 
825*7513SDarren.Reed@Sun.COM int
826*7513SDarren.Reed@Sun.COM net_instance_notify_register(netid_t netid, hook_notify_fn_t callback,
827*7513SDarren.Reed@Sun.COM     void *arg)
828*7513SDarren.Reed@Sun.COM {
829*7513SDarren.Reed@Sun.COM 
830*7513SDarren.Reed@Sun.COM 	return (hook_stack_notify_register(net_getnetstackidbynetid(netid),
831*7513SDarren.Reed@Sun.COM 	    callback, arg));
832*7513SDarren.Reed@Sun.COM }
833*7513SDarren.Reed@Sun.COM 
834*7513SDarren.Reed@Sun.COM int
835*7513SDarren.Reed@Sun.COM net_instance_notify_unregister(netid_t netid, hook_notify_fn_t callback)
836*7513SDarren.Reed@Sun.COM {
837*7513SDarren.Reed@Sun.COM 
838*7513SDarren.Reed@Sun.COM 	return (hook_stack_notify_unregister(net_getnetstackidbynetid(netid),
839*7513SDarren.Reed@Sun.COM 	    callback));
840*7513SDarren.Reed@Sun.COM }
841