blob: 83528b4959cdc3b61e78321499eb2cc4a3b5207d [file] [log] [blame]
Darren Reed7ddc9b12008-09-08 14:46:50 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/param.h>
27#include <sys/atomic.h>
28#include <sys/kmem.h>
29#include <sys/rwlock.h>
30#include <sys/errno.h>
31#include <sys/queue.h>
32#include <sys/sunddi.h>
33#include <inet/common.h>
34#include <inet/led.h>
35#include <inet/ip.h>
36#include <sys/neti.h>
37#include <sys/zone.h>
38#include <sys/sdt.h>
39
40
Darren Reed8ad74182008-10-23 10:33:00 -070041typedef boolean_t napplyfn_t(neti_stack_t *, void *);
Darren Reed7ddc9b12008-09-08 14:46:50 -070042
43static void *neti_stack_init(netstackid_t stackid, netstack_t *ns);
44static void neti_stack_fini(netstackid_t stackid, void *arg);
45static net_instance_int_t *net_instance_int_create(net_instance_t *nin,
46 net_instance_int_t *parent);
47static void neti_stack_shutdown(netstackid_t stackid, void *arg);
48static void net_instance_int_free(net_instance_int_t *nini);
49
Darren Reed8ad74182008-10-23 10:33:00 -070050static boolean_t neti_stack_apply_create(neti_stack_t *, void *);
51static boolean_t neti_stack_apply_destroy(neti_stack_t *, void *);
52static boolean_t neti_stack_apply_shutdown(neti_stack_t *, void *);
Darren Reed7ddc9b12008-09-08 14:46:50 -070053static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *);
54static void neti_apply_all_stacks(void *, napplyfn_t *);
Darren Reed8ad74182008-10-23 10:33:00 -070055static boolean_t wait_for_nini_inprogress(neti_stack_t *,
Darren Reed7ddc9b12008-09-08 14:46:50 -070056 net_instance_int_t *, uint32_t);
57
58static nini_head_t neti_instance_list;
59static neti_stack_head_t neti_stack_list;
60static kmutex_t neti_stack_lock;
61
62void
63neti_init()
64{
65 mutex_init(&neti_stack_lock, NULL, MUTEX_DRIVER, NULL);
66
67 LIST_INIT(&neti_instance_list);
68 LIST_INIT(&neti_stack_list);
69 /*
70 * We want to be informed each time a netstack is created or
71 * destroyed in the kernel.
72 */
73 netstack_register(NS_NETI, neti_stack_init, neti_stack_shutdown,
74 neti_stack_fini);
75}
76
77void
78neti_fini()
79{
80 ASSERT(LIST_EMPTY(&neti_instance_list));
81 ASSERT(LIST_EMPTY(&neti_stack_list));
82
83 netstack_unregister(NS_NETI);
84
85 mutex_destroy(&neti_stack_lock);
86}
87
88/*
89 * Initialize the neti stack instance. Because this is called out of the
90 * netstack framework, it is not possible for it to be called twice with
91 * the same values for (stackid,ns). The same also applies to the other
92 * two functions used with netstack_register: neti_stack_shutdown and
93 * neti_stack_fini.
94 */
95static void *
96neti_stack_init(netstackid_t stackid, netstack_t *ns)
97{
98 net_instance_int_t *dup;
99 net_instance_int_t *n;
100 neti_stack_t *nts;
101
102 nts = kmem_zalloc(sizeof (*nts), KM_SLEEP);
103 LIST_INIT(&nts->nts_instances);
104 nts->nts_id = (netid_t)stackid;
105 nts->nts_stackid = stackid;
106 nts->nts_netstack = ns;
107 nts->nts_zoneid = netstackid_to_zoneid(stackid);
108 nts->nts_flags = NSF_ZONE_CREATE;
109 cv_init(&nts->nts_cv, NULL, CV_DRIVER, NULL);
110 mutex_init(&nts->nts_lock, NULL, MUTEX_DRIVER, NULL);
111
112 mutex_enter(&neti_stack_lock);
113 LIST_INSERT_HEAD(&neti_stack_list, nts, nts_next);
114
115 LIST_FOREACH(n, &neti_instance_list, nini_next) {
116 /*
117 * This function returns with the NSS_CREATE_NEEDED flag
118 * set in "dup", so it is adequately prepared for the
119 * upcoming apply.
120 */
121 dup = net_instance_int_create(n->nini_instance, n);
122
123 mutex_enter(&nts->nts_lock);
124 LIST_INSERT_HEAD(&nts->nts_instances, dup, nini_next);
125 mutex_exit(&nts->nts_lock);
126 }
127
128 neti_apply_all_instances(nts, neti_stack_apply_create);
129
130 mutex_enter(&nts->nts_lock);
131 nts->nts_flags &= ~NSF_ZONE_CREATE;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700132 mutex_exit(&nts->nts_lock);
133
134 mutex_exit(&neti_stack_lock);
135
136 return (nts);
137}
138
139/*
140 * Run the shutdown for all of the hooks.
141 */
142/*ARGSUSED*/
143static void
144neti_stack_shutdown(netstackid_t stackid, void *arg)
145{
146 neti_stack_t *nts = arg;
147 net_instance_int_t *n;
148 struct net_data *nd;
149
150 ASSERT(nts != NULL);
151
152 mutex_enter(&neti_stack_lock);
153 mutex_enter(&nts->nts_lock);
154 /*
155 * Walk through all of the protocol stacks and mark them as shutting
156 * down.
157 */
158 LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
159 nd->netd_condemned = 1;
160 }
161
162 /*
163 * Now proceed to see which callbacks are waiting to hear about the
164 * impending shutdown...
165 */
166 LIST_FOREACH(n, &nts->nts_instances, nini_next) {
167 if (n->nini_instance->nin_shutdown == NULL) {
168 /*
169 * If there is no shutdown function registered,
170 * fake that we have completed it.
171 */
172 n->nini_flags |= NSS_SHUTDOWN_COMPLETED;
173 continue;
174 }
175
176 /*
177 * We need to ensure that we don't try and shutdown something
178 * that is already in the process of being shutdown or
179 * destroyed. If it is still being created, that's ok, the
180 * shtudown flag is added to the mix of things to do.
181 */
182 if ((n->nini_flags & (NSS_DESTROY_ALL|NSS_SHUTDOWN_ALL)) == 0)
183 n->nini_flags |= NSS_SHUTDOWN_NEEDED;
184 }
185 nts->nts_flags |= NSF_ZONE_SHUTDOWN;
186 mutex_exit(&nts->nts_lock);
187
188 neti_apply_all_instances(nts, neti_stack_apply_shutdown);
189
190 mutex_enter(&nts->nts_lock);
191
192 nts->nts_netstack = NULL;
Darren Reed8ad74182008-10-23 10:33:00 -0700193 nts->nts_flags &= ~NSF_ZONE_SHUTDOWN;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700194 mutex_exit(&nts->nts_lock);
195
196 mutex_exit(&neti_stack_lock);
197 ASSERT(nts != NULL);
198}
199
200/*
201 * Free the neti stack instance.
202 * This function relies on the netstack framework only calling the _destroy
203 * callback once for each stackid. The netstack framework also provides us
204 * with assurance that nobody else will be doing any work (_create, _shutdown)
205 * on it, so there is no need to set and use flags to guard against
206 * simultaneous execution (ie. no need to set NSF_CLOSING.)
Darren Reed8ad74182008-10-23 10:33:00 -0700207 * What is required, however, is to make sure that we don't corrupt the
Darren Reed7ddc9b12008-09-08 14:46:50 -0700208 * list of neti_stack_t's for other code that walks it.
209 */
210/*ARGSUSED*/
211static void
212neti_stack_fini(netstackid_t stackid, void *arg)
213{
214 neti_stack_t *nts = arg;
215 net_instance_int_t *n;
216 struct net_data *nd;
217
218 mutex_enter(&neti_stack_lock);
Darren Reed8ad74182008-10-23 10:33:00 -0700219 mutex_enter(&nts->nts_lock);
220
Darren Reed7ddc9b12008-09-08 14:46:50 -0700221 LIST_REMOVE(nts, nts_next);
222
Darren Reed7ddc9b12008-09-08 14:46:50 -0700223 /*
224 * Walk through all of the protocol stacks and mark them as being
225 * destroyed.
226 */
227 LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
228 nd->netd_condemned = 2;
229 }
230
231 LIST_FOREACH(n, &nts->nts_instances, nini_next) {
232 ASSERT((n->nini_flags & NSS_SHUTDOWN_ALL) != 0);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700233 if ((n->nini_flags & NSS_DESTROY_ALL) == 0)
234 n->nini_flags |= NSS_DESTROY_NEEDED;
235 }
236 mutex_exit(&nts->nts_lock);
237
238 neti_apply_all_instances(nts, neti_stack_apply_destroy);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700239
240 while (!LIST_EMPTY(&nts->nts_instances)) {
241 n = LIST_FIRST(&nts->nts_instances);
242 LIST_REMOVE(n, nini_next);
243
244 net_instance_int_free(n);
245 }
Darren Reed8ad74182008-10-23 10:33:00 -0700246 mutex_exit(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700247
248 ASSERT(LIST_EMPTY(&nts->nts_netd_head));
249
250 mutex_destroy(&nts->nts_lock);
251 cv_destroy(&nts->nts_cv);
252
253 kmem_free(nts, sizeof (*nts));
254}
255
256static net_instance_int_t *
257net_instance_int_create(net_instance_t *nin, net_instance_int_t *parent)
258{
259 net_instance_int_t *nini;
260
261 nini = kmem_zalloc(sizeof (net_instance_int_t), KM_SLEEP);
262 nini->nini_instance = nin;
263 nini->nini_parent = parent;
264 if (parent != NULL) {
265 /*
266 * If the parent pointer is non-NULL then we take that as
267 * an indication that the net_instance_int_t is being
268 * created for an active instance and there will expect
269 * the create function to be called. In contrast, if
270 * parent is NULL then this code assumes the object is
271 * being prepared for insertion onto the master list of
272 * callbacks to be called when an instance is created, etc.
273 */
274 parent->nini_ref++;
275 nini->nini_flags |= NSS_CREATE_NEEDED;
276 }
277
278 cv_init(&nini->nini_cv, NULL, CV_DRIVER, NULL);
279
280 return (nini);
281}
282
Darren Reed8ad74182008-10-23 10:33:00 -0700283/*
284 * Free'ing of a net_instance_int_t is only to be done when we know nobody
285 * else has is using it. For both parents and clones, this is indicated by
286 * nini_ref being greater than 0, however, nini_ref is managed differently
287 * for its two uses. For parents, nini_ref is increased when a new clone is
288 * created and it is decremented here. For clones, nini_ref is adjusted by
289 * code elsewhere (e.g. in neti_stack_apply_*) and is not changed here.
290 */
Darren Reed7ddc9b12008-09-08 14:46:50 -0700291static void
292net_instance_int_free(net_instance_int_t *nini)
293{
Darren Reed8ad74182008-10-23 10:33:00 -0700294 /*
295 * This mutex guards the use of nini_ref.
296 */
297 ASSERT(mutex_owned(&neti_stack_lock));
Darren Reed7ddc9b12008-09-08 14:46:50 -0700298
Darren Reed8ad74182008-10-23 10:33:00 -0700299 /*
300 * For 'parent' structures, nini_ref will drop to 0 when
301 * the last clone has been free'd... but for clones, it
302 * is possible for nini_ref to be non-zero if we get in
303 * here when all the locks have been given up to execute
304 * a callback or wait_for_nini_inprogress. In that case,
305 * we do not want to free the structure and just indicate
306 * that it is on the "doomed" list, thus we set the
307 * condemned flag.
308 */
309 if (nini->nini_parent != NULL) {
310 if (nini->nini_ref > 0)
311 nini->nini_condemned = B_TRUE;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700312 nini->nini_parent->nini_ref--;
Darren Reed8ad74182008-10-23 10:33:00 -0700313 if (nini->nini_parent->nini_ref == 0)
314 net_instance_int_free(nini->nini_parent);
315 nini->nini_parent = NULL;
316 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700317
Darren Reed8ad74182008-10-23 10:33:00 -0700318 if (nini->nini_ref == 0) {
319 cv_destroy(&nini->nini_cv);
320 kmem_free(nini, sizeof (*nini));
321 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700322}
323
324net_instance_t *
325net_instance_alloc(const int version)
326{
327 net_instance_t *nin;
328
329 if (version != NETINFO_VERSION)
330 return (NULL);
331
332 nin = kmem_zalloc(sizeof (net_instance_t), KM_SLEEP);
333 nin->nin_version = version;
334
335 return (nin);
336}
337
338void
339net_instance_free(net_instance_t *nin)
340{
341 kmem_free(nin, sizeof (*nin));
342}
343
344int
345net_instance_register(net_instance_t *nin)
346{
347 net_instance_int_t *parent;
348 net_instance_int_t *tmp;
349 neti_stack_t *nts;
350
351 ASSERT(nin->nin_name != NULL);
352
353 if (nin->nin_create == NULL || nin->nin_destroy == NULL)
354 return (DDI_FAILURE);
355
356 mutex_enter(&neti_stack_lock);
357 /*
358 * Search for duplicate, either on the global list or on any
359 * of the known instances.
360 */
361 LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
362 if (strcmp(nin->nin_name, tmp->nini_instance->nin_name) == 0) {
363 mutex_exit(&neti_stack_lock);
364 return (DDI_FAILURE);
365 }
366 }
367
368 /*
369 * Now insert and activate.
370 */
371 parent = net_instance_int_create(nin, NULL);
372 ASSERT(parent != NULL);
373 LIST_INSERT_HEAD(&neti_instance_list, parent, nini_next);
374
375 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
376 mutex_enter(&nts->nts_lock);
377 /*
378 * If shutdown of the zone has begun then do not add a new
379 * instance of the object being registered.
380 */
381 if ((nts->nts_flags & NSF_ZONE_SHUTDOWN) ||
382 (nts->nts_netstack == NULL)) {
383 mutex_exit(&nts->nts_lock);
384 continue;
385 }
Darren Reed8ad74182008-10-23 10:33:00 -0700386
Darren Reed7ddc9b12008-09-08 14:46:50 -0700387 /*
388 * This function returns with the NSS_CREATE_NEEDED flag
389 * set in "dup", so it is adequately prepared for the
390 * upcoming apply.
391 */
392 tmp = net_instance_int_create(nin, parent);
393 ASSERT(tmp != NULL);
394 LIST_INSERT_HEAD(&nts->nts_instances, tmp, nini_next);
395 mutex_exit(&nts->nts_lock);
396
397 }
398
399 neti_apply_all_stacks(parent, neti_stack_apply_create);
400 mutex_exit(&neti_stack_lock);
401
402 return (DDI_SUCCESS);
403}
404
405/*
406 * While net_instance_register() isn't likely to be racing against itself,
407 * net_instance_unregister() can be entered from various directions that
408 * can compete: shutdown of a zone, unloading of a module (and it calling
409 * _unregister() as part of that) and the module doing an _unregister()
410 * anyway.
411 */
412int
413net_instance_unregister(net_instance_t *nin)
414{
415 net_instance_int_t *parent;
416 net_instance_int_t *tmp;
417 neti_stack_t *nts;
418
419 mutex_enter(&neti_stack_lock);
420
421 LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
422 if (strcmp(tmp->nini_instance->nin_name, nin->nin_name) == 0) {
423 LIST_REMOVE(tmp, nini_next);
424 break;
425 }
426 }
427
428 if (tmp == NULL) {
429 mutex_exit(&neti_stack_lock);
430 return (DDI_FAILURE);
431 }
432 parent = tmp;
433
434 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
435 mutex_enter(&nts->nts_lock);
436 LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
437 if (tmp->nini_parent != parent)
438 continue;
439 /*
440 * Netstack difference:
441 * In netstack.c, there is a check for
442 * NSS_CREATE_COMPLETED before setting the other
443 * _NEEDED flags. If we consider that a list
444 * member must always have at least the _CREATE_NEEDED
445 * flag set and that wait_for_nini_inprogress will
446 * also wait for that flag to be cleared in both of
447 * the shutdown and destroy apply functions.
448 *
449 * It is possible to optimize out the case where
450 * all three _NEEDED flags are set to being able
451 * to pretend everything has been done and just
452 * set all three _COMPLETE flags. This makes a
453 * special case that we then need to consider in
454 * other locations, so for the sake of simplicity,
455 * we leave it as it is.
456 */
457 if ((tmp->nini_flags & NSS_SHUTDOWN_ALL) == 0)
458 tmp->nini_flags |= NSS_SHUTDOWN_NEEDED;
459 if ((tmp->nini_flags & NSS_DESTROY_ALL) == 0)
460 tmp->nini_flags |= NSS_DESTROY_NEEDED;
Darren Reed8ad74182008-10-23 10:33:00 -0700461 break;
Darren Reed7ddc9b12008-09-08 14:46:50 -0700462 }
463 mutex_exit(&nts->nts_lock);
464 }
465
466 /*
467 * Each of these functions ensures that the requisite _COMPLETED
468 * flag is present before calling the apply function. So we are
469 * guaranteed to have NSS_CREATE_COMPLETED|NSS_SHUTDOWN_COMPLETED
470 * both set after the first call here and when the second completes,
471 * NSS_DESTROY_COMPLETED is also set.
472 */
473 neti_apply_all_stacks(parent, neti_stack_apply_shutdown);
474 neti_apply_all_stacks(parent, neti_stack_apply_destroy);
475
476 /*
477 * Remove the instance callback information from each stack.
478 */
479 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
480 mutex_enter(&nts->nts_lock);
481 LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
482 if ((tmp->nini_parent == parent) &&
483 (tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) &&
484 (tmp->nini_flags & NSS_DESTROY_COMPLETED)) {
485 /*
486 * There should only be one entry that has a
487 * matching nini_parent so there is no need to
488 * worry about continuing a loop where we are
489 * free'ing the structure holding the 'next'
490 * pointer.
491 */
492 LIST_REMOVE(tmp, nini_next);
493 net_instance_int_free(tmp);
494 break;
495 }
496 }
497 mutex_exit(&nts->nts_lock);
498 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700499
Darren Reed8ad74182008-10-23 10:33:00 -0700500 mutex_exit(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700501
502 return (DDI_SUCCESS);
503}
504
505static void
506neti_apply_all_instances(neti_stack_t *nts, napplyfn_t *applyfn)
507{
508 net_instance_int_t *n;
509
510 ASSERT(mutex_owned(&neti_stack_lock));
511
512 n = LIST_FIRST(&nts->nts_instances);
513 while (n != NULL) {
Darren Reed8ad74182008-10-23 10:33:00 -0700514 if ((applyfn)(nts, n->nini_parent)) {
Darren Reed7ddc9b12008-09-08 14:46:50 -0700515 /* Lock dropped - restart at head */
516 n = LIST_FIRST(&nts->nts_instances);
517 } else {
518 n = LIST_NEXT(n, nini_next);
519 }
520 }
521}
522
523static void
524neti_apply_all_stacks(void *parent, napplyfn_t *applyfn)
525{
526 neti_stack_t *nts;
527
528 ASSERT(mutex_owned(&neti_stack_lock));
529
530 nts = LIST_FIRST(&neti_stack_list);
531 while (nts != NULL) {
532 /*
533 * This function differs, in that it doesn't have a call to
534 * a "wait_creator" call, from the zsd/netstack code. The
535 * waiting is pushed into the apply functions which cause
536 * the waiting to be done in wait_for_nini_progress with
537 * the passing in of cmask.
538 */
Darren Reed8ad74182008-10-23 10:33:00 -0700539 if ((applyfn)(nts, parent)) {
Darren Reed7ddc9b12008-09-08 14:46:50 -0700540 /* Lock dropped - restart at head */
541 nts = LIST_FIRST(&neti_stack_list);
542 } else {
543 nts = LIST_NEXT(nts, nts_next);
544 }
545 }
546}
547
548static boolean_t
Darren Reed8ad74182008-10-23 10:33:00 -0700549neti_stack_apply_create(neti_stack_t *nts, void *parent)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700550{
551 void *result;
552 boolean_t dropped = B_FALSE;
553 net_instance_int_t *tmp;
554 net_instance_t *nin;
555
556 ASSERT(parent != NULL);
Darren Reed8ad74182008-10-23 10:33:00 -0700557 ASSERT(mutex_owned(&neti_stack_lock));
Darren Reed7ddc9b12008-09-08 14:46:50 -0700558
559 mutex_enter(&nts->nts_lock);
560
561 LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
562 if (tmp->nini_parent == parent)
563 break;
564 }
565 if (tmp == NULL) {
566 mutex_exit(&nts->nts_lock);
567 return (dropped);
568 }
569
Darren Reed8ad74182008-10-23 10:33:00 -0700570 tmp->nini_ref++;
571
572 if (wait_for_nini_inprogress(nts, tmp, 0))
Darren Reed7ddc9b12008-09-08 14:46:50 -0700573 dropped = B_TRUE;
574
Darren Reed8ad74182008-10-23 10:33:00 -0700575 if ((tmp->nini_flags & NSS_CREATE_NEEDED) && !tmp->nini_condemned) {
Darren Reed7ddc9b12008-09-08 14:46:50 -0700576 nin = tmp->nini_instance;
577 tmp->nini_flags &= ~NSS_CREATE_NEEDED;
578 tmp->nini_flags |= NSS_CREATE_INPROGRESS;
579 DTRACE_PROBE2(neti__stack__create__inprogress,
580 neti_stack_t *, nts, net_instance_int_t *, tmp);
581 mutex_exit(&nts->nts_lock);
Darren Reed8ad74182008-10-23 10:33:00 -0700582 mutex_exit(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700583 dropped = B_TRUE;
584
585 ASSERT(tmp->nini_created == NULL);
586 ASSERT(nin->nin_create != NULL);
587 DTRACE_PROBE2(neti__stack__create__start,
588 netstackid_t, nts->nts_id,
589 neti_stack_t *, nts);
590 result = (nin->nin_create)(nts->nts_id);
591 DTRACE_PROBE2(neti__stack__create__end,
592 void *, result, neti_stack_t *, nts);
593
594 ASSERT(result != NULL);
Darren Reed8ad74182008-10-23 10:33:00 -0700595 mutex_enter(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700596 mutex_enter(&nts->nts_lock);
597 tmp->nini_created = result;
598 tmp->nini_flags &= ~NSS_CREATE_INPROGRESS;
599 tmp->nini_flags |= NSS_CREATE_COMPLETED;
600 cv_broadcast(&tmp->nini_cv);
601 DTRACE_PROBE2(neti__stack__create__completed,
602 neti_stack_t *, nts, net_instance_int_t *, tmp);
603 }
Darren Reed8ad74182008-10-23 10:33:00 -0700604 tmp->nini_ref--;
605
606 if (tmp->nini_condemned) {
607 net_instance_int_free(tmp);
608 dropped = B_TRUE;
609 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700610 mutex_exit(&nts->nts_lock);
611 return (dropped);
612}
613
614
615static boolean_t
Darren Reed8ad74182008-10-23 10:33:00 -0700616neti_stack_apply_shutdown(neti_stack_t *nts, void *parent)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700617{
618 boolean_t dropped = B_FALSE;
619 net_instance_int_t *tmp;
620 net_instance_t *nin;
621
622 ASSERT(parent != NULL);
Darren Reed8ad74182008-10-23 10:33:00 -0700623 ASSERT(mutex_owned(&neti_stack_lock));
Darren Reed7ddc9b12008-09-08 14:46:50 -0700624
625 mutex_enter(&nts->nts_lock);
626
627 LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
628 if (tmp->nini_parent == parent)
629 break;
630 }
631 if (tmp == NULL) {
632 mutex_exit(&nts->nts_lock);
633 return (dropped);
634 }
Darren Reed8ad74182008-10-23 10:33:00 -0700635 ASSERT((tmp->nini_flags & NSS_SHUTDOWN_ALL) != 0);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700636
Darren Reed8ad74182008-10-23 10:33:00 -0700637 tmp->nini_ref++;
638
639 if (wait_for_nini_inprogress(nts, tmp, NSS_CREATE_NEEDED))
Darren Reed7ddc9b12008-09-08 14:46:50 -0700640 dropped = B_TRUE;
641
642 nin = tmp->nini_instance;
643 if (nin->nin_shutdown == NULL) {
644 /*
645 * If there is no shutdown function, fake having completed it.
646 */
647 if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) {
648 tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
649 tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
650 }
Darren Reed8ad74182008-10-23 10:33:00 -0700651 tmp->nini_ref--;
652
653 if (tmp->nini_condemned) {
654 net_instance_int_free(tmp);
655 dropped = B_TRUE;
656 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700657
658 mutex_exit(&nts->nts_lock);
659 return (dropped);
660 }
661
Darren Reed8ad74182008-10-23 10:33:00 -0700662 if ((tmp->nini_flags & NSS_SHUTDOWN_NEEDED) && !tmp->nini_condemned) {
Darren Reed7ddc9b12008-09-08 14:46:50 -0700663 ASSERT((tmp->nini_flags & NSS_CREATE_COMPLETED) != 0);
664 tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
665 tmp->nini_flags |= NSS_SHUTDOWN_INPROGRESS;
666 DTRACE_PROBE2(neti__stack__shutdown__inprogress,
667 neti_stack_t *, nts, net_instance_int_t *, tmp);
668 mutex_exit(&nts->nts_lock);
Darren Reed8ad74182008-10-23 10:33:00 -0700669 mutex_exit(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700670 dropped = B_TRUE;
671
672 ASSERT(nin->nin_shutdown != NULL);
673 DTRACE_PROBE2(neti__stack__shutdown__start,
674 netstackid_t, nts->nts_id,
675 neti_stack_t *, nts);
676 (nin->nin_shutdown)(nts->nts_id, tmp->nini_created);
677 DTRACE_PROBE1(neti__stack__shutdown__end,
678 neti_stack_t *, nts);
679
Darren Reed8ad74182008-10-23 10:33:00 -0700680 mutex_enter(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700681 mutex_enter(&nts->nts_lock);
682 tmp->nini_flags &= ~NSS_SHUTDOWN_INPROGRESS;
683 tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
684 cv_broadcast(&tmp->nini_cv);
685 DTRACE_PROBE2(neti__stack__shutdown__completed,
686 neti_stack_t *, nts, net_instance_int_t *, tmp);
687 }
688 ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
Darren Reed8ad74182008-10-23 10:33:00 -0700689 tmp->nini_ref--;
690
691 if (tmp->nini_condemned) {
692 net_instance_int_free(tmp);
693 dropped = B_TRUE;
694 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700695 mutex_exit(&nts->nts_lock);
696 return (dropped);
697}
698
699static boolean_t
Darren Reed8ad74182008-10-23 10:33:00 -0700700neti_stack_apply_destroy(neti_stack_t *nts, void *parent)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700701{
702 boolean_t dropped = B_FALSE;
703 net_instance_int_t *tmp;
704 net_instance_t *nin;
705
706 ASSERT(parent != NULL);
Darren Reed8ad74182008-10-23 10:33:00 -0700707 ASSERT(mutex_owned(&neti_stack_lock));
Darren Reed7ddc9b12008-09-08 14:46:50 -0700708
709 mutex_enter(&nts->nts_lock);
710
711 LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
712 if (tmp->nini_parent == parent)
713 break;
714 }
715 if (tmp == NULL) {
716 mutex_exit(&nts->nts_lock);
717 return (dropped);
718 }
719
Darren Reed8ad74182008-10-23 10:33:00 -0700720 tmp->nini_ref++;
721
Darren Reed7ddc9b12008-09-08 14:46:50 -0700722 /*
723 * We pause here so that when we continue we know that we're the
724 * only one doing anything active with this node.
725 */
Darren Reed8ad74182008-10-23 10:33:00 -0700726 if (wait_for_nini_inprogress(nts, tmp,
Darren Reed7ddc9b12008-09-08 14:46:50 -0700727 NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED))
728 dropped = B_TRUE;
729
Darren Reed8ad74182008-10-23 10:33:00 -0700730 if ((tmp->nini_flags & NSS_DESTROY_NEEDED) && !tmp->nini_condemned) {
Darren Reed7ddc9b12008-09-08 14:46:50 -0700731 ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
732 nin = tmp->nini_instance;
733 tmp->nini_flags &= ~NSS_DESTROY_NEEDED;
734 tmp->nini_flags |= NSS_DESTROY_INPROGRESS;
735 DTRACE_PROBE2(neti__stack__destroy__inprogress,
736 neti_stack_t *, nts, net_instance_int_t *, tmp);
737 mutex_exit(&nts->nts_lock);
Darren Reed8ad74182008-10-23 10:33:00 -0700738 mutex_exit(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700739 dropped = B_TRUE;
740
741 ASSERT(nin->nin_destroy != NULL);
742 DTRACE_PROBE2(neti__stack__destroy__start,
743 netstackid_t, nts->nts_id,
744 neti_stack_t *, nts);
745 (nin->nin_destroy)(nts->nts_id, tmp->nini_created);
746 DTRACE_PROBE1(neti__stack__destroy__end,
747 neti_stack_t *, nts);
748
Darren Reed8ad74182008-10-23 10:33:00 -0700749 mutex_enter(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700750 mutex_enter(&nts->nts_lock);
751 tmp->nini_flags &= ~NSS_DESTROY_INPROGRESS;
752 tmp->nini_flags |= NSS_DESTROY_COMPLETED;
753 cv_broadcast(&tmp->nini_cv);
754 DTRACE_PROBE2(neti__stack__destroy__completed,
755 neti_stack_t *, nts, net_instance_int_t *, tmp);
756 }
Darren Reed8ad74182008-10-23 10:33:00 -0700757 tmp->nini_ref--;
758
759 if (tmp->nini_condemned) {
760 net_instance_int_free(tmp);
761 dropped = B_TRUE;
762 }
Darren Reed7ddc9b12008-09-08 14:46:50 -0700763 mutex_exit(&nts->nts_lock);
764 return (dropped);
765}
766
767static boolean_t
Darren Reed8ad74182008-10-23 10:33:00 -0700768wait_for_nini_inprogress(neti_stack_t *nts, net_instance_int_t *nini,
769 uint32_t cmask)
Darren Reed7ddc9b12008-09-08 14:46:50 -0700770{
771 boolean_t dropped = B_FALSE;
772
Darren Reed8ad74182008-10-23 10:33:00 -0700773 ASSERT(mutex_owned(&neti_stack_lock));
Darren Reed7ddc9b12008-09-08 14:46:50 -0700774
775 while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) {
Darren Reed8ad74182008-10-23 10:33:00 -0700776 DTRACE_PROBE2(neti__wait__nini__inprogress,
Darren Reed7ddc9b12008-09-08 14:46:50 -0700777 neti_stack_t *, nts, net_instance_int_t *, nini);
778 dropped = B_TRUE;
Darren Reed8ad74182008-10-23 10:33:00 -0700779 mutex_exit(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700780
781 cv_wait(&nini->nini_cv, &nts->nts_lock);
782
783 /* First drop netstack_lock to preserve order */
784 mutex_exit(&nts->nts_lock);
Darren Reed8ad74182008-10-23 10:33:00 -0700785 DTRACE_PROBE2(wait__nini__inprogress__pause,
786 neti_stack_t *, nts, net_instance_int_t *, nini);
787 mutex_enter(&neti_stack_lock);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700788 mutex_enter(&nts->nts_lock);
789 }
Darren Reed8ad74182008-10-23 10:33:00 -0700790 DTRACE_PROBE2(neti__wait__nini__inprogress__complete,
791 neti_stack_t *, nts, net_instance_int_t *, nini);
Darren Reed7ddc9b12008-09-08 14:46:50 -0700792 return (dropped);
793}
794
795/* ======================================================================= */
796
797netid_t
798net_zoneidtonetid(zoneid_t zoneid)
799{
800
801 neti_stack_t *nts;
802
803 mutex_enter(&neti_stack_lock);
804 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
805 if (nts->nts_zoneid == zoneid) {
806 mutex_exit(&neti_stack_lock);
807 return (nts->nts_id);
808 }
809 }
810 mutex_exit(&neti_stack_lock);
811
812 return (-1);
813}
814
815zoneid_t
816net_getzoneidbynetid(netid_t netid)
817{
818 neti_stack_t *nts;
819
820 mutex_enter(&neti_stack_lock);
821 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
822 if (nts->nts_id == netid) {
823 mutex_exit(&neti_stack_lock);
824 return (nts->nts_zoneid);
825 }
826 }
827 mutex_exit(&neti_stack_lock);
828
829 return (-1);
830}
831
832netstackid_t
833net_getnetstackidbynetid(netid_t netid)
834{
835 neti_stack_t *nts;
836
837 mutex_enter(&neti_stack_lock);
838 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
839 if (nts->nts_id == netid) {
840 mutex_exit(&neti_stack_lock);
841 return (nts->nts_stackid);
842 }
843 }
844 mutex_exit(&neti_stack_lock);
845
846 return (-1);
847}
848
849netid_t
850net_getnetidbynetstackid(netstackid_t netstackid)
851{
852 neti_stack_t *nts;
853
854 mutex_enter(&neti_stack_lock);
855 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
856 if (nts->nts_stackid == netstackid) {
857 mutex_exit(&neti_stack_lock);
858 return (nts->nts_id);
859 }
860 }
861 mutex_exit(&neti_stack_lock);
862
863 return (-1);
864}
865
866neti_stack_t *
867net_getnetistackbyid(netid_t netid)
868{
869 neti_stack_t *nts;
870
871 mutex_enter(&neti_stack_lock);
872 LIST_FOREACH(nts, &neti_stack_list, nts_next) {
873 if (nts->nts_id == netid) {
874 mutex_exit(&neti_stack_lock);
875 return (nts);
876 }
877 }
878 mutex_exit(&neti_stack_lock);
879
880 return (NULL);
881}
882
883int
884net_instance_notify_register(netid_t netid, hook_notify_fn_t callback,
885 void *arg)
886{
887
888 return (hook_stack_notify_register(net_getnetstackidbynetid(netid),
889 callback, arg));
890}
891
892int
893net_instance_notify_unregister(netid_t netid, hook_notify_fn_t callback)
894{
895
896 return (hook_stack_notify_unregister(net_getnetstackidbynetid(netid),
897 callback));
898}