Home | History | Annotate | Download | only in io
      1 /*
      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 
     41 typedef boolean_t napplyfn_t(neti_stack_t *, void *);
     42 
     43 static void *neti_stack_init(netstackid_t stackid, netstack_t *ns);
     44 static void neti_stack_fini(netstackid_t stackid, void *arg);
     45 static net_instance_int_t *net_instance_int_create(net_instance_t *nin,
     46     net_instance_int_t *parent);
     47 static void neti_stack_shutdown(netstackid_t stackid, void *arg);
     48 static void net_instance_int_free(net_instance_int_t *nini);
     49 
     50 static boolean_t neti_stack_apply_create(neti_stack_t *, void *);
     51 static boolean_t neti_stack_apply_destroy(neti_stack_t *, void *);
     52 static boolean_t neti_stack_apply_shutdown(neti_stack_t *, void *);
     53 static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *);
     54 static void neti_apply_all_stacks(void *, napplyfn_t *);
     55 static boolean_t wait_for_nini_inprogress(neti_stack_t *,
     56     net_instance_int_t *, uint32_t);
     57 
     58 static nini_head_t neti_instance_list;
     59 static neti_stack_head_t neti_stack_list;
     60 static kmutex_t neti_stack_lock;
     61 
     62 void
     63 neti_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 
     77 void
     78 neti_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  */
     95 static void *
     96 neti_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;
    132 	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*/
    143 static void
    144 neti_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;
    193 	nts->nts_flags &= ~NSF_ZONE_SHUTDOWN;
    194 	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.)
    207  * What is required, however, is to make sure that we don't corrupt the
    208  * list of neti_stack_t's for other code that walks it.
    209  */
    210 /*ARGSUSED*/
    211 static void
    212 neti_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);
    219 	mutex_enter(&nts->nts_lock);
    220 
    221 	LIST_REMOVE(nts, nts_next);
    222 
    223 	/*
    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);
    233 		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);
    239 
    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 	}
    246 	mutex_exit(&neti_stack_lock);
    247 
    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 
    256 static net_instance_int_t *
    257 net_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 
    283 /*
    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  */
    291 static void
    292 net_instance_int_free(net_instance_int_t *nini)
    293 {
    294 	/*
    295 	 * This mutex guards the use of nini_ref.
    296 	 */
    297 	ASSERT(mutex_owned(&neti_stack_lock));
    298 
    299 	/*
    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;
    312 		nini->nini_parent->nini_ref--;
    313 		if (nini->nini_parent->nini_ref == 0)
    314 			net_instance_int_free(nini->nini_parent);
    315 		nini->nini_parent = NULL;
    316 	}
    317 
    318 	if (nini->nini_ref == 0) {
    319 		cv_destroy(&nini->nini_cv);
    320 		kmem_free(nini, sizeof (*nini));
    321 	}
    322 }
    323 
    324 net_instance_t *
    325 net_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 
    338 void
    339 net_instance_free(net_instance_t *nin)
    340 {
    341 	kmem_free(nin, sizeof (*nin));
    342 }
    343 
    344 int
    345 net_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 		}
    386 
    387 		/*
    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  */
    412 int
    413 net_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;
    461 			break;
    462 		}
    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 	}
    499 
    500 	mutex_exit(&neti_stack_lock);
    501 
    502 	return (DDI_SUCCESS);
    503 }
    504 
    505 static void
    506 neti_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) {
    514 		if ((applyfn)(nts, n->nini_parent)) {
    515 			/* 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 
    523 static void
    524 neti_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 		 */
    539 		if ((applyfn)(nts, parent)) {
    540 			/* 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 
    548 static boolean_t
    549 neti_stack_apply_create(neti_stack_t *nts, void *parent)
    550 {
    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);
    557 	ASSERT(mutex_owned(&neti_stack_lock));
    558 
    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 
    570 	tmp->nini_ref++;
    571 
    572 	if (wait_for_nini_inprogress(nts, tmp, 0))
    573 		dropped = B_TRUE;
    574 
    575 	if ((tmp->nini_flags & NSS_CREATE_NEEDED) && !tmp->nini_condemned) {
    576 		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);
    582 		mutex_exit(&neti_stack_lock);
    583 		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);
    595 		mutex_enter(&neti_stack_lock);
    596 		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 	}
    604 	tmp->nini_ref--;
    605 
    606 	if (tmp->nini_condemned) {
    607 		net_instance_int_free(tmp);
    608 		dropped = B_TRUE;
    609 	}
    610 	mutex_exit(&nts->nts_lock);
    611 	return (dropped);
    612 }
    613 
    614 
    615 static boolean_t
    616 neti_stack_apply_shutdown(neti_stack_t *nts, void *parent)
    617 {
    618 	boolean_t dropped = B_FALSE;
    619 	net_instance_int_t *tmp;
    620 	net_instance_t *nin;
    621 
    622 	ASSERT(parent != NULL);
    623 	ASSERT(mutex_owned(&neti_stack_lock));
    624 
    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 	}
    635 	ASSERT((tmp->nini_flags & NSS_SHUTDOWN_ALL) != 0);
    636 
    637 	tmp->nini_ref++;
    638 
    639 	if (wait_for_nini_inprogress(nts, tmp, NSS_CREATE_NEEDED))
    640 		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 		}
    651 		tmp->nini_ref--;
    652 
    653 		if (tmp->nini_condemned) {
    654 			net_instance_int_free(tmp);
    655 			dropped = B_TRUE;
    656 		}
    657 
    658 		mutex_exit(&nts->nts_lock);
    659 		return (dropped);
    660 	}
    661 
    662 	if ((tmp->nini_flags & NSS_SHUTDOWN_NEEDED) && !tmp->nini_condemned) {
    663 		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);
    669 		mutex_exit(&neti_stack_lock);
    670 		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 
    680 		mutex_enter(&neti_stack_lock);
    681 		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);
    689 	tmp->nini_ref--;
    690 
    691 	if (tmp->nini_condemned) {
    692 		net_instance_int_free(tmp);
    693 		dropped = B_TRUE;
    694 	}
    695 	mutex_exit(&nts->nts_lock);
    696 	return (dropped);
    697 }
    698 
    699 static boolean_t
    700 neti_stack_apply_destroy(neti_stack_t *nts, void *parent)
    701 {
    702 	boolean_t dropped = B_FALSE;
    703 	net_instance_int_t *tmp;
    704 	net_instance_t *nin;
    705 
    706 	ASSERT(parent != NULL);
    707 	ASSERT(mutex_owned(&neti_stack_lock));
    708 
    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 
    720 	tmp->nini_ref++;
    721 
    722 	/*
    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 	 */
    726 	if (wait_for_nini_inprogress(nts, tmp,
    727 	    NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED))
    728 		dropped = B_TRUE;
    729 
    730 	if ((tmp->nini_flags & NSS_DESTROY_NEEDED) && !tmp->nini_condemned) {
    731 		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);
    738 		mutex_exit(&neti_stack_lock);
    739 		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 
    749 		mutex_enter(&neti_stack_lock);
    750 		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 	}
    757 	tmp->nini_ref--;
    758 
    759 	if (tmp->nini_condemned) {
    760 		net_instance_int_free(tmp);
    761 		dropped = B_TRUE;
    762 	}
    763 	mutex_exit(&nts->nts_lock);
    764 	return (dropped);
    765 }
    766 
    767 static boolean_t
    768 wait_for_nini_inprogress(neti_stack_t *nts, net_instance_int_t *nini,
    769     uint32_t cmask)
    770 {
    771 	boolean_t dropped = B_FALSE;
    772 
    773 	ASSERT(mutex_owned(&neti_stack_lock));
    774 
    775 	while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) {
    776 		DTRACE_PROBE2(neti__wait__nini__inprogress,
    777 		    neti_stack_t *, nts, net_instance_int_t *, nini);
    778 		dropped = B_TRUE;
    779 		mutex_exit(&neti_stack_lock);
    780 
    781 		cv_wait(&nini->nini_cv, &nts->nts_lock);
    782 
    783 		/* First drop netstack_lock to preserve order */
    784 		mutex_exit(&nts->nts_lock);
    785 		DTRACE_PROBE2(wait__nini__inprogress__pause,
    786 		    neti_stack_t *, nts, net_instance_int_t *, nini);
    787 		mutex_enter(&neti_stack_lock);
    788 		mutex_enter(&nts->nts_lock);
    789 	}
    790 	DTRACE_PROBE2(neti__wait__nini__inprogress__complete,
    791 	    neti_stack_t *, nts, net_instance_int_t *, nini);
    792 	return (dropped);
    793 }
    794 
    795 /* ======================================================================= */
    796 
    797 netid_t
    798 net_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 
    815 zoneid_t
    816 net_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 
    832 netstackid_t
    833 net_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 
    849 netid_t
    850 net_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 
    866 neti_stack_t *
    867 net_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 
    883 int
    884 net_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 
    892 int
    893 net_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 }
    899