17513SDarren.Reed@Sun.COM /*
27513SDarren.Reed@Sun.COM * CDDL HEADER START
37513SDarren.Reed@Sun.COM *
47513SDarren.Reed@Sun.COM * The contents of this file are subject to the terms of the
57513SDarren.Reed@Sun.COM * Common Development and Distribution License (the "License").
67513SDarren.Reed@Sun.COM * You may not use this file except in compliance with the License.
77513SDarren.Reed@Sun.COM *
87513SDarren.Reed@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97513SDarren.Reed@Sun.COM * or http://www.opensolaris.org/os/licensing.
107513SDarren.Reed@Sun.COM * See the License for the specific language governing permissions
117513SDarren.Reed@Sun.COM * and limitations under the License.
127513SDarren.Reed@Sun.COM *
137513SDarren.Reed@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147513SDarren.Reed@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157513SDarren.Reed@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167513SDarren.Reed@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177513SDarren.Reed@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187513SDarren.Reed@Sun.COM *
197513SDarren.Reed@Sun.COM * CDDL HEADER END
207513SDarren.Reed@Sun.COM */
217513SDarren.Reed@Sun.COM /*
227513SDarren.Reed@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237513SDarren.Reed@Sun.COM * Use is subject to license terms.
247513SDarren.Reed@Sun.COM */
257513SDarren.Reed@Sun.COM
267513SDarren.Reed@Sun.COM #include <sys/param.h>
277513SDarren.Reed@Sun.COM #include <sys/atomic.h>
287513SDarren.Reed@Sun.COM #include <sys/kmem.h>
297513SDarren.Reed@Sun.COM #include <sys/rwlock.h>
307513SDarren.Reed@Sun.COM #include <sys/errno.h>
317513SDarren.Reed@Sun.COM #include <sys/queue.h>
327513SDarren.Reed@Sun.COM #include <sys/sunddi.h>
337513SDarren.Reed@Sun.COM #include <inet/common.h>
347513SDarren.Reed@Sun.COM #include <inet/led.h>
357513SDarren.Reed@Sun.COM #include <inet/ip.h>
367513SDarren.Reed@Sun.COM #include <sys/neti.h>
377513SDarren.Reed@Sun.COM #include <sys/zone.h>
387513SDarren.Reed@Sun.COM #include <sys/sdt.h>
397513SDarren.Reed@Sun.COM
407513SDarren.Reed@Sun.COM
41*7915SDarren.Reed@Sun.COM typedef boolean_t napplyfn_t(neti_stack_t *, void *);
427513SDarren.Reed@Sun.COM
437513SDarren.Reed@Sun.COM static void *neti_stack_init(netstackid_t stackid, netstack_t *ns);
447513SDarren.Reed@Sun.COM static void neti_stack_fini(netstackid_t stackid, void *arg);
457513SDarren.Reed@Sun.COM static net_instance_int_t *net_instance_int_create(net_instance_t *nin,
467513SDarren.Reed@Sun.COM net_instance_int_t *parent);
477513SDarren.Reed@Sun.COM static void neti_stack_shutdown(netstackid_t stackid, void *arg);
487513SDarren.Reed@Sun.COM static void net_instance_int_free(net_instance_int_t *nini);
497513SDarren.Reed@Sun.COM
50*7915SDarren.Reed@Sun.COM static boolean_t neti_stack_apply_create(neti_stack_t *, void *);
51*7915SDarren.Reed@Sun.COM static boolean_t neti_stack_apply_destroy(neti_stack_t *, void *);
52*7915SDarren.Reed@Sun.COM static boolean_t neti_stack_apply_shutdown(neti_stack_t *, void *);
537513SDarren.Reed@Sun.COM static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *);
547513SDarren.Reed@Sun.COM static void neti_apply_all_stacks(void *, napplyfn_t *);
55*7915SDarren.Reed@Sun.COM static boolean_t wait_for_nini_inprogress(neti_stack_t *,
567513SDarren.Reed@Sun.COM net_instance_int_t *, uint32_t);
577513SDarren.Reed@Sun.COM
587513SDarren.Reed@Sun.COM static nini_head_t neti_instance_list;
597513SDarren.Reed@Sun.COM static neti_stack_head_t neti_stack_list;
607513SDarren.Reed@Sun.COM static kmutex_t neti_stack_lock;
617513SDarren.Reed@Sun.COM
627513SDarren.Reed@Sun.COM void
neti_init()637513SDarren.Reed@Sun.COM neti_init()
647513SDarren.Reed@Sun.COM {
657513SDarren.Reed@Sun.COM mutex_init(&neti_stack_lock, NULL, MUTEX_DRIVER, NULL);
667513SDarren.Reed@Sun.COM
677513SDarren.Reed@Sun.COM LIST_INIT(&neti_instance_list);
687513SDarren.Reed@Sun.COM LIST_INIT(&neti_stack_list);
697513SDarren.Reed@Sun.COM /*
707513SDarren.Reed@Sun.COM * We want to be informed each time a netstack is created or
717513SDarren.Reed@Sun.COM * destroyed in the kernel.
727513SDarren.Reed@Sun.COM */
737513SDarren.Reed@Sun.COM netstack_register(NS_NETI, neti_stack_init, neti_stack_shutdown,
747513SDarren.Reed@Sun.COM neti_stack_fini);
757513SDarren.Reed@Sun.COM }
767513SDarren.Reed@Sun.COM
777513SDarren.Reed@Sun.COM void
neti_fini()787513SDarren.Reed@Sun.COM neti_fini()
797513SDarren.Reed@Sun.COM {
807513SDarren.Reed@Sun.COM ASSERT(LIST_EMPTY(&neti_instance_list));
817513SDarren.Reed@Sun.COM ASSERT(LIST_EMPTY(&neti_stack_list));
827513SDarren.Reed@Sun.COM
837513SDarren.Reed@Sun.COM netstack_unregister(NS_NETI);
847513SDarren.Reed@Sun.COM
857513SDarren.Reed@Sun.COM mutex_destroy(&neti_stack_lock);
867513SDarren.Reed@Sun.COM }
877513SDarren.Reed@Sun.COM
887513SDarren.Reed@Sun.COM /*
897513SDarren.Reed@Sun.COM * Initialize the neti stack instance. Because this is called out of the
907513SDarren.Reed@Sun.COM * netstack framework, it is not possible for it to be called twice with
917513SDarren.Reed@Sun.COM * the same values for (stackid,ns). The same also applies to the other
927513SDarren.Reed@Sun.COM * two functions used with netstack_register: neti_stack_shutdown and
937513SDarren.Reed@Sun.COM * neti_stack_fini.
947513SDarren.Reed@Sun.COM */
957513SDarren.Reed@Sun.COM static void *
neti_stack_init(netstackid_t stackid,netstack_t * ns)967513SDarren.Reed@Sun.COM neti_stack_init(netstackid_t stackid, netstack_t *ns)
977513SDarren.Reed@Sun.COM {
987513SDarren.Reed@Sun.COM net_instance_int_t *dup;
997513SDarren.Reed@Sun.COM net_instance_int_t *n;
1007513SDarren.Reed@Sun.COM neti_stack_t *nts;
1017513SDarren.Reed@Sun.COM
1027513SDarren.Reed@Sun.COM nts = kmem_zalloc(sizeof (*nts), KM_SLEEP);
1037513SDarren.Reed@Sun.COM LIST_INIT(&nts->nts_instances);
1047513SDarren.Reed@Sun.COM nts->nts_id = (netid_t)stackid;
1057513SDarren.Reed@Sun.COM nts->nts_stackid = stackid;
1067513SDarren.Reed@Sun.COM nts->nts_netstack = ns;
1077513SDarren.Reed@Sun.COM nts->nts_zoneid = netstackid_to_zoneid(stackid);
1087513SDarren.Reed@Sun.COM nts->nts_flags = NSF_ZONE_CREATE;
1097513SDarren.Reed@Sun.COM cv_init(&nts->nts_cv, NULL, CV_DRIVER, NULL);
1107513SDarren.Reed@Sun.COM mutex_init(&nts->nts_lock, NULL, MUTEX_DRIVER, NULL);
1117513SDarren.Reed@Sun.COM
1127513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
1137513SDarren.Reed@Sun.COM LIST_INSERT_HEAD(&neti_stack_list, nts, nts_next);
1147513SDarren.Reed@Sun.COM
1157513SDarren.Reed@Sun.COM LIST_FOREACH(n, &neti_instance_list, nini_next) {
1167513SDarren.Reed@Sun.COM /*
1177513SDarren.Reed@Sun.COM * This function returns with the NSS_CREATE_NEEDED flag
1187513SDarren.Reed@Sun.COM * set in "dup", so it is adequately prepared for the
1197513SDarren.Reed@Sun.COM * upcoming apply.
1207513SDarren.Reed@Sun.COM */
1217513SDarren.Reed@Sun.COM dup = net_instance_int_create(n->nini_instance, n);
1227513SDarren.Reed@Sun.COM
1237513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
1247513SDarren.Reed@Sun.COM LIST_INSERT_HEAD(&nts->nts_instances, dup, nini_next);
1257513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
1267513SDarren.Reed@Sun.COM }
1277513SDarren.Reed@Sun.COM
1287513SDarren.Reed@Sun.COM neti_apply_all_instances(nts, neti_stack_apply_create);
1297513SDarren.Reed@Sun.COM
1307513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
1317513SDarren.Reed@Sun.COM nts->nts_flags &= ~NSF_ZONE_CREATE;
1327513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
1337513SDarren.Reed@Sun.COM
1347513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
1357513SDarren.Reed@Sun.COM
1367513SDarren.Reed@Sun.COM return (nts);
1377513SDarren.Reed@Sun.COM }
1387513SDarren.Reed@Sun.COM
1397513SDarren.Reed@Sun.COM /*
1407513SDarren.Reed@Sun.COM * Run the shutdown for all of the hooks.
1417513SDarren.Reed@Sun.COM */
1427513SDarren.Reed@Sun.COM /*ARGSUSED*/
1437513SDarren.Reed@Sun.COM static void
neti_stack_shutdown(netstackid_t stackid,void * arg)1447513SDarren.Reed@Sun.COM neti_stack_shutdown(netstackid_t stackid, void *arg)
1457513SDarren.Reed@Sun.COM {
1467513SDarren.Reed@Sun.COM neti_stack_t *nts = arg;
1477513SDarren.Reed@Sun.COM net_instance_int_t *n;
1487513SDarren.Reed@Sun.COM struct net_data *nd;
1497513SDarren.Reed@Sun.COM
1507513SDarren.Reed@Sun.COM ASSERT(nts != NULL);
1517513SDarren.Reed@Sun.COM
1527513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
1537513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
1547513SDarren.Reed@Sun.COM /*
1557513SDarren.Reed@Sun.COM * Walk through all of the protocol stacks and mark them as shutting
1567513SDarren.Reed@Sun.COM * down.
1577513SDarren.Reed@Sun.COM */
1587513SDarren.Reed@Sun.COM LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
1597513SDarren.Reed@Sun.COM nd->netd_condemned = 1;
1607513SDarren.Reed@Sun.COM }
1617513SDarren.Reed@Sun.COM
1627513SDarren.Reed@Sun.COM /*
1637513SDarren.Reed@Sun.COM * Now proceed to see which callbacks are waiting to hear about the
1647513SDarren.Reed@Sun.COM * impending shutdown...
1657513SDarren.Reed@Sun.COM */
1667513SDarren.Reed@Sun.COM LIST_FOREACH(n, &nts->nts_instances, nini_next) {
1677513SDarren.Reed@Sun.COM if (n->nini_instance->nin_shutdown == NULL) {
1687513SDarren.Reed@Sun.COM /*
1697513SDarren.Reed@Sun.COM * If there is no shutdown function registered,
1707513SDarren.Reed@Sun.COM * fake that we have completed it.
1717513SDarren.Reed@Sun.COM */
1727513SDarren.Reed@Sun.COM n->nini_flags |= NSS_SHUTDOWN_COMPLETED;
1737513SDarren.Reed@Sun.COM continue;
1747513SDarren.Reed@Sun.COM }
1757513SDarren.Reed@Sun.COM
1767513SDarren.Reed@Sun.COM /*
1777513SDarren.Reed@Sun.COM * We need to ensure that we don't try and shutdown something
1787513SDarren.Reed@Sun.COM * that is already in the process of being shutdown or
1797513SDarren.Reed@Sun.COM * destroyed. If it is still being created, that's ok, the
1807513SDarren.Reed@Sun.COM * shtudown flag is added to the mix of things to do.
1817513SDarren.Reed@Sun.COM */
1827513SDarren.Reed@Sun.COM if ((n->nini_flags & (NSS_DESTROY_ALL|NSS_SHUTDOWN_ALL)) == 0)
1837513SDarren.Reed@Sun.COM n->nini_flags |= NSS_SHUTDOWN_NEEDED;
1847513SDarren.Reed@Sun.COM }
1857513SDarren.Reed@Sun.COM nts->nts_flags |= NSF_ZONE_SHUTDOWN;
1867513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
1877513SDarren.Reed@Sun.COM
1887513SDarren.Reed@Sun.COM neti_apply_all_instances(nts, neti_stack_apply_shutdown);
1897513SDarren.Reed@Sun.COM
1907513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
1917513SDarren.Reed@Sun.COM
1927513SDarren.Reed@Sun.COM nts->nts_netstack = NULL;
193*7915SDarren.Reed@Sun.COM nts->nts_flags &= ~NSF_ZONE_SHUTDOWN;
1947513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
1957513SDarren.Reed@Sun.COM
1967513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
1977513SDarren.Reed@Sun.COM ASSERT(nts != NULL);
1987513SDarren.Reed@Sun.COM }
1997513SDarren.Reed@Sun.COM
2007513SDarren.Reed@Sun.COM /*
2017513SDarren.Reed@Sun.COM * Free the neti stack instance.
2027513SDarren.Reed@Sun.COM * This function relies on the netstack framework only calling the _destroy
2037513SDarren.Reed@Sun.COM * callback once for each stackid. The netstack framework also provides us
2047513SDarren.Reed@Sun.COM * with assurance that nobody else will be doing any work (_create, _shutdown)
2057513SDarren.Reed@Sun.COM * on it, so there is no need to set and use flags to guard against
2067513SDarren.Reed@Sun.COM * simultaneous execution (ie. no need to set NSF_CLOSING.)
207*7915SDarren.Reed@Sun.COM * What is required, however, is to make sure that we don't corrupt the
2087513SDarren.Reed@Sun.COM * list of neti_stack_t's for other code that walks it.
2097513SDarren.Reed@Sun.COM */
2107513SDarren.Reed@Sun.COM /*ARGSUSED*/
2117513SDarren.Reed@Sun.COM static void
neti_stack_fini(netstackid_t stackid,void * arg)2127513SDarren.Reed@Sun.COM neti_stack_fini(netstackid_t stackid, void *arg)
2137513SDarren.Reed@Sun.COM {
2147513SDarren.Reed@Sun.COM neti_stack_t *nts = arg;
2157513SDarren.Reed@Sun.COM net_instance_int_t *n;
2167513SDarren.Reed@Sun.COM struct net_data *nd;
2177513SDarren.Reed@Sun.COM
2187513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
219*7915SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
220*7915SDarren.Reed@Sun.COM
2217513SDarren.Reed@Sun.COM LIST_REMOVE(nts, nts_next);
2227513SDarren.Reed@Sun.COM
2237513SDarren.Reed@Sun.COM /*
2247513SDarren.Reed@Sun.COM * Walk through all of the protocol stacks and mark them as being
2257513SDarren.Reed@Sun.COM * destroyed.
2267513SDarren.Reed@Sun.COM */
2277513SDarren.Reed@Sun.COM LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
2287513SDarren.Reed@Sun.COM nd->netd_condemned = 2;
2297513SDarren.Reed@Sun.COM }
2307513SDarren.Reed@Sun.COM
2317513SDarren.Reed@Sun.COM LIST_FOREACH(n, &nts->nts_instances, nini_next) {
2327513SDarren.Reed@Sun.COM ASSERT((n->nini_flags & NSS_SHUTDOWN_ALL) != 0);
2337513SDarren.Reed@Sun.COM if ((n->nini_flags & NSS_DESTROY_ALL) == 0)
2347513SDarren.Reed@Sun.COM n->nini_flags |= NSS_DESTROY_NEEDED;
2357513SDarren.Reed@Sun.COM }
2367513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
2377513SDarren.Reed@Sun.COM
2387513SDarren.Reed@Sun.COM neti_apply_all_instances(nts, neti_stack_apply_destroy);
2397513SDarren.Reed@Sun.COM
2407513SDarren.Reed@Sun.COM while (!LIST_EMPTY(&nts->nts_instances)) {
2417513SDarren.Reed@Sun.COM n = LIST_FIRST(&nts->nts_instances);
2427513SDarren.Reed@Sun.COM LIST_REMOVE(n, nini_next);
2437513SDarren.Reed@Sun.COM
2447513SDarren.Reed@Sun.COM net_instance_int_free(n);
2457513SDarren.Reed@Sun.COM }
246*7915SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
2477513SDarren.Reed@Sun.COM
2487513SDarren.Reed@Sun.COM ASSERT(LIST_EMPTY(&nts->nts_netd_head));
2497513SDarren.Reed@Sun.COM
2507513SDarren.Reed@Sun.COM mutex_destroy(&nts->nts_lock);
2517513SDarren.Reed@Sun.COM cv_destroy(&nts->nts_cv);
2527513SDarren.Reed@Sun.COM
2537513SDarren.Reed@Sun.COM kmem_free(nts, sizeof (*nts));
2547513SDarren.Reed@Sun.COM }
2557513SDarren.Reed@Sun.COM
2567513SDarren.Reed@Sun.COM static net_instance_int_t *
net_instance_int_create(net_instance_t * nin,net_instance_int_t * parent)2577513SDarren.Reed@Sun.COM net_instance_int_create(net_instance_t *nin, net_instance_int_t *parent)
2587513SDarren.Reed@Sun.COM {
2597513SDarren.Reed@Sun.COM net_instance_int_t *nini;
2607513SDarren.Reed@Sun.COM
2617513SDarren.Reed@Sun.COM nini = kmem_zalloc(sizeof (net_instance_int_t), KM_SLEEP);
2627513SDarren.Reed@Sun.COM nini->nini_instance = nin;
2637513SDarren.Reed@Sun.COM nini->nini_parent = parent;
2647513SDarren.Reed@Sun.COM if (parent != NULL) {
2657513SDarren.Reed@Sun.COM /*
2667513SDarren.Reed@Sun.COM * If the parent pointer is non-NULL then we take that as
2677513SDarren.Reed@Sun.COM * an indication that the net_instance_int_t is being
2687513SDarren.Reed@Sun.COM * created for an active instance and there will expect
2697513SDarren.Reed@Sun.COM * the create function to be called. In contrast, if
2707513SDarren.Reed@Sun.COM * parent is NULL then this code assumes the object is
2717513SDarren.Reed@Sun.COM * being prepared for insertion onto the master list of
2727513SDarren.Reed@Sun.COM * callbacks to be called when an instance is created, etc.
2737513SDarren.Reed@Sun.COM */
2747513SDarren.Reed@Sun.COM parent->nini_ref++;
2757513SDarren.Reed@Sun.COM nini->nini_flags |= NSS_CREATE_NEEDED;
2767513SDarren.Reed@Sun.COM }
2777513SDarren.Reed@Sun.COM
2787513SDarren.Reed@Sun.COM cv_init(&nini->nini_cv, NULL, CV_DRIVER, NULL);
2797513SDarren.Reed@Sun.COM
2807513SDarren.Reed@Sun.COM return (nini);
2817513SDarren.Reed@Sun.COM }
2827513SDarren.Reed@Sun.COM
283*7915SDarren.Reed@Sun.COM /*
284*7915SDarren.Reed@Sun.COM * Free'ing of a net_instance_int_t is only to be done when we know nobody
285*7915SDarren.Reed@Sun.COM * else has is using it. For both parents and clones, this is indicated by
286*7915SDarren.Reed@Sun.COM * nini_ref being greater than 0, however, nini_ref is managed differently
287*7915SDarren.Reed@Sun.COM * for its two uses. For parents, nini_ref is increased when a new clone is
288*7915SDarren.Reed@Sun.COM * created and it is decremented here. For clones, nini_ref is adjusted by
289*7915SDarren.Reed@Sun.COM * code elsewhere (e.g. in neti_stack_apply_*) and is not changed here.
290*7915SDarren.Reed@Sun.COM */
2917513SDarren.Reed@Sun.COM static void
net_instance_int_free(net_instance_int_t * nini)2927513SDarren.Reed@Sun.COM net_instance_int_free(net_instance_int_t *nini)
2937513SDarren.Reed@Sun.COM {
294*7915SDarren.Reed@Sun.COM /*
295*7915SDarren.Reed@Sun.COM * This mutex guards the use of nini_ref.
296*7915SDarren.Reed@Sun.COM */
297*7915SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
2987513SDarren.Reed@Sun.COM
299*7915SDarren.Reed@Sun.COM /*
300*7915SDarren.Reed@Sun.COM * For 'parent' structures, nini_ref will drop to 0 when
301*7915SDarren.Reed@Sun.COM * the last clone has been free'd... but for clones, it
302*7915SDarren.Reed@Sun.COM * is possible for nini_ref to be non-zero if we get in
303*7915SDarren.Reed@Sun.COM * here when all the locks have been given up to execute
304*7915SDarren.Reed@Sun.COM * a callback or wait_for_nini_inprogress. In that case,
305*7915SDarren.Reed@Sun.COM * we do not want to free the structure and just indicate
306*7915SDarren.Reed@Sun.COM * that it is on the "doomed" list, thus we set the
307*7915SDarren.Reed@Sun.COM * condemned flag.
308*7915SDarren.Reed@Sun.COM */
309*7915SDarren.Reed@Sun.COM if (nini->nini_parent != NULL) {
310*7915SDarren.Reed@Sun.COM if (nini->nini_ref > 0)
311*7915SDarren.Reed@Sun.COM nini->nini_condemned = B_TRUE;
3127513SDarren.Reed@Sun.COM nini->nini_parent->nini_ref--;
313*7915SDarren.Reed@Sun.COM if (nini->nini_parent->nini_ref == 0)
314*7915SDarren.Reed@Sun.COM net_instance_int_free(nini->nini_parent);
315*7915SDarren.Reed@Sun.COM nini->nini_parent = NULL;
316*7915SDarren.Reed@Sun.COM }
3177513SDarren.Reed@Sun.COM
318*7915SDarren.Reed@Sun.COM if (nini->nini_ref == 0) {
319*7915SDarren.Reed@Sun.COM cv_destroy(&nini->nini_cv);
320*7915SDarren.Reed@Sun.COM kmem_free(nini, sizeof (*nini));
321*7915SDarren.Reed@Sun.COM }
3227513SDarren.Reed@Sun.COM }
3237513SDarren.Reed@Sun.COM
3247513SDarren.Reed@Sun.COM net_instance_t *
net_instance_alloc(const int version)3257513SDarren.Reed@Sun.COM net_instance_alloc(const int version)
3267513SDarren.Reed@Sun.COM {
3277513SDarren.Reed@Sun.COM net_instance_t *nin;
3287513SDarren.Reed@Sun.COM
3297513SDarren.Reed@Sun.COM if (version != NETINFO_VERSION)
3307513SDarren.Reed@Sun.COM return (NULL);
3317513SDarren.Reed@Sun.COM
3327513SDarren.Reed@Sun.COM nin = kmem_zalloc(sizeof (net_instance_t), KM_SLEEP);
3337513SDarren.Reed@Sun.COM nin->nin_version = version;
3347513SDarren.Reed@Sun.COM
3357513SDarren.Reed@Sun.COM return (nin);
3367513SDarren.Reed@Sun.COM }
3377513SDarren.Reed@Sun.COM
3387513SDarren.Reed@Sun.COM void
net_instance_free(net_instance_t * nin)3397513SDarren.Reed@Sun.COM net_instance_free(net_instance_t *nin)
3407513SDarren.Reed@Sun.COM {
3417513SDarren.Reed@Sun.COM kmem_free(nin, sizeof (*nin));
3427513SDarren.Reed@Sun.COM }
3437513SDarren.Reed@Sun.COM
3447513SDarren.Reed@Sun.COM int
net_instance_register(net_instance_t * nin)3457513SDarren.Reed@Sun.COM net_instance_register(net_instance_t *nin)
3467513SDarren.Reed@Sun.COM {
3477513SDarren.Reed@Sun.COM net_instance_int_t *parent;
3487513SDarren.Reed@Sun.COM net_instance_int_t *tmp;
3497513SDarren.Reed@Sun.COM neti_stack_t *nts;
3507513SDarren.Reed@Sun.COM
3517513SDarren.Reed@Sun.COM ASSERT(nin->nin_name != NULL);
3527513SDarren.Reed@Sun.COM
3537513SDarren.Reed@Sun.COM if (nin->nin_create == NULL || nin->nin_destroy == NULL)
3547513SDarren.Reed@Sun.COM return (DDI_FAILURE);
3557513SDarren.Reed@Sun.COM
3567513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
3577513SDarren.Reed@Sun.COM /*
3587513SDarren.Reed@Sun.COM * Search for duplicate, either on the global list or on any
3597513SDarren.Reed@Sun.COM * of the known instances.
3607513SDarren.Reed@Sun.COM */
3617513SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
3627513SDarren.Reed@Sun.COM if (strcmp(nin->nin_name, tmp->nini_instance->nin_name) == 0) {
3637513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
3647513SDarren.Reed@Sun.COM return (DDI_FAILURE);
3657513SDarren.Reed@Sun.COM }
3667513SDarren.Reed@Sun.COM }
3677513SDarren.Reed@Sun.COM
3687513SDarren.Reed@Sun.COM /*
3697513SDarren.Reed@Sun.COM * Now insert and activate.
3707513SDarren.Reed@Sun.COM */
3717513SDarren.Reed@Sun.COM parent = net_instance_int_create(nin, NULL);
3727513SDarren.Reed@Sun.COM ASSERT(parent != NULL);
3737513SDarren.Reed@Sun.COM LIST_INSERT_HEAD(&neti_instance_list, parent, nini_next);
3747513SDarren.Reed@Sun.COM
3757513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
3767513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
3777513SDarren.Reed@Sun.COM /*
3787513SDarren.Reed@Sun.COM * If shutdown of the zone has begun then do not add a new
3797513SDarren.Reed@Sun.COM * instance of the object being registered.
3807513SDarren.Reed@Sun.COM */
3817513SDarren.Reed@Sun.COM if ((nts->nts_flags & NSF_ZONE_SHUTDOWN) ||
3827513SDarren.Reed@Sun.COM (nts->nts_netstack == NULL)) {
3837513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
3847513SDarren.Reed@Sun.COM continue;
3857513SDarren.Reed@Sun.COM }
386*7915SDarren.Reed@Sun.COM
3877513SDarren.Reed@Sun.COM /*
3887513SDarren.Reed@Sun.COM * This function returns with the NSS_CREATE_NEEDED flag
3897513SDarren.Reed@Sun.COM * set in "dup", so it is adequately prepared for the
3907513SDarren.Reed@Sun.COM * upcoming apply.
3917513SDarren.Reed@Sun.COM */
3927513SDarren.Reed@Sun.COM tmp = net_instance_int_create(nin, parent);
3937513SDarren.Reed@Sun.COM ASSERT(tmp != NULL);
3947513SDarren.Reed@Sun.COM LIST_INSERT_HEAD(&nts->nts_instances, tmp, nini_next);
3957513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
3967513SDarren.Reed@Sun.COM
3977513SDarren.Reed@Sun.COM }
3987513SDarren.Reed@Sun.COM
3997513SDarren.Reed@Sun.COM neti_apply_all_stacks(parent, neti_stack_apply_create);
4007513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
4017513SDarren.Reed@Sun.COM
4027513SDarren.Reed@Sun.COM return (DDI_SUCCESS);
4037513SDarren.Reed@Sun.COM }
4047513SDarren.Reed@Sun.COM
4057513SDarren.Reed@Sun.COM /*
4067513SDarren.Reed@Sun.COM * While net_instance_register() isn't likely to be racing against itself,
4077513SDarren.Reed@Sun.COM * net_instance_unregister() can be entered from various directions that
4087513SDarren.Reed@Sun.COM * can compete: shutdown of a zone, unloading of a module (and it calling
4097513SDarren.Reed@Sun.COM * _unregister() as part of that) and the module doing an _unregister()
4107513SDarren.Reed@Sun.COM * anyway.
4117513SDarren.Reed@Sun.COM */
4127513SDarren.Reed@Sun.COM int
net_instance_unregister(net_instance_t * nin)4137513SDarren.Reed@Sun.COM net_instance_unregister(net_instance_t *nin)
4147513SDarren.Reed@Sun.COM {
4157513SDarren.Reed@Sun.COM net_instance_int_t *parent;
4167513SDarren.Reed@Sun.COM net_instance_int_t *tmp;
4177513SDarren.Reed@Sun.COM neti_stack_t *nts;
4187513SDarren.Reed@Sun.COM
4197513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
4207513SDarren.Reed@Sun.COM
4217513SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
4227513SDarren.Reed@Sun.COM if (strcmp(tmp->nini_instance->nin_name, nin->nin_name) == 0) {
4237513SDarren.Reed@Sun.COM LIST_REMOVE(tmp, nini_next);
4247513SDarren.Reed@Sun.COM break;
4257513SDarren.Reed@Sun.COM }
4267513SDarren.Reed@Sun.COM }
4277513SDarren.Reed@Sun.COM
4287513SDarren.Reed@Sun.COM if (tmp == NULL) {
4297513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
4307513SDarren.Reed@Sun.COM return (DDI_FAILURE);
4317513SDarren.Reed@Sun.COM }
4327513SDarren.Reed@Sun.COM parent = tmp;
4337513SDarren.Reed@Sun.COM
4347513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
4357513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
4367513SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
4377513SDarren.Reed@Sun.COM if (tmp->nini_parent != parent)
4387513SDarren.Reed@Sun.COM continue;
4397513SDarren.Reed@Sun.COM /*
4407513SDarren.Reed@Sun.COM * Netstack difference:
4417513SDarren.Reed@Sun.COM * In netstack.c, there is a check for
4427513SDarren.Reed@Sun.COM * NSS_CREATE_COMPLETED before setting the other
4437513SDarren.Reed@Sun.COM * _NEEDED flags. If we consider that a list
4447513SDarren.Reed@Sun.COM * member must always have at least the _CREATE_NEEDED
4457513SDarren.Reed@Sun.COM * flag set and that wait_for_nini_inprogress will
4467513SDarren.Reed@Sun.COM * also wait for that flag to be cleared in both of
4477513SDarren.Reed@Sun.COM * the shutdown and destroy apply functions.
4487513SDarren.Reed@Sun.COM *
4497513SDarren.Reed@Sun.COM * It is possible to optimize out the case where
4507513SDarren.Reed@Sun.COM * all three _NEEDED flags are set to being able
4517513SDarren.Reed@Sun.COM * to pretend everything has been done and just
4527513SDarren.Reed@Sun.COM * set all three _COMPLETE flags. This makes a
4537513SDarren.Reed@Sun.COM * special case that we then need to consider in
4547513SDarren.Reed@Sun.COM * other locations, so for the sake of simplicity,
4557513SDarren.Reed@Sun.COM * we leave it as it is.
4567513SDarren.Reed@Sun.COM */
4577513SDarren.Reed@Sun.COM if ((tmp->nini_flags & NSS_SHUTDOWN_ALL) == 0)
4587513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_SHUTDOWN_NEEDED;
4597513SDarren.Reed@Sun.COM if ((tmp->nini_flags & NSS_DESTROY_ALL) == 0)
4607513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_DESTROY_NEEDED;
461*7915SDarren.Reed@Sun.COM break;
4627513SDarren.Reed@Sun.COM }
4637513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
4647513SDarren.Reed@Sun.COM }
4657513SDarren.Reed@Sun.COM
4667513SDarren.Reed@Sun.COM /*
4677513SDarren.Reed@Sun.COM * Each of these functions ensures that the requisite _COMPLETED
4687513SDarren.Reed@Sun.COM * flag is present before calling the apply function. So we are
4697513SDarren.Reed@Sun.COM * guaranteed to have NSS_CREATE_COMPLETED|NSS_SHUTDOWN_COMPLETED
4707513SDarren.Reed@Sun.COM * both set after the first call here and when the second completes,
4717513SDarren.Reed@Sun.COM * NSS_DESTROY_COMPLETED is also set.
4727513SDarren.Reed@Sun.COM */
4737513SDarren.Reed@Sun.COM neti_apply_all_stacks(parent, neti_stack_apply_shutdown);
4747513SDarren.Reed@Sun.COM neti_apply_all_stacks(parent, neti_stack_apply_destroy);
4757513SDarren.Reed@Sun.COM
4767513SDarren.Reed@Sun.COM /*
4777513SDarren.Reed@Sun.COM * Remove the instance callback information from each stack.
4787513SDarren.Reed@Sun.COM */
4797513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
4807513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
4817513SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
4827513SDarren.Reed@Sun.COM if ((tmp->nini_parent == parent) &&
4837513SDarren.Reed@Sun.COM (tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) &&
4847513SDarren.Reed@Sun.COM (tmp->nini_flags & NSS_DESTROY_COMPLETED)) {
4857513SDarren.Reed@Sun.COM /*
4867513SDarren.Reed@Sun.COM * There should only be one entry that has a
4877513SDarren.Reed@Sun.COM * matching nini_parent so there is no need to
4887513SDarren.Reed@Sun.COM * worry about continuing a loop where we are
4897513SDarren.Reed@Sun.COM * free'ing the structure holding the 'next'
4907513SDarren.Reed@Sun.COM * pointer.
4917513SDarren.Reed@Sun.COM */
4927513SDarren.Reed@Sun.COM LIST_REMOVE(tmp, nini_next);
4937513SDarren.Reed@Sun.COM net_instance_int_free(tmp);
4947513SDarren.Reed@Sun.COM break;
4957513SDarren.Reed@Sun.COM }
4967513SDarren.Reed@Sun.COM }
4977513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
4987513SDarren.Reed@Sun.COM }
499*7915SDarren.Reed@Sun.COM
5007513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
5017513SDarren.Reed@Sun.COM
5027513SDarren.Reed@Sun.COM return (DDI_SUCCESS);
5037513SDarren.Reed@Sun.COM }
5047513SDarren.Reed@Sun.COM
5057513SDarren.Reed@Sun.COM static void
neti_apply_all_instances(neti_stack_t * nts,napplyfn_t * applyfn)5067513SDarren.Reed@Sun.COM neti_apply_all_instances(neti_stack_t *nts, napplyfn_t *applyfn)
5077513SDarren.Reed@Sun.COM {
5087513SDarren.Reed@Sun.COM net_instance_int_t *n;
5097513SDarren.Reed@Sun.COM
5107513SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
5117513SDarren.Reed@Sun.COM
5127513SDarren.Reed@Sun.COM n = LIST_FIRST(&nts->nts_instances);
5137513SDarren.Reed@Sun.COM while (n != NULL) {
514*7915SDarren.Reed@Sun.COM if ((applyfn)(nts, n->nini_parent)) {
5157513SDarren.Reed@Sun.COM /* Lock dropped - restart at head */
5167513SDarren.Reed@Sun.COM n = LIST_FIRST(&nts->nts_instances);
5177513SDarren.Reed@Sun.COM } else {
5187513SDarren.Reed@Sun.COM n = LIST_NEXT(n, nini_next);
5197513SDarren.Reed@Sun.COM }
5207513SDarren.Reed@Sun.COM }
5217513SDarren.Reed@Sun.COM }
5227513SDarren.Reed@Sun.COM
5237513SDarren.Reed@Sun.COM static void
neti_apply_all_stacks(void * parent,napplyfn_t * applyfn)5247513SDarren.Reed@Sun.COM neti_apply_all_stacks(void *parent, napplyfn_t *applyfn)
5257513SDarren.Reed@Sun.COM {
5267513SDarren.Reed@Sun.COM neti_stack_t *nts;
5277513SDarren.Reed@Sun.COM
5287513SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
5297513SDarren.Reed@Sun.COM
5307513SDarren.Reed@Sun.COM nts = LIST_FIRST(&neti_stack_list);
5317513SDarren.Reed@Sun.COM while (nts != NULL) {
5327513SDarren.Reed@Sun.COM /*
5337513SDarren.Reed@Sun.COM * This function differs, in that it doesn't have a call to
5347513SDarren.Reed@Sun.COM * a "wait_creator" call, from the zsd/netstack code. The
5357513SDarren.Reed@Sun.COM * waiting is pushed into the apply functions which cause
5367513SDarren.Reed@Sun.COM * the waiting to be done in wait_for_nini_progress with
5377513SDarren.Reed@Sun.COM * the passing in of cmask.
5387513SDarren.Reed@Sun.COM */
539*7915SDarren.Reed@Sun.COM if ((applyfn)(nts, parent)) {
5407513SDarren.Reed@Sun.COM /* Lock dropped - restart at head */
5417513SDarren.Reed@Sun.COM nts = LIST_FIRST(&neti_stack_list);
5427513SDarren.Reed@Sun.COM } else {
5437513SDarren.Reed@Sun.COM nts = LIST_NEXT(nts, nts_next);
5447513SDarren.Reed@Sun.COM }
5457513SDarren.Reed@Sun.COM }
5467513SDarren.Reed@Sun.COM }
5477513SDarren.Reed@Sun.COM
5487513SDarren.Reed@Sun.COM static boolean_t
neti_stack_apply_create(neti_stack_t * nts,void * parent)549*7915SDarren.Reed@Sun.COM neti_stack_apply_create(neti_stack_t *nts, void *parent)
5507513SDarren.Reed@Sun.COM {
5517513SDarren.Reed@Sun.COM void *result;
5527513SDarren.Reed@Sun.COM boolean_t dropped = B_FALSE;
5537513SDarren.Reed@Sun.COM net_instance_int_t *tmp;
5547513SDarren.Reed@Sun.COM net_instance_t *nin;
5557513SDarren.Reed@Sun.COM
5567513SDarren.Reed@Sun.COM ASSERT(parent != NULL);
557*7915SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
5587513SDarren.Reed@Sun.COM
5597513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
5607513SDarren.Reed@Sun.COM
5617513SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
5627513SDarren.Reed@Sun.COM if (tmp->nini_parent == parent)
5637513SDarren.Reed@Sun.COM break;
5647513SDarren.Reed@Sun.COM }
5657513SDarren.Reed@Sun.COM if (tmp == NULL) {
5667513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
5677513SDarren.Reed@Sun.COM return (dropped);
5687513SDarren.Reed@Sun.COM }
5697513SDarren.Reed@Sun.COM
570*7915SDarren.Reed@Sun.COM tmp->nini_ref++;
571*7915SDarren.Reed@Sun.COM
572*7915SDarren.Reed@Sun.COM if (wait_for_nini_inprogress(nts, tmp, 0))
573*7915SDarren.Reed@Sun.COM dropped = B_TRUE;
574*7915SDarren.Reed@Sun.COM
575*7915SDarren.Reed@Sun.COM if ((tmp->nini_flags & NSS_CREATE_NEEDED) && !tmp->nini_condemned) {
576*7915SDarren.Reed@Sun.COM nin = tmp->nini_instance;
577*7915SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_CREATE_NEEDED;
578*7915SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_CREATE_INPROGRESS;
579*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__create__inprogress,
580*7915SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, tmp);
581*7915SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
582*7915SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
583*7915SDarren.Reed@Sun.COM dropped = B_TRUE;
584*7915SDarren.Reed@Sun.COM
585*7915SDarren.Reed@Sun.COM ASSERT(tmp->nini_created == NULL);
586*7915SDarren.Reed@Sun.COM ASSERT(nin->nin_create != NULL);
587*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__create__start,
588*7915SDarren.Reed@Sun.COM netstackid_t, nts->nts_id,
589*7915SDarren.Reed@Sun.COM neti_stack_t *, nts);
590*7915SDarren.Reed@Sun.COM result = (nin->nin_create)(nts->nts_id);
591*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__create__end,
592*7915SDarren.Reed@Sun.COM void *, result, neti_stack_t *, nts);
593*7915SDarren.Reed@Sun.COM
594*7915SDarren.Reed@Sun.COM ASSERT(result != NULL);
595*7915SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
596*7915SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
597*7915SDarren.Reed@Sun.COM tmp->nini_created = result;
598*7915SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_CREATE_INPROGRESS;
599*7915SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_CREATE_COMPLETED;
600*7915SDarren.Reed@Sun.COM cv_broadcast(&tmp->nini_cv);
601*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__create__completed,
602*7915SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, tmp);
603*7915SDarren.Reed@Sun.COM }
604*7915SDarren.Reed@Sun.COM tmp->nini_ref--;
605*7915SDarren.Reed@Sun.COM
606*7915SDarren.Reed@Sun.COM if (tmp->nini_condemned) {
607*7915SDarren.Reed@Sun.COM net_instance_int_free(tmp);
608*7915SDarren.Reed@Sun.COM dropped = B_TRUE;
609*7915SDarren.Reed@Sun.COM }
610*7915SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
611*7915SDarren.Reed@Sun.COM return (dropped);
612*7915SDarren.Reed@Sun.COM }
613*7915SDarren.Reed@Sun.COM
614*7915SDarren.Reed@Sun.COM
615*7915SDarren.Reed@Sun.COM static boolean_t
neti_stack_apply_shutdown(neti_stack_t * nts,void * parent)616*7915SDarren.Reed@Sun.COM neti_stack_apply_shutdown(neti_stack_t *nts, void *parent)
617*7915SDarren.Reed@Sun.COM {
618*7915SDarren.Reed@Sun.COM boolean_t dropped = B_FALSE;
619*7915SDarren.Reed@Sun.COM net_instance_int_t *tmp;
620*7915SDarren.Reed@Sun.COM net_instance_t *nin;
621*7915SDarren.Reed@Sun.COM
622*7915SDarren.Reed@Sun.COM ASSERT(parent != NULL);
623*7915SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
624*7915SDarren.Reed@Sun.COM
625*7915SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
626*7915SDarren.Reed@Sun.COM
627*7915SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
628*7915SDarren.Reed@Sun.COM if (tmp->nini_parent == parent)
629*7915SDarren.Reed@Sun.COM break;
630*7915SDarren.Reed@Sun.COM }
631*7915SDarren.Reed@Sun.COM if (tmp == NULL) {
632*7915SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
633*7915SDarren.Reed@Sun.COM return (dropped);
634*7915SDarren.Reed@Sun.COM }
635*7915SDarren.Reed@Sun.COM ASSERT((tmp->nini_flags & NSS_SHUTDOWN_ALL) != 0);
636*7915SDarren.Reed@Sun.COM
637*7915SDarren.Reed@Sun.COM tmp->nini_ref++;
638*7915SDarren.Reed@Sun.COM
639*7915SDarren.Reed@Sun.COM if (wait_for_nini_inprogress(nts, tmp, NSS_CREATE_NEEDED))
6407513SDarren.Reed@Sun.COM dropped = B_TRUE;
6417513SDarren.Reed@Sun.COM
6427513SDarren.Reed@Sun.COM nin = tmp->nini_instance;
6437513SDarren.Reed@Sun.COM if (nin->nin_shutdown == NULL) {
6447513SDarren.Reed@Sun.COM /*
6457513SDarren.Reed@Sun.COM * If there is no shutdown function, fake having completed it.
6467513SDarren.Reed@Sun.COM */
6477513SDarren.Reed@Sun.COM if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) {
6487513SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
6497513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
6507513SDarren.Reed@Sun.COM }
651*7915SDarren.Reed@Sun.COM tmp->nini_ref--;
652*7915SDarren.Reed@Sun.COM
653*7915SDarren.Reed@Sun.COM if (tmp->nini_condemned) {
654*7915SDarren.Reed@Sun.COM net_instance_int_free(tmp);
655*7915SDarren.Reed@Sun.COM dropped = B_TRUE;
656*7915SDarren.Reed@Sun.COM }
6577513SDarren.Reed@Sun.COM
6587513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
6597513SDarren.Reed@Sun.COM return (dropped);
6607513SDarren.Reed@Sun.COM }
6617513SDarren.Reed@Sun.COM
662*7915SDarren.Reed@Sun.COM if ((tmp->nini_flags & NSS_SHUTDOWN_NEEDED) && !tmp->nini_condemned) {
6637513SDarren.Reed@Sun.COM ASSERT((tmp->nini_flags & NSS_CREATE_COMPLETED) != 0);
6647513SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
6657513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_SHUTDOWN_INPROGRESS;
6667513SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__shutdown__inprogress,
6677513SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, tmp);
6687513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
669*7915SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
6707513SDarren.Reed@Sun.COM dropped = B_TRUE;
6717513SDarren.Reed@Sun.COM
6727513SDarren.Reed@Sun.COM ASSERT(nin->nin_shutdown != NULL);
6737513SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__shutdown__start,
6747513SDarren.Reed@Sun.COM netstackid_t, nts->nts_id,
6757513SDarren.Reed@Sun.COM neti_stack_t *, nts);
6767513SDarren.Reed@Sun.COM (nin->nin_shutdown)(nts->nts_id, tmp->nini_created);
6777513SDarren.Reed@Sun.COM DTRACE_PROBE1(neti__stack__shutdown__end,
6787513SDarren.Reed@Sun.COM neti_stack_t *, nts);
6797513SDarren.Reed@Sun.COM
680*7915SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
6817513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
6827513SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_SHUTDOWN_INPROGRESS;
6837513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
6847513SDarren.Reed@Sun.COM cv_broadcast(&tmp->nini_cv);
6857513SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__shutdown__completed,
6867513SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, tmp);
6877513SDarren.Reed@Sun.COM }
6887513SDarren.Reed@Sun.COM ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
689*7915SDarren.Reed@Sun.COM tmp->nini_ref--;
690*7915SDarren.Reed@Sun.COM
691*7915SDarren.Reed@Sun.COM if (tmp->nini_condemned) {
692*7915SDarren.Reed@Sun.COM net_instance_int_free(tmp);
693*7915SDarren.Reed@Sun.COM dropped = B_TRUE;
694*7915SDarren.Reed@Sun.COM }
6957513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
6967513SDarren.Reed@Sun.COM return (dropped);
6977513SDarren.Reed@Sun.COM }
6987513SDarren.Reed@Sun.COM
6997513SDarren.Reed@Sun.COM static boolean_t
neti_stack_apply_destroy(neti_stack_t * nts,void * parent)700*7915SDarren.Reed@Sun.COM neti_stack_apply_destroy(neti_stack_t *nts, void *parent)
7017513SDarren.Reed@Sun.COM {
7027513SDarren.Reed@Sun.COM boolean_t dropped = B_FALSE;
7037513SDarren.Reed@Sun.COM net_instance_int_t *tmp;
7047513SDarren.Reed@Sun.COM net_instance_t *nin;
7057513SDarren.Reed@Sun.COM
7067513SDarren.Reed@Sun.COM ASSERT(parent != NULL);
707*7915SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
7087513SDarren.Reed@Sun.COM
7097513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
7107513SDarren.Reed@Sun.COM
7117513SDarren.Reed@Sun.COM LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
7127513SDarren.Reed@Sun.COM if (tmp->nini_parent == parent)
7137513SDarren.Reed@Sun.COM break;
7147513SDarren.Reed@Sun.COM }
7157513SDarren.Reed@Sun.COM if (tmp == NULL) {
7167513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
7177513SDarren.Reed@Sun.COM return (dropped);
7187513SDarren.Reed@Sun.COM }
7197513SDarren.Reed@Sun.COM
720*7915SDarren.Reed@Sun.COM tmp->nini_ref++;
721*7915SDarren.Reed@Sun.COM
7227513SDarren.Reed@Sun.COM /*
7237513SDarren.Reed@Sun.COM * We pause here so that when we continue we know that we're the
7247513SDarren.Reed@Sun.COM * only one doing anything active with this node.
7257513SDarren.Reed@Sun.COM */
726*7915SDarren.Reed@Sun.COM if (wait_for_nini_inprogress(nts, tmp,
7277513SDarren.Reed@Sun.COM NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED))
7287513SDarren.Reed@Sun.COM dropped = B_TRUE;
7297513SDarren.Reed@Sun.COM
730*7915SDarren.Reed@Sun.COM if ((tmp->nini_flags & NSS_DESTROY_NEEDED) && !tmp->nini_condemned) {
7317513SDarren.Reed@Sun.COM ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
7327513SDarren.Reed@Sun.COM nin = tmp->nini_instance;
7337513SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_DESTROY_NEEDED;
7347513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_DESTROY_INPROGRESS;
7357513SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__destroy__inprogress,
7367513SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, tmp);
7377513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
738*7915SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
7397513SDarren.Reed@Sun.COM dropped = B_TRUE;
7407513SDarren.Reed@Sun.COM
7417513SDarren.Reed@Sun.COM ASSERT(nin->nin_destroy != NULL);
7427513SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__destroy__start,
7437513SDarren.Reed@Sun.COM netstackid_t, nts->nts_id,
7447513SDarren.Reed@Sun.COM neti_stack_t *, nts);
7457513SDarren.Reed@Sun.COM (nin->nin_destroy)(nts->nts_id, tmp->nini_created);
7467513SDarren.Reed@Sun.COM DTRACE_PROBE1(neti__stack__destroy__end,
7477513SDarren.Reed@Sun.COM neti_stack_t *, nts);
7487513SDarren.Reed@Sun.COM
749*7915SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
7507513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
7517513SDarren.Reed@Sun.COM tmp->nini_flags &= ~NSS_DESTROY_INPROGRESS;
7527513SDarren.Reed@Sun.COM tmp->nini_flags |= NSS_DESTROY_COMPLETED;
7537513SDarren.Reed@Sun.COM cv_broadcast(&tmp->nini_cv);
7547513SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__stack__destroy__completed,
7557513SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, tmp);
7567513SDarren.Reed@Sun.COM }
757*7915SDarren.Reed@Sun.COM tmp->nini_ref--;
758*7915SDarren.Reed@Sun.COM
759*7915SDarren.Reed@Sun.COM if (tmp->nini_condemned) {
760*7915SDarren.Reed@Sun.COM net_instance_int_free(tmp);
761*7915SDarren.Reed@Sun.COM dropped = B_TRUE;
762*7915SDarren.Reed@Sun.COM }
7637513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
7647513SDarren.Reed@Sun.COM return (dropped);
7657513SDarren.Reed@Sun.COM }
7667513SDarren.Reed@Sun.COM
7677513SDarren.Reed@Sun.COM static boolean_t
wait_for_nini_inprogress(neti_stack_t * nts,net_instance_int_t * nini,uint32_t cmask)768*7915SDarren.Reed@Sun.COM wait_for_nini_inprogress(neti_stack_t *nts, net_instance_int_t *nini,
769*7915SDarren.Reed@Sun.COM uint32_t cmask)
7707513SDarren.Reed@Sun.COM {
7717513SDarren.Reed@Sun.COM boolean_t dropped = B_FALSE;
7727513SDarren.Reed@Sun.COM
773*7915SDarren.Reed@Sun.COM ASSERT(mutex_owned(&neti_stack_lock));
7747513SDarren.Reed@Sun.COM
7757513SDarren.Reed@Sun.COM while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) {
776*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__wait__nini__inprogress,
7777513SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, nini);
7787513SDarren.Reed@Sun.COM dropped = B_TRUE;
779*7915SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
7807513SDarren.Reed@Sun.COM
7817513SDarren.Reed@Sun.COM cv_wait(&nini->nini_cv, &nts->nts_lock);
7827513SDarren.Reed@Sun.COM
7837513SDarren.Reed@Sun.COM /* First drop netstack_lock to preserve order */
7847513SDarren.Reed@Sun.COM mutex_exit(&nts->nts_lock);
785*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(wait__nini__inprogress__pause,
786*7915SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, nini);
787*7915SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
7887513SDarren.Reed@Sun.COM mutex_enter(&nts->nts_lock);
7897513SDarren.Reed@Sun.COM }
790*7915SDarren.Reed@Sun.COM DTRACE_PROBE2(neti__wait__nini__inprogress__complete,
791*7915SDarren.Reed@Sun.COM neti_stack_t *, nts, net_instance_int_t *, nini);
7927513SDarren.Reed@Sun.COM return (dropped);
7937513SDarren.Reed@Sun.COM }
7947513SDarren.Reed@Sun.COM
7957513SDarren.Reed@Sun.COM /* ======================================================================= */
7967513SDarren.Reed@Sun.COM
7977513SDarren.Reed@Sun.COM netid_t
net_zoneidtonetid(zoneid_t zoneid)7987513SDarren.Reed@Sun.COM net_zoneidtonetid(zoneid_t zoneid)
7997513SDarren.Reed@Sun.COM {
8007513SDarren.Reed@Sun.COM
8017513SDarren.Reed@Sun.COM neti_stack_t *nts;
8027513SDarren.Reed@Sun.COM
8037513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
8047513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
8057513SDarren.Reed@Sun.COM if (nts->nts_zoneid == zoneid) {
8067513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8077513SDarren.Reed@Sun.COM return (nts->nts_id);
8087513SDarren.Reed@Sun.COM }
8097513SDarren.Reed@Sun.COM }
8107513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8117513SDarren.Reed@Sun.COM
8127513SDarren.Reed@Sun.COM return (-1);
8137513SDarren.Reed@Sun.COM }
8147513SDarren.Reed@Sun.COM
8157513SDarren.Reed@Sun.COM zoneid_t
net_getzoneidbynetid(netid_t netid)8167513SDarren.Reed@Sun.COM net_getzoneidbynetid(netid_t netid)
8177513SDarren.Reed@Sun.COM {
8187513SDarren.Reed@Sun.COM neti_stack_t *nts;
8197513SDarren.Reed@Sun.COM
8207513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
8217513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
8227513SDarren.Reed@Sun.COM if (nts->nts_id == netid) {
8237513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8247513SDarren.Reed@Sun.COM return (nts->nts_zoneid);
8257513SDarren.Reed@Sun.COM }
8267513SDarren.Reed@Sun.COM }
8277513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8287513SDarren.Reed@Sun.COM
8297513SDarren.Reed@Sun.COM return (-1);
8307513SDarren.Reed@Sun.COM }
8317513SDarren.Reed@Sun.COM
8327513SDarren.Reed@Sun.COM netstackid_t
net_getnetstackidbynetid(netid_t netid)8337513SDarren.Reed@Sun.COM net_getnetstackidbynetid(netid_t netid)
8347513SDarren.Reed@Sun.COM {
8357513SDarren.Reed@Sun.COM neti_stack_t *nts;
8367513SDarren.Reed@Sun.COM
8377513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
8387513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
8397513SDarren.Reed@Sun.COM if (nts->nts_id == netid) {
8407513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8417513SDarren.Reed@Sun.COM return (nts->nts_stackid);
8427513SDarren.Reed@Sun.COM }
8437513SDarren.Reed@Sun.COM }
8447513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8457513SDarren.Reed@Sun.COM
8467513SDarren.Reed@Sun.COM return (-1);
8477513SDarren.Reed@Sun.COM }
8487513SDarren.Reed@Sun.COM
8497513SDarren.Reed@Sun.COM netid_t
net_getnetidbynetstackid(netstackid_t netstackid)8507513SDarren.Reed@Sun.COM net_getnetidbynetstackid(netstackid_t netstackid)
8517513SDarren.Reed@Sun.COM {
8527513SDarren.Reed@Sun.COM neti_stack_t *nts;
8537513SDarren.Reed@Sun.COM
8547513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
8557513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
8567513SDarren.Reed@Sun.COM if (nts->nts_stackid == netstackid) {
8577513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8587513SDarren.Reed@Sun.COM return (nts->nts_id);
8597513SDarren.Reed@Sun.COM }
8607513SDarren.Reed@Sun.COM }
8617513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8627513SDarren.Reed@Sun.COM
8637513SDarren.Reed@Sun.COM return (-1);
8647513SDarren.Reed@Sun.COM }
8657513SDarren.Reed@Sun.COM
8667513SDarren.Reed@Sun.COM neti_stack_t *
net_getnetistackbyid(netid_t netid)8677513SDarren.Reed@Sun.COM net_getnetistackbyid(netid_t netid)
8687513SDarren.Reed@Sun.COM {
8697513SDarren.Reed@Sun.COM neti_stack_t *nts;
8707513SDarren.Reed@Sun.COM
8717513SDarren.Reed@Sun.COM mutex_enter(&neti_stack_lock);
8727513SDarren.Reed@Sun.COM LIST_FOREACH(nts, &neti_stack_list, nts_next) {
8737513SDarren.Reed@Sun.COM if (nts->nts_id == netid) {
8747513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8757513SDarren.Reed@Sun.COM return (nts);
8767513SDarren.Reed@Sun.COM }
8777513SDarren.Reed@Sun.COM }
8787513SDarren.Reed@Sun.COM mutex_exit(&neti_stack_lock);
8797513SDarren.Reed@Sun.COM
8807513SDarren.Reed@Sun.COM return (NULL);
8817513SDarren.Reed@Sun.COM }
8827513SDarren.Reed@Sun.COM
8837513SDarren.Reed@Sun.COM int
net_instance_notify_register(netid_t netid,hook_notify_fn_t callback,void * arg)8847513SDarren.Reed@Sun.COM net_instance_notify_register(netid_t netid, hook_notify_fn_t callback,
8857513SDarren.Reed@Sun.COM void *arg)
8867513SDarren.Reed@Sun.COM {
8877513SDarren.Reed@Sun.COM
8887513SDarren.Reed@Sun.COM return (hook_stack_notify_register(net_getnetstackidbynetid(netid),
8897513SDarren.Reed@Sun.COM callback, arg));
8907513SDarren.Reed@Sun.COM }
8917513SDarren.Reed@Sun.COM
8927513SDarren.Reed@Sun.COM int
net_instance_notify_unregister(netid_t netid,hook_notify_fn_t callback)8937513SDarren.Reed@Sun.COM net_instance_notify_unregister(netid_t netid, hook_notify_fn_t callback)
8947513SDarren.Reed@Sun.COM {
8957513SDarren.Reed@Sun.COM
8967513SDarren.Reed@Sun.COM return (hook_stack_notify_unregister(net_getnetstackidbynetid(netid),
8977513SDarren.Reed@Sun.COM callback));
8987513SDarren.Reed@Sun.COM }
899