13448Sdh155122 /* 23448Sdh155122 * CDDL HEADER START 33448Sdh155122 * 43448Sdh155122 * The contents of this file are subject to the terms of the 53448Sdh155122 * Common Development and Distribution License (the "License"). 63448Sdh155122 * You may not use this file except in compliance with the License. 73448Sdh155122 * 83448Sdh155122 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93448Sdh155122 * or http://www.opensolaris.org/os/licensing. 103448Sdh155122 * See the License for the specific language governing permissions 113448Sdh155122 * and limitations under the License. 123448Sdh155122 * 133448Sdh155122 * When distributing Covered Code, include this CDDL HEADER in each 143448Sdh155122 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153448Sdh155122 * If applicable, add the following below this CDDL HEADER, with the 163448Sdh155122 * fields enclosed by brackets "[]" replaced with your own identifying 173448Sdh155122 * information: Portions Copyright [yyyy] [name of copyright owner] 183448Sdh155122 * 193448Sdh155122 * CDDL HEADER END 203448Sdh155122 */ 213448Sdh155122 223448Sdh155122 /* 23*5880Snordmark * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243448Sdh155122 * Use is subject to license terms. 253448Sdh155122 */ 263448Sdh155122 273448Sdh155122 #pragma ident "%Z%%M% %I% %E% SMI" 283448Sdh155122 293448Sdh155122 #include <sys/param.h> 303448Sdh155122 #include <sys/sysmacros.h> 313448Sdh155122 #include <sys/vm.h> 323448Sdh155122 #include <sys/proc.h> 333448Sdh155122 #include <sys/tuneable.h> 343448Sdh155122 #include <sys/systm.h> 353448Sdh155122 #include <sys/cmn_err.h> 363448Sdh155122 #include <sys/debug.h> 373448Sdh155122 #include <sys/sdt.h> 383448Sdh155122 #include <sys/mutex.h> 393448Sdh155122 #include <sys/bitmap.h> 403448Sdh155122 #include <sys/atomic.h> 413448Sdh155122 #include <sys/kobj.h> 423448Sdh155122 #include <sys/disp.h> 433448Sdh155122 #include <vm/seg_kmem.h> 443448Sdh155122 #include <sys/zone.h> 453448Sdh155122 #include <sys/netstack.h> 463448Sdh155122 473448Sdh155122 /* 483448Sdh155122 * What we use so that the zones framework can tell us about new zones, 493448Sdh155122 * which we use to create new stacks. 503448Sdh155122 */ 513448Sdh155122 static zone_key_t netstack_zone_key; 523448Sdh155122 533448Sdh155122 static int netstack_initialized = 0; 543448Sdh155122 553448Sdh155122 /* 563448Sdh155122 * Track the registered netstacks. 573448Sdh155122 * The global lock protects 583448Sdh155122 * - ns_reg 593448Sdh155122 * - the list starting at netstack_head and following the netstack_next 603448Sdh155122 * pointers. 613448Sdh155122 */ 623448Sdh155122 static kmutex_t netstack_g_lock; 633448Sdh155122 643448Sdh155122 /* 653448Sdh155122 * Registry of netstacks with their create/shutdown/destory functions. 663448Sdh155122 */ 673448Sdh155122 static struct netstack_registry ns_reg[NS_MAX]; 683448Sdh155122 693448Sdh155122 /* 703448Sdh155122 * Global list of existing stacks. We use this when a new zone with 713448Sdh155122 * an exclusive IP instance is created. 723448Sdh155122 * 733448Sdh155122 * Note that in some cases a netstack_t needs to stay around after the zone 743448Sdh155122 * has gone away. This is because there might be outstanding references 753448Sdh155122 * (from TCP TIME_WAIT connections, IPsec state, etc). The netstack_t data 763448Sdh155122 * structure and all the foo_stack_t's hanging off of it will be cleaned up 773448Sdh155122 * when the last reference to it is dropped. 783448Sdh155122 * However, the same zone might be rebooted. That is handled using the 793448Sdh155122 * assumption that the zones framework picks a new zoneid each time a zone 803448Sdh155122 * is (re)booted. We assert for that condition in netstack_zone_create(). 813448Sdh155122 * Thus the old netstack_t can take its time for things to time out. 823448Sdh155122 */ 833448Sdh155122 static netstack_t *netstack_head; 843448Sdh155122 853448Sdh155122 /* 863448Sdh155122 * To support kstat_create_netstack() using kstat_zone_add we need 873448Sdh155122 * to track both 883448Sdh155122 * - all zoneids that use the global/shared stack 893448Sdh155122 * - all kstats that have been added for the shared stack 903448Sdh155122 */ 913448Sdh155122 struct shared_zone_list { 923448Sdh155122 struct shared_zone_list *sz_next; 933448Sdh155122 zoneid_t sz_zoneid; 943448Sdh155122 }; 953448Sdh155122 963448Sdh155122 struct shared_kstat_list { 973448Sdh155122 struct shared_kstat_list *sk_next; 983448Sdh155122 kstat_t *sk_kstat; 993448Sdh155122 }; 1003448Sdh155122 1013448Sdh155122 static kmutex_t netstack_shared_lock; /* protects the following two */ 1023448Sdh155122 static struct shared_zone_list *netstack_shared_zones; 1033448Sdh155122 static struct shared_kstat_list *netstack_shared_kstats; 1043448Sdh155122 1053448Sdh155122 static void *netstack_zone_create(zoneid_t zoneid); 1063448Sdh155122 static void netstack_zone_shutdown(zoneid_t zoneid, void *arg); 1073448Sdh155122 static void netstack_zone_destroy(zoneid_t zoneid, void *arg); 1083448Sdh155122 1093448Sdh155122 static void netstack_shared_zone_add(zoneid_t zoneid); 1103448Sdh155122 static void netstack_shared_zone_remove(zoneid_t zoneid); 1113448Sdh155122 static void netstack_shared_kstat_add(kstat_t *ks); 1123448Sdh155122 static void netstack_shared_kstat_remove(kstat_t *ks); 1133448Sdh155122 1144287Snordmark typedef boolean_t applyfn_t(kmutex_t *, netstack_t *, int); 1153448Sdh155122 116*5880Snordmark static void apply_all_netstacks(int, applyfn_t *); 117*5880Snordmark static void apply_all_modules(netstack_t *, applyfn_t *); 118*5880Snordmark static void apply_all_modules_reverse(netstack_t *, applyfn_t *); 119*5880Snordmark static boolean_t netstack_apply_create(kmutex_t *, netstack_t *, int); 120*5880Snordmark static boolean_t netstack_apply_shutdown(kmutex_t *, netstack_t *, int); 121*5880Snordmark static boolean_t netstack_apply_destroy(kmutex_t *, netstack_t *, int); 122*5880Snordmark static boolean_t wait_for_zone_creator(netstack_t *, kmutex_t *); 123*5880Snordmark static boolean_t wait_for_nms_inprogress(netstack_t *, nm_state_t *, 124*5880Snordmark kmutex_t *); 125*5880Snordmark 1263448Sdh155122 void 1273448Sdh155122 netstack_init(void) 1283448Sdh155122 { 1293448Sdh155122 mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL); 1303448Sdh155122 mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL); 1313448Sdh155122 1323448Sdh155122 netstack_initialized = 1; 1333448Sdh155122 1343448Sdh155122 /* 1353448Sdh155122 * We want to be informed each time a zone is created or 1363448Sdh155122 * destroyed in the kernel, so we can maintain the 1373448Sdh155122 * stack instance information. 1383448Sdh155122 */ 1393448Sdh155122 zone_key_create(&netstack_zone_key, netstack_zone_create, 1403448Sdh155122 netstack_zone_shutdown, netstack_zone_destroy); 1413448Sdh155122 } 1423448Sdh155122 1433448Sdh155122 /* 1443448Sdh155122 * Register a new module with the framework. 1453448Sdh155122 * This registers interest in changes to the set of netstacks. 1463448Sdh155122 * The createfn and destroyfn are required, but the shutdownfn can be 1473448Sdh155122 * NULL. 1483448Sdh155122 * Note that due to the current zsd implementation, when the create 1493448Sdh155122 * function is called the zone isn't fully present, thus functions 1503448Sdh155122 * like zone_find_by_* will fail, hence the create function can not 1513448Sdh155122 * use many zones kernel functions including zcmn_err(). 1523448Sdh155122 */ 1533448Sdh155122 void 1543448Sdh155122 netstack_register(int moduleid, 1553448Sdh155122 void *(*module_create)(netstackid_t, netstack_t *), 1563448Sdh155122 void (*module_shutdown)(netstackid_t, void *), 1573448Sdh155122 void (*module_destroy)(netstackid_t, void *)) 1583448Sdh155122 { 1593448Sdh155122 netstack_t *ns; 1603448Sdh155122 1613448Sdh155122 ASSERT(netstack_initialized); 1623448Sdh155122 ASSERT(moduleid >= 0 && moduleid < NS_MAX); 1633448Sdh155122 ASSERT(module_create != NULL); 1643448Sdh155122 165*5880Snordmark /* 166*5880Snordmark * Make instances created after this point in time run the create 167*5880Snordmark * callback. 168*5880Snordmark */ 1693448Sdh155122 mutex_enter(&netstack_g_lock); 1703448Sdh155122 ASSERT(ns_reg[moduleid].nr_create == NULL); 1713448Sdh155122 ASSERT(ns_reg[moduleid].nr_flags == 0); 1723448Sdh155122 ns_reg[moduleid].nr_create = module_create; 1733448Sdh155122 ns_reg[moduleid].nr_shutdown = module_shutdown; 1743448Sdh155122 ns_reg[moduleid].nr_destroy = module_destroy; 1753448Sdh155122 ns_reg[moduleid].nr_flags = NRF_REGISTERED; 1763448Sdh155122 1773448Sdh155122 /* 1783448Sdh155122 * Determine the set of stacks that exist before we drop the lock. 179*5880Snordmark * Set NSS_CREATE_NEEDED for each of those. 1803448Sdh155122 * netstacks which have been deleted will have NSS_CREATE_COMPLETED 1813448Sdh155122 * set, but check NSF_CLOSING to be sure. 1823448Sdh155122 */ 1833448Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 184*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[moduleid]; 185*5880Snordmark 1863448Sdh155122 mutex_enter(&ns->netstack_lock); 1873448Sdh155122 if (!(ns->netstack_flags & NSF_CLOSING) && 188*5880Snordmark (nms->nms_flags & NSS_CREATE_ALL) == 0) { 189*5880Snordmark nms->nms_flags |= NSS_CREATE_NEEDED; 1903448Sdh155122 DTRACE_PROBE2(netstack__create__needed, 1913448Sdh155122 netstack_t *, ns, int, moduleid); 1923448Sdh155122 } 1933448Sdh155122 mutex_exit(&ns->netstack_lock); 1943448Sdh155122 } 1953448Sdh155122 mutex_exit(&netstack_g_lock); 1963448Sdh155122 1973448Sdh155122 /* 198*5880Snordmark * At this point in time a new instance can be created or an instance 199*5880Snordmark * can be destroyed, or some other module can register or unregister. 200*5880Snordmark * Make sure we either run all the create functions for this moduleid 201*5880Snordmark * or we wait for any other creators for this moduleid. 2023448Sdh155122 */ 203*5880Snordmark apply_all_netstacks(moduleid, netstack_apply_create); 2043448Sdh155122 } 2053448Sdh155122 2063448Sdh155122 void 2073448Sdh155122 netstack_unregister(int moduleid) 2083448Sdh155122 { 2093448Sdh155122 netstack_t *ns; 2103448Sdh155122 2113448Sdh155122 ASSERT(moduleid >= 0 && moduleid < NS_MAX); 2123448Sdh155122 2133448Sdh155122 ASSERT(ns_reg[moduleid].nr_create != NULL); 2143448Sdh155122 ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED); 2153448Sdh155122 2163448Sdh155122 mutex_enter(&netstack_g_lock); 2173448Sdh155122 /* 2183448Sdh155122 * Determine the set of stacks that exist before we drop the lock. 219*5880Snordmark * Set NSS_SHUTDOWN_NEEDED and NSS_DESTROY_NEEDED for each of those. 220*5880Snordmark * That ensures that when we return all the callbacks for existing 221*5880Snordmark * instances have completed. And since we set NRF_DYING no new 222*5880Snordmark * instances can use this module. 2233448Sdh155122 */ 2243448Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 225*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[moduleid]; 226*5880Snordmark 2273448Sdh155122 mutex_enter(&ns->netstack_lock); 2283448Sdh155122 if (ns_reg[moduleid].nr_shutdown != NULL && 229*5880Snordmark (nms->nms_flags & NSS_CREATE_COMPLETED) && 230*5880Snordmark (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) { 231*5880Snordmark nms->nms_flags |= NSS_SHUTDOWN_NEEDED; 2323448Sdh155122 DTRACE_PROBE2(netstack__shutdown__needed, 2333448Sdh155122 netstack_t *, ns, int, moduleid); 2343448Sdh155122 } 2353448Sdh155122 if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) && 2363448Sdh155122 ns_reg[moduleid].nr_destroy != NULL && 237*5880Snordmark (nms->nms_flags & NSS_CREATE_COMPLETED) && 238*5880Snordmark (nms->nms_flags & NSS_DESTROY_ALL) == 0) { 239*5880Snordmark nms->nms_flags |= NSS_DESTROY_NEEDED; 2403448Sdh155122 DTRACE_PROBE2(netstack__destroy__needed, 2413448Sdh155122 netstack_t *, ns, int, moduleid); 2423448Sdh155122 } 2433448Sdh155122 mutex_exit(&ns->netstack_lock); 2443448Sdh155122 } 245*5880Snordmark /* 246*5880Snordmark * Prevent any new netstack from calling the registered create 247*5880Snordmark * function, while keeping the function pointers in place until the 248*5880Snordmark * shutdown and destroy callbacks are complete. 249*5880Snordmark */ 250*5880Snordmark ns_reg[moduleid].nr_flags |= NRF_DYING; 2513448Sdh155122 mutex_exit(&netstack_g_lock); 2523448Sdh155122 253*5880Snordmark apply_all_netstacks(moduleid, netstack_apply_shutdown); 254*5880Snordmark apply_all_netstacks(moduleid, netstack_apply_destroy); 2553448Sdh155122 2563448Sdh155122 /* 257*5880Snordmark * Clear the nms_flags so that we can handle this module 2583448Sdh155122 * being loaded again. 259*5880Snordmark * Also remove the registered functions. 2603448Sdh155122 */ 2613448Sdh155122 mutex_enter(&netstack_g_lock); 262*5880Snordmark ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED); 263*5880Snordmark ASSERT(ns_reg[moduleid].nr_flags & NRF_DYING); 2643448Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 265*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[moduleid]; 266*5880Snordmark 2673448Sdh155122 mutex_enter(&ns->netstack_lock); 268*5880Snordmark if (nms->nms_flags & NSS_DESTROY_COMPLETED) { 269*5880Snordmark nms->nms_flags = 0; 2703448Sdh155122 DTRACE_PROBE2(netstack__destroy__done, 2713448Sdh155122 netstack_t *, ns, int, moduleid); 2723448Sdh155122 } 2733448Sdh155122 mutex_exit(&ns->netstack_lock); 2743448Sdh155122 } 2753448Sdh155122 2763448Sdh155122 ns_reg[moduleid].nr_create = NULL; 2773448Sdh155122 ns_reg[moduleid].nr_shutdown = NULL; 2783448Sdh155122 ns_reg[moduleid].nr_destroy = NULL; 2793448Sdh155122 ns_reg[moduleid].nr_flags = 0; 2803448Sdh155122 mutex_exit(&netstack_g_lock); 2813448Sdh155122 } 2823448Sdh155122 2833448Sdh155122 /* 2843448Sdh155122 * Lookup and/or allocate a netstack for this zone. 2853448Sdh155122 */ 2863448Sdh155122 static void * 2873448Sdh155122 netstack_zone_create(zoneid_t zoneid) 2883448Sdh155122 { 2893448Sdh155122 netstackid_t stackid; 2903448Sdh155122 netstack_t *ns; 2913448Sdh155122 netstack_t **nsp; 2923448Sdh155122 zone_t *zone; 2933448Sdh155122 int i; 2943448Sdh155122 2953448Sdh155122 ASSERT(netstack_initialized); 2963448Sdh155122 2973448Sdh155122 zone = zone_find_by_id_nolock(zoneid); 2983448Sdh155122 ASSERT(zone != NULL); 2993448Sdh155122 3003448Sdh155122 if (zone->zone_flags & ZF_NET_EXCL) { 3013448Sdh155122 stackid = zoneid; 3023448Sdh155122 } else { 3033448Sdh155122 /* Look for the stack instance for the global */ 3043448Sdh155122 stackid = GLOBAL_NETSTACKID; 3053448Sdh155122 } 3063448Sdh155122 3073448Sdh155122 /* Allocate even if it isn't needed; simplifies locking */ 3083448Sdh155122 ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP); 3093448Sdh155122 3103448Sdh155122 /* Look if there is a matching stack instance */ 3113448Sdh155122 mutex_enter(&netstack_g_lock); 3123448Sdh155122 for (nsp = &netstack_head; *nsp != NULL; 3133448Sdh155122 nsp = &((*nsp)->netstack_next)) { 3143448Sdh155122 if ((*nsp)->netstack_stackid == stackid) { 3153448Sdh155122 /* 3163448Sdh155122 * Should never find a pre-existing exclusive stack 3173448Sdh155122 */ 3183448Sdh155122 ASSERT(stackid == GLOBAL_NETSTACKID); 3193448Sdh155122 kmem_free(ns, sizeof (netstack_t)); 3203448Sdh155122 ns = *nsp; 3213448Sdh155122 mutex_enter(&ns->netstack_lock); 3223448Sdh155122 ns->netstack_numzones++; 3233448Sdh155122 mutex_exit(&ns->netstack_lock); 3243448Sdh155122 mutex_exit(&netstack_g_lock); 3253448Sdh155122 DTRACE_PROBE1(netstack__inc__numzones, 3263448Sdh155122 netstack_t *, ns); 3273448Sdh155122 /* Record that we have a new shared stack zone */ 3283448Sdh155122 netstack_shared_zone_add(zoneid); 3293448Sdh155122 zone->zone_netstack = ns; 3303448Sdh155122 return (ns); 3313448Sdh155122 } 3323448Sdh155122 } 3333448Sdh155122 /* Not found */ 3343448Sdh155122 mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL); 335*5880Snordmark cv_init(&ns->netstack_cv, NULL, CV_DEFAULT, NULL); 3363448Sdh155122 ns->netstack_stackid = zoneid; 3373448Sdh155122 ns->netstack_numzones = 1; 3383448Sdh155122 ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */ 3393448Sdh155122 ns->netstack_flags = NSF_UNINIT; 3403448Sdh155122 *nsp = ns; 3413448Sdh155122 zone->zone_netstack = ns; 3423448Sdh155122 343*5880Snordmark mutex_enter(&ns->netstack_lock); 344*5880Snordmark /* 345*5880Snordmark * Mark this netstack as having a CREATE running so 346*5880Snordmark * any netstack_register/netstack_unregister waits for 347*5880Snordmark * the existing create callbacks to complete in moduleid order 348*5880Snordmark */ 349*5880Snordmark ns->netstack_flags |= NSF_ZONE_CREATE; 350*5880Snordmark 3513448Sdh155122 /* 3523448Sdh155122 * Determine the set of module create functions that need to be 3533448Sdh155122 * called before we drop the lock. 354*5880Snordmark * Set NSS_CREATE_NEEDED for each of those. 355*5880Snordmark * Skip any with NRF_DYING set, since those are in the process of 356*5880Snordmark * going away, by checking for flags being exactly NRF_REGISTERED. 3573448Sdh155122 */ 3583448Sdh155122 for (i = 0; i < NS_MAX; i++) { 359*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[i]; 360*5880Snordmark 361*5880Snordmark cv_init(&nms->nms_cv, NULL, CV_DEFAULT, NULL); 362*5880Snordmark 363*5880Snordmark if ((ns_reg[i].nr_flags == NRF_REGISTERED) && 364*5880Snordmark (nms->nms_flags & NSS_CREATE_ALL) == 0) { 365*5880Snordmark nms->nms_flags |= NSS_CREATE_NEEDED; 3663448Sdh155122 DTRACE_PROBE2(netstack__create__needed, 3673448Sdh155122 netstack_t *, ns, int, i); 3683448Sdh155122 } 3693448Sdh155122 } 370*5880Snordmark mutex_exit(&ns->netstack_lock); 3713448Sdh155122 mutex_exit(&netstack_g_lock); 3723448Sdh155122 373*5880Snordmark apply_all_modules(ns, netstack_apply_create); 3743448Sdh155122 375*5880Snordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */ 3763448Sdh155122 mutex_enter(&ns->netstack_lock); 3773448Sdh155122 ns->netstack_flags &= ~NSF_UNINIT; 378*5880Snordmark ASSERT(ns->netstack_flags & NSF_ZONE_CREATE); 379*5880Snordmark ns->netstack_flags &= ~NSF_ZONE_CREATE; 380*5880Snordmark cv_broadcast(&ns->netstack_cv); 3813448Sdh155122 mutex_exit(&ns->netstack_lock); 3823448Sdh155122 3833448Sdh155122 return (ns); 3843448Sdh155122 } 3853448Sdh155122 3863448Sdh155122 /* ARGSUSED */ 3873448Sdh155122 static void 3883448Sdh155122 netstack_zone_shutdown(zoneid_t zoneid, void *arg) 3893448Sdh155122 { 3903448Sdh155122 netstack_t *ns = (netstack_t *)arg; 3913448Sdh155122 int i; 3923448Sdh155122 3933448Sdh155122 ASSERT(arg != NULL); 3943448Sdh155122 3953448Sdh155122 mutex_enter(&ns->netstack_lock); 3963448Sdh155122 ASSERT(ns->netstack_numzones > 0); 3973448Sdh155122 if (ns->netstack_numzones != 1) { 3983448Sdh155122 /* Stack instance being used by other zone */ 3993448Sdh155122 mutex_exit(&ns->netstack_lock); 4003448Sdh155122 ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID); 4013448Sdh155122 return; 4023448Sdh155122 } 4033448Sdh155122 mutex_exit(&ns->netstack_lock); 4043448Sdh155122 4053448Sdh155122 mutex_enter(&netstack_g_lock); 406*5880Snordmark mutex_enter(&ns->netstack_lock); 407*5880Snordmark /* 408*5880Snordmark * Mark this netstack as having a SHUTDOWN running so 409*5880Snordmark * any netstack_register/netstack_unregister waits for 410*5880Snordmark * the existing create callbacks to complete in moduleid order 411*5880Snordmark */ 412*5880Snordmark ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS)); 413*5880Snordmark ns->netstack_flags |= NSF_ZONE_SHUTDOWN; 414*5880Snordmark 4153448Sdh155122 /* 4163448Sdh155122 * Determine the set of stacks that exist before we drop the lock. 417*5880Snordmark * Set NSS_SHUTDOWN_NEEDED for each of those. 4183448Sdh155122 */ 4193448Sdh155122 for (i = 0; i < NS_MAX; i++) { 420*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[i]; 421*5880Snordmark 4223448Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 4233448Sdh155122 ns_reg[i].nr_shutdown != NULL && 424*5880Snordmark (nms->nms_flags & NSS_CREATE_COMPLETED) && 425*5880Snordmark (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) { 426*5880Snordmark nms->nms_flags |= NSS_SHUTDOWN_NEEDED; 4273448Sdh155122 DTRACE_PROBE2(netstack__shutdown__needed, 4283448Sdh155122 netstack_t *, ns, int, i); 4293448Sdh155122 } 4303448Sdh155122 } 431*5880Snordmark mutex_exit(&ns->netstack_lock); 4323448Sdh155122 mutex_exit(&netstack_g_lock); 4333448Sdh155122 4344287Snordmark /* 4354287Snordmark * Call the shutdown function for all registered modules for this 4364287Snordmark * netstack. 4374287Snordmark */ 438*5880Snordmark apply_all_modules(ns, netstack_apply_shutdown); 439*5880Snordmark 440*5880Snordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */ 441*5880Snordmark mutex_enter(&ns->netstack_lock); 442*5880Snordmark ASSERT(ns->netstack_flags & NSF_ZONE_SHUTDOWN); 443*5880Snordmark ns->netstack_flags &= ~NSF_ZONE_SHUTDOWN; 444*5880Snordmark cv_broadcast(&ns->netstack_cv); 445*5880Snordmark mutex_exit(&ns->netstack_lock); 4463448Sdh155122 } 4473448Sdh155122 4483448Sdh155122 /* 4493448Sdh155122 * Common routine to release a zone. 4503448Sdh155122 * If this was the last zone using the stack instance then prepare to 4513448Sdh155122 * have the refcnt dropping to zero free the zone. 4523448Sdh155122 */ 4533448Sdh155122 /* ARGSUSED */ 4543448Sdh155122 static void 4553448Sdh155122 netstack_zone_destroy(zoneid_t zoneid, void *arg) 4563448Sdh155122 { 4573448Sdh155122 netstack_t *ns = (netstack_t *)arg; 4583448Sdh155122 4593448Sdh155122 ASSERT(arg != NULL); 4603448Sdh155122 4613448Sdh155122 mutex_enter(&ns->netstack_lock); 4623448Sdh155122 ASSERT(ns->netstack_numzones > 0); 4633448Sdh155122 ns->netstack_numzones--; 4643448Sdh155122 if (ns->netstack_numzones != 0) { 4653448Sdh155122 /* Stack instance being used by other zone */ 4663448Sdh155122 mutex_exit(&ns->netstack_lock); 4673448Sdh155122 ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID); 4683448Sdh155122 /* Record that we a shared stack zone has gone away */ 4693448Sdh155122 netstack_shared_zone_remove(zoneid); 4703448Sdh155122 return; 4713448Sdh155122 } 4723448Sdh155122 /* 4734287Snordmark * Set CLOSING so that netstack_find_by will not find it. 4743448Sdh155122 */ 4753448Sdh155122 ns->netstack_flags |= NSF_CLOSING; 4763448Sdh155122 mutex_exit(&ns->netstack_lock); 4773448Sdh155122 DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns); 4783448Sdh155122 /* No other thread can call zone_destroy for this stack */ 4793448Sdh155122 4803448Sdh155122 /* 4813448Sdh155122 * Decrease refcnt to account for the one in netstack_zone_init() 4823448Sdh155122 */ 4833448Sdh155122 netstack_rele(ns); 4843448Sdh155122 } 4853448Sdh155122 4863448Sdh155122 /* 4873448Sdh155122 * Called when the reference count drops to zero. 4883448Sdh155122 * Call the destroy functions for each registered module. 4893448Sdh155122 */ 4903448Sdh155122 static void 4913448Sdh155122 netstack_stack_inactive(netstack_t *ns) 4923448Sdh155122 { 4933448Sdh155122 int i; 4943448Sdh155122 4953448Sdh155122 mutex_enter(&netstack_g_lock); 496*5880Snordmark mutex_enter(&ns->netstack_lock); 497*5880Snordmark /* 498*5880Snordmark * Mark this netstack as having a DESTROY running so 499*5880Snordmark * any netstack_register/netstack_unregister waits for 500*5880Snordmark * the existing destroy callbacks to complete in reverse moduleid order 501*5880Snordmark */ 502*5880Snordmark ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS)); 503*5880Snordmark ns->netstack_flags |= NSF_ZONE_DESTROY; 5043448Sdh155122 /* 5053448Sdh155122 * If the shutdown callback wasn't called earlier (e.g., if this is 506*5880Snordmark * a netstack shared between multiple zones), then we schedule it now. 507*5880Snordmark * 508*5880Snordmark * Determine the set of stacks that exist before we drop the lock. 509*5880Snordmark * Set NSS_DESTROY_NEEDED for each of those. That 510*5880Snordmark * ensures that when we return all the callbacks for existing 511*5880Snordmark * instances have completed. 5123448Sdh155122 */ 5133448Sdh155122 for (i = 0; i < NS_MAX; i++) { 514*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[i]; 515*5880Snordmark 5163448Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 5173448Sdh155122 ns_reg[i].nr_shutdown != NULL && 518*5880Snordmark (nms->nms_flags & NSS_CREATE_COMPLETED) && 519*5880Snordmark (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) { 520*5880Snordmark nms->nms_flags |= NSS_SHUTDOWN_NEEDED; 5213448Sdh155122 DTRACE_PROBE2(netstack__shutdown__needed, 5223448Sdh155122 netstack_t *, ns, int, i); 5233448Sdh155122 } 524*5880Snordmark 5253448Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 5263448Sdh155122 ns_reg[i].nr_destroy != NULL && 527*5880Snordmark (nms->nms_flags & NSS_CREATE_COMPLETED) && 528*5880Snordmark (nms->nms_flags & NSS_DESTROY_ALL) == 0) { 529*5880Snordmark nms->nms_flags |= NSS_DESTROY_NEEDED; 5303448Sdh155122 DTRACE_PROBE2(netstack__destroy__needed, 5313448Sdh155122 netstack_t *, ns, int, i); 5323448Sdh155122 } 5333448Sdh155122 } 534*5880Snordmark mutex_exit(&ns->netstack_lock); 5353448Sdh155122 mutex_exit(&netstack_g_lock); 5363448Sdh155122 5374287Snordmark /* 5384287Snordmark * Call the shutdown and destroy functions for all registered modules 5394287Snordmark * for this netstack. 540*5880Snordmark * 541*5880Snordmark * Since there are some ordering dependencies between the modules we 542*5880Snordmark * tear them down in the reverse order of what was used to create them. 543*5880Snordmark * 544*5880Snordmark * Since a netstack_t is never reused (when a zone is rebooted it gets 545*5880Snordmark * a new zoneid == netstackid i.e. a new netstack_t is allocated) we 546*5880Snordmark * leave nms_flags the way it is i.e. with NSS_DESTROY_COMPLETED set. 547*5880Snordmark * That is different than in the netstack_unregister() case. 5484287Snordmark */ 549*5880Snordmark apply_all_modules(ns, netstack_apply_shutdown); 550*5880Snordmark apply_all_modules_reverse(ns, netstack_apply_destroy); 5513448Sdh155122 552*5880Snordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */ 5533448Sdh155122 mutex_enter(&ns->netstack_lock); 554*5880Snordmark ASSERT(ns->netstack_flags & NSF_ZONE_DESTROY); 555*5880Snordmark ns->netstack_flags &= ~NSF_ZONE_DESTROY; 556*5880Snordmark cv_broadcast(&ns->netstack_cv); 557*5880Snordmark mutex_exit(&ns->netstack_lock); 5583448Sdh155122 } 5593448Sdh155122 5604287Snordmark /* 5614287Snordmark * Apply a function to all netstacks for a particular moduleid. 5624287Snordmark * 563*5880Snordmark * If there is any zone activity (due to a zone being created, shutdown, 564*5880Snordmark * or destroyed) we wait for that to complete before we proceed. This ensures 565*5880Snordmark * that the moduleids are processed in order when a zone is created or 566*5880Snordmark * destroyed. 567*5880Snordmark * 5684287Snordmark * The applyfn has to drop netstack_g_lock if it does some work. 569*5880Snordmark * In that case we don't follow netstack_next, 570*5880Snordmark * even if it is possible to do so without any hazards. This is 5714287Snordmark * because we want the design to allow for the list of netstacks threaded 5724287Snordmark * by netstack_next to change in any arbitrary way during the time the 5734287Snordmark * lock was dropped. 5744287Snordmark * 5754287Snordmark * It is safe to restart the loop at netstack_head since the applyfn 5764287Snordmark * changes netstack_m_state as it processes things, so a subsequent 5774287Snordmark * pass through will have no effect in applyfn, hence the loop will terminate 5784287Snordmark * in at worst O(N^2). 5794287Snordmark */ 5803448Sdh155122 static void 5814287Snordmark apply_all_netstacks(int moduleid, applyfn_t *applyfn) 5823448Sdh155122 { 5833448Sdh155122 netstack_t *ns; 5843448Sdh155122 5854287Snordmark mutex_enter(&netstack_g_lock); 5864287Snordmark ns = netstack_head; 5873448Sdh155122 while (ns != NULL) { 588*5880Snordmark if (wait_for_zone_creator(ns, &netstack_g_lock)) { 5894287Snordmark /* Lock dropped - restart at head */ 590*5880Snordmark ns = netstack_head; 591*5880Snordmark } else if ((applyfn)(&netstack_g_lock, ns, moduleid)) { 592*5880Snordmark /* Lock dropped - restart at head */ 5934287Snordmark ns = netstack_head; 5943448Sdh155122 } else { 5953448Sdh155122 ns = ns->netstack_next; 5963448Sdh155122 } 5973448Sdh155122 } 5984287Snordmark mutex_exit(&netstack_g_lock); 5993448Sdh155122 } 6003448Sdh155122 6013448Sdh155122 /* 6024287Snordmark * Apply a function to all moduleids for a particular netstack. 6034287Snordmark * 6044287Snordmark * Since the netstack linkage doesn't matter in this case we can 6054287Snordmark * ignore whether the function drops the lock. 6064287Snordmark */ 6074287Snordmark static void 6084287Snordmark apply_all_modules(netstack_t *ns, applyfn_t *applyfn) 6094287Snordmark { 6104287Snordmark int i; 6114287Snordmark 6124287Snordmark mutex_enter(&netstack_g_lock); 6134287Snordmark for (i = 0; i < NS_MAX; i++) { 614*5880Snordmark /* 615*5880Snordmark * We don't care whether the lock was dropped 616*5880Snordmark * since we are not iterating over netstack_head. 617*5880Snordmark */ 618*5880Snordmark (void) (applyfn)(&netstack_g_lock, ns, i); 6194287Snordmark } 6204287Snordmark mutex_exit(&netstack_g_lock); 6214287Snordmark } 6224287Snordmark 6234287Snordmark /* Like the above but in reverse moduleid order */ 6244287Snordmark static void 6254287Snordmark apply_all_modules_reverse(netstack_t *ns, applyfn_t *applyfn) 6264287Snordmark { 6274287Snordmark int i; 6284287Snordmark 6294287Snordmark mutex_enter(&netstack_g_lock); 6304287Snordmark for (i = NS_MAX-1; i >= 0; i--) { 631*5880Snordmark /* 632*5880Snordmark * We don't care whether the lock was dropped 633*5880Snordmark * since we are not iterating over netstack_head. 634*5880Snordmark */ 635*5880Snordmark (void) (applyfn)(&netstack_g_lock, ns, i); 6364287Snordmark } 6374287Snordmark mutex_exit(&netstack_g_lock); 6384287Snordmark } 6394287Snordmark 6404287Snordmark /* 641*5880Snordmark * Call the create function for the ns and moduleid if CREATE_NEEDED 642*5880Snordmark * is set. 643*5880Snordmark * If some other thread gets here first and sets *_INPROGRESS, then 644*5880Snordmark * we wait for that thread to complete so that we can ensure that 645*5880Snordmark * all the callbacks are done when we've looped over all netstacks/moduleids. 6464287Snordmark * 647*5880Snordmark * When we call the create function, we temporarily drop the netstack_lock 648*5880Snordmark * held by the caller, and return true to tell the caller it needs to 649*5880Snordmark * re-evalute the state. 6503448Sdh155122 */ 651*5880Snordmark static boolean_t 652*5880Snordmark netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid) 6533448Sdh155122 { 654*5880Snordmark void *result; 655*5880Snordmark netstackid_t stackid; 656*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[moduleid]; 657*5880Snordmark boolean_t dropped = B_FALSE; 658*5880Snordmark 659*5880Snordmark ASSERT(MUTEX_HELD(lockp)); 660*5880Snordmark mutex_enter(&ns->netstack_lock); 661*5880Snordmark 662*5880Snordmark if (wait_for_nms_inprogress(ns, nms, lockp)) 663*5880Snordmark dropped = B_TRUE; 664*5880Snordmark 665*5880Snordmark if (nms->nms_flags & NSS_CREATE_NEEDED) { 666*5880Snordmark nms->nms_flags &= ~NSS_CREATE_NEEDED; 667*5880Snordmark nms->nms_flags |= NSS_CREATE_INPROGRESS; 668*5880Snordmark DTRACE_PROBE2(netstack__create__inprogress, 669*5880Snordmark netstack_t *, ns, int, moduleid); 670*5880Snordmark mutex_exit(&ns->netstack_lock); 671*5880Snordmark mutex_exit(lockp); 672*5880Snordmark dropped = B_TRUE; 673*5880Snordmark 674*5880Snordmark ASSERT(ns_reg[moduleid].nr_create != NULL); 675*5880Snordmark stackid = ns->netstack_stackid; 676*5880Snordmark DTRACE_PROBE2(netstack__create__start, 677*5880Snordmark netstackid_t, stackid, 678*5880Snordmark netstack_t *, ns); 679*5880Snordmark result = (ns_reg[moduleid].nr_create)(stackid, ns); 680*5880Snordmark DTRACE_PROBE2(netstack__create__end, 681*5880Snordmark void *, result, netstack_t *, ns); 682*5880Snordmark 683*5880Snordmark ASSERT(result != NULL); 684*5880Snordmark mutex_enter(lockp); 685*5880Snordmark mutex_enter(&ns->netstack_lock); 686*5880Snordmark ns->netstack_modules[moduleid] = result; 687*5880Snordmark nms->nms_flags &= ~NSS_CREATE_INPROGRESS; 688*5880Snordmark nms->nms_flags |= NSS_CREATE_COMPLETED; 689*5880Snordmark cv_broadcast(&nms->nms_cv); 690*5880Snordmark DTRACE_PROBE2(netstack__create__completed, 691*5880Snordmark netstack_t *, ns, int, moduleid); 692*5880Snordmark mutex_exit(&ns->netstack_lock); 693*5880Snordmark return (dropped); 6944287Snordmark } else { 695*5880Snordmark mutex_exit(&ns->netstack_lock); 696*5880Snordmark return (dropped); 697*5880Snordmark } 698*5880Snordmark } 699*5880Snordmark 700*5880Snordmark /* 701*5880Snordmark * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED 702*5880Snordmark * is set. 703*5880Snordmark * If some other thread gets here first and sets *_INPROGRESS, then 704*5880Snordmark * we wait for that thread to complete so that we can ensure that 705*5880Snordmark * all the callbacks are done when we've looped over all netstacks/moduleids. 706*5880Snordmark * 707*5880Snordmark * When we call the shutdown function, we temporarily drop the netstack_lock 708*5880Snordmark * held by the caller, and return true to tell the caller it needs to 709*5880Snordmark * re-evalute the state. 710*5880Snordmark */ 711*5880Snordmark static boolean_t 712*5880Snordmark netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid) 713*5880Snordmark { 714*5880Snordmark netstackid_t stackid; 715*5880Snordmark void * netstack_module; 716*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[moduleid]; 717*5880Snordmark boolean_t dropped = B_FALSE; 718*5880Snordmark 719*5880Snordmark ASSERT(MUTEX_HELD(lockp)); 720*5880Snordmark mutex_enter(&ns->netstack_lock); 721*5880Snordmark 722*5880Snordmark if (wait_for_nms_inprogress(ns, nms, lockp)) 723*5880Snordmark dropped = B_TRUE; 7244287Snordmark 725*5880Snordmark if (nms->nms_flags & NSS_SHUTDOWN_NEEDED) { 726*5880Snordmark nms->nms_flags &= ~NSS_SHUTDOWN_NEEDED; 727*5880Snordmark nms->nms_flags |= NSS_SHUTDOWN_INPROGRESS; 728*5880Snordmark DTRACE_PROBE2(netstack__shutdown__inprogress, 729*5880Snordmark netstack_t *, ns, int, moduleid); 730*5880Snordmark mutex_exit(&ns->netstack_lock); 731*5880Snordmark mutex_exit(lockp); 732*5880Snordmark dropped = B_TRUE; 733*5880Snordmark 734*5880Snordmark ASSERT(ns_reg[moduleid].nr_shutdown != NULL); 735*5880Snordmark stackid = ns->netstack_stackid; 736*5880Snordmark netstack_module = ns->netstack_modules[moduleid]; 737*5880Snordmark DTRACE_PROBE2(netstack__shutdown__start, 738*5880Snordmark netstackid_t, stackid, 739*5880Snordmark void *, netstack_module); 740*5880Snordmark (ns_reg[moduleid].nr_shutdown)(stackid, netstack_module); 741*5880Snordmark DTRACE_PROBE1(netstack__shutdown__end, 742*5880Snordmark netstack_t *, ns); 743*5880Snordmark 744*5880Snordmark mutex_enter(lockp); 745*5880Snordmark mutex_enter(&ns->netstack_lock); 746*5880Snordmark nms->nms_flags &= ~NSS_SHUTDOWN_INPROGRESS; 747*5880Snordmark nms->nms_flags |= NSS_SHUTDOWN_COMPLETED; 748*5880Snordmark cv_broadcast(&nms->nms_cv); 749*5880Snordmark DTRACE_PROBE2(netstack__shutdown__completed, 750*5880Snordmark netstack_t *, ns, int, moduleid); 751*5880Snordmark mutex_exit(&ns->netstack_lock); 752*5880Snordmark return (dropped); 753*5880Snordmark } else { 754*5880Snordmark mutex_exit(&ns->netstack_lock); 755*5880Snordmark return (dropped); 7564287Snordmark } 7573448Sdh155122 } 7583448Sdh155122 7593448Sdh155122 /* 760*5880Snordmark * Call the destroy function for the ns and moduleid if DESTROY_NEEDED 761*5880Snordmark * is set. 762*5880Snordmark * If some other thread gets here first and sets *_INPROGRESS, then 763*5880Snordmark * we wait for that thread to complete so that we can ensure that 764*5880Snordmark * all the callbacks are done when we've looped over all netstacks/moduleids. 7653448Sdh155122 * 766*5880Snordmark * When we call the destroy function, we temporarily drop the netstack_lock 767*5880Snordmark * held by the caller, and return true to tell the caller it needs to 768*5880Snordmark * re-evalute the state. 7693448Sdh155122 */ 770*5880Snordmark static boolean_t 771*5880Snordmark netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid) 7723448Sdh155122 { 773*5880Snordmark netstackid_t stackid; 774*5880Snordmark void * netstack_module; 775*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[moduleid]; 776*5880Snordmark boolean_t dropped = B_FALSE; 777*5880Snordmark 778*5880Snordmark ASSERT(MUTEX_HELD(lockp)); 779*5880Snordmark mutex_enter(&ns->netstack_lock); 780*5880Snordmark 781*5880Snordmark if (wait_for_nms_inprogress(ns, nms, lockp)) 782*5880Snordmark dropped = B_TRUE; 783*5880Snordmark 784*5880Snordmark if (nms->nms_flags & NSS_DESTROY_NEEDED) { 785*5880Snordmark nms->nms_flags &= ~NSS_DESTROY_NEEDED; 786*5880Snordmark nms->nms_flags |= NSS_DESTROY_INPROGRESS; 787*5880Snordmark DTRACE_PROBE2(netstack__destroy__inprogress, 788*5880Snordmark netstack_t *, ns, int, moduleid); 789*5880Snordmark mutex_exit(&ns->netstack_lock); 790*5880Snordmark mutex_exit(lockp); 791*5880Snordmark dropped = B_TRUE; 792*5880Snordmark 793*5880Snordmark ASSERT(ns_reg[moduleid].nr_destroy != NULL); 794*5880Snordmark stackid = ns->netstack_stackid; 795*5880Snordmark netstack_module = ns->netstack_modules[moduleid]; 796*5880Snordmark DTRACE_PROBE2(netstack__destroy__start, 797*5880Snordmark netstackid_t, stackid, 798*5880Snordmark void *, netstack_module); 799*5880Snordmark (ns_reg[moduleid].nr_destroy)(stackid, netstack_module); 800*5880Snordmark DTRACE_PROBE1(netstack__destroy__end, 801*5880Snordmark netstack_t *, ns); 802*5880Snordmark 803*5880Snordmark mutex_enter(lockp); 804*5880Snordmark mutex_enter(&ns->netstack_lock); 805*5880Snordmark ns->netstack_modules[moduleid] = NULL; 806*5880Snordmark nms->nms_flags &= ~NSS_DESTROY_INPROGRESS; 807*5880Snordmark nms->nms_flags |= NSS_DESTROY_COMPLETED; 808*5880Snordmark cv_broadcast(&nms->nms_cv); 809*5880Snordmark DTRACE_PROBE2(netstack__destroy__completed, 810*5880Snordmark netstack_t *, ns, int, moduleid); 811*5880Snordmark mutex_exit(&ns->netstack_lock); 812*5880Snordmark return (dropped); 813*5880Snordmark } else { 814*5880Snordmark mutex_exit(&ns->netstack_lock); 815*5880Snordmark return (dropped); 816*5880Snordmark } 8173448Sdh155122 } 8183448Sdh155122 8193448Sdh155122 /* 820*5880Snordmark * If somebody is creating the netstack (due to a new zone being created) 821*5880Snordmark * then we wait for them to complete. This ensures that any additional 822*5880Snordmark * netstack_register() doesn't cause the create functions to run out of 823*5880Snordmark * order. 824*5880Snordmark * Note that we do not need such a global wait in the case of the shutdown 825*5880Snordmark * and destroy callbacks, since in that case it is sufficient for both 826*5880Snordmark * threads to set NEEDED and wait for INPROGRESS to ensure ordering. 827*5880Snordmark * Returns true if lockp was temporarily dropped while waiting. 8283448Sdh155122 */ 829*5880Snordmark static boolean_t 830*5880Snordmark wait_for_zone_creator(netstack_t *ns, kmutex_t *lockp) 8313448Sdh155122 { 832*5880Snordmark boolean_t dropped = B_FALSE; 833*5880Snordmark 834*5880Snordmark mutex_enter(&ns->netstack_lock); 835*5880Snordmark while (ns->netstack_flags & NSF_ZONE_CREATE) { 836*5880Snordmark DTRACE_PROBE1(netstack__wait__zone__inprogress, 837*5880Snordmark netstack_t *, ns); 838*5880Snordmark if (lockp != NULL) { 839*5880Snordmark dropped = B_TRUE; 840*5880Snordmark mutex_exit(lockp); 841*5880Snordmark } 842*5880Snordmark cv_wait(&ns->netstack_cv, &ns->netstack_lock); 843*5880Snordmark if (lockp != NULL) { 844*5880Snordmark /* First drop netstack_lock to preserve order */ 845*5880Snordmark mutex_exit(&ns->netstack_lock); 846*5880Snordmark mutex_enter(lockp); 847*5880Snordmark mutex_enter(&ns->netstack_lock); 848*5880Snordmark } 849*5880Snordmark } 850*5880Snordmark mutex_exit(&ns->netstack_lock); 851*5880Snordmark return (dropped); 8523448Sdh155122 } 8533448Sdh155122 8543448Sdh155122 /* 855*5880Snordmark * Wait for any INPROGRESS flag to be cleared for the netstack/moduleid 856*5880Snordmark * combination. 857*5880Snordmark * Returns true if lockp was temporarily dropped while waiting. 8583448Sdh155122 */ 859*5880Snordmark static boolean_t 860*5880Snordmark wait_for_nms_inprogress(netstack_t *ns, nm_state_t *nms, kmutex_t *lockp) 8613448Sdh155122 { 862*5880Snordmark boolean_t dropped = B_FALSE; 863*5880Snordmark 864*5880Snordmark while (nms->nms_flags & NSS_ALL_INPROGRESS) { 865*5880Snordmark DTRACE_PROBE2(netstack__wait__nms__inprogress, 866*5880Snordmark netstack_t *, ns, nm_state_t *, nms); 867*5880Snordmark if (lockp != NULL) { 868*5880Snordmark dropped = B_TRUE; 869*5880Snordmark mutex_exit(lockp); 870*5880Snordmark } 871*5880Snordmark cv_wait(&nms->nms_cv, &ns->netstack_lock); 872*5880Snordmark if (lockp != NULL) { 873*5880Snordmark /* First drop netstack_lock to preserve order */ 874*5880Snordmark mutex_exit(&ns->netstack_lock); 875*5880Snordmark mutex_enter(lockp); 876*5880Snordmark mutex_enter(&ns->netstack_lock); 877*5880Snordmark } 878*5880Snordmark } 879*5880Snordmark return (dropped); 8803448Sdh155122 } 8813448Sdh155122 8823448Sdh155122 /* 8833448Sdh155122 * Get the stack instance used in caller's zone. 8843448Sdh155122 * Increases the reference count, caller must do a netstack_rele. 8853448Sdh155122 * It can't be called after zone_destroy() has started. 8863448Sdh155122 */ 8874136Snordmark netstack_t * 8883448Sdh155122 netstack_get_current(void) 8893448Sdh155122 { 8903448Sdh155122 netstack_t *ns; 8913448Sdh155122 8923448Sdh155122 ns = curproc->p_zone->zone_netstack; 8933448Sdh155122 ASSERT(ns != NULL); 8943448Sdh155122 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) 8953448Sdh155122 return (NULL); 8963448Sdh155122 8973448Sdh155122 netstack_hold(ns); 8983448Sdh155122 8993448Sdh155122 return (ns); 9003448Sdh155122 } 9013448Sdh155122 9023448Sdh155122 /* 9033448Sdh155122 * Find a stack instance given the cred. 9043448Sdh155122 * This is used by the modules to potentially allow for a future when 9053448Sdh155122 * something other than the zoneid is used to determine the stack. 9063448Sdh155122 */ 9073448Sdh155122 netstack_t * 9083448Sdh155122 netstack_find_by_cred(const cred_t *cr) 9093448Sdh155122 { 9103448Sdh155122 zoneid_t zoneid = crgetzoneid(cr); 9113448Sdh155122 9123448Sdh155122 /* Handle the case when cr_zone is NULL */ 9133448Sdh155122 if (zoneid == (zoneid_t)-1) 9143448Sdh155122 zoneid = GLOBAL_ZONEID; 9153448Sdh155122 9163448Sdh155122 /* For performance ... */ 9173448Sdh155122 if (curproc->p_zone->zone_id == zoneid) 9183448Sdh155122 return (netstack_get_current()); 9193448Sdh155122 else 9203448Sdh155122 return (netstack_find_by_zoneid(zoneid)); 9213448Sdh155122 } 9223448Sdh155122 9233448Sdh155122 /* 9243448Sdh155122 * Find a stack instance given the zoneid. 9253448Sdh155122 * Increases the reference count if found; caller must do a 9263448Sdh155122 * netstack_rele(). 9273448Sdh155122 * 9283448Sdh155122 * If there is no exact match then assume the shared stack instance 9293448Sdh155122 * matches. 9303448Sdh155122 * 9313448Sdh155122 * Skip the unitialized ones. 9323448Sdh155122 */ 9333448Sdh155122 netstack_t * 9343448Sdh155122 netstack_find_by_zoneid(zoneid_t zoneid) 9353448Sdh155122 { 9363448Sdh155122 netstack_t *ns; 9373448Sdh155122 zone_t *zone; 9383448Sdh155122 9393448Sdh155122 zone = zone_find_by_id(zoneid); 9403448Sdh155122 9413448Sdh155122 if (zone == NULL) 9423448Sdh155122 return (NULL); 9433448Sdh155122 9443448Sdh155122 ns = zone->zone_netstack; 9453448Sdh155122 ASSERT(ns != NULL); 9463448Sdh155122 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) 9473448Sdh155122 ns = NULL; 9483448Sdh155122 else 9493448Sdh155122 netstack_hold(ns); 9503448Sdh155122 9513448Sdh155122 zone_rele(zone); 9523448Sdh155122 return (ns); 9533448Sdh155122 } 9543448Sdh155122 9553448Sdh155122 /* 956*5880Snordmark * Find a stack instance given the zoneid. Can only be called from 957*5880Snordmark * the create callback. See the comments in zone_find_by_id_nolock why 958*5880Snordmark * that limitation exists. 959*5880Snordmark * 9603448Sdh155122 * Increases the reference count if found; caller must do a 9613448Sdh155122 * netstack_rele(). 9623448Sdh155122 * 9633448Sdh155122 * If there is no exact match then assume the shared stack instance 9643448Sdh155122 * matches. 9653448Sdh155122 * 9663448Sdh155122 * Skip the unitialized ones. 9673448Sdh155122 */ 9683448Sdh155122 netstack_t * 9693448Sdh155122 netstack_find_by_zoneid_nolock(zoneid_t zoneid) 9703448Sdh155122 { 9713448Sdh155122 netstack_t *ns; 9723448Sdh155122 zone_t *zone; 9733448Sdh155122 9743448Sdh155122 zone = zone_find_by_id_nolock(zoneid); 9753448Sdh155122 9763448Sdh155122 if (zone == NULL) 9773448Sdh155122 return (NULL); 9783448Sdh155122 9793448Sdh155122 ns = zone->zone_netstack; 9803448Sdh155122 ASSERT(ns != NULL); 9813448Sdh155122 9823448Sdh155122 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) 9833448Sdh155122 ns = NULL; 9843448Sdh155122 else 9853448Sdh155122 netstack_hold(ns); 9863448Sdh155122 987*5880Snordmark /* zone_find_by_id_nolock does not have a hold on the zone */ 9883448Sdh155122 return (ns); 9893448Sdh155122 } 9903448Sdh155122 9913448Sdh155122 /* 9923448Sdh155122 * Find a stack instance given the stackid with exact match? 9933448Sdh155122 * Increases the reference count if found; caller must do a 9943448Sdh155122 * netstack_rele(). 9953448Sdh155122 * 9963448Sdh155122 * Skip the unitialized ones. 9973448Sdh155122 */ 9983448Sdh155122 netstack_t * 9993448Sdh155122 netstack_find_by_stackid(netstackid_t stackid) 10003448Sdh155122 { 10013448Sdh155122 netstack_t *ns; 10023448Sdh155122 10033448Sdh155122 mutex_enter(&netstack_g_lock); 10043448Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 10053448Sdh155122 mutex_enter(&ns->netstack_lock); 10063448Sdh155122 if (ns->netstack_stackid == stackid && 10073448Sdh155122 !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) { 10083448Sdh155122 mutex_exit(&ns->netstack_lock); 10093448Sdh155122 netstack_hold(ns); 10103448Sdh155122 mutex_exit(&netstack_g_lock); 10113448Sdh155122 return (ns); 10123448Sdh155122 } 10133448Sdh155122 mutex_exit(&ns->netstack_lock); 10143448Sdh155122 } 10153448Sdh155122 mutex_exit(&netstack_g_lock); 10163448Sdh155122 return (NULL); 10173448Sdh155122 } 10183448Sdh155122 10193448Sdh155122 void 10203448Sdh155122 netstack_rele(netstack_t *ns) 10213448Sdh155122 { 10223448Sdh155122 netstack_t **nsp; 10233448Sdh155122 boolean_t found; 10243448Sdh155122 int refcnt, numzones; 1025*5880Snordmark int i; 10263448Sdh155122 10273448Sdh155122 mutex_enter(&ns->netstack_lock); 10283448Sdh155122 ASSERT(ns->netstack_refcnt > 0); 10293448Sdh155122 ns->netstack_refcnt--; 10303448Sdh155122 /* 10313448Sdh155122 * As we drop the lock additional netstack_rele()s can come in 10323448Sdh155122 * and decrement the refcnt to zero and free the netstack_t. 10333448Sdh155122 * Store pointers in local variables and if we were not the last 10343448Sdh155122 * then don't reference the netstack_t after that. 10353448Sdh155122 */ 10363448Sdh155122 refcnt = ns->netstack_refcnt; 10373448Sdh155122 numzones = ns->netstack_numzones; 10383448Sdh155122 DTRACE_PROBE1(netstack__dec__ref, netstack_t *, ns); 10393448Sdh155122 mutex_exit(&ns->netstack_lock); 10403448Sdh155122 10413448Sdh155122 if (refcnt == 0 && numzones == 0) { 10423448Sdh155122 /* 10433448Sdh155122 * Time to call the destroy functions and free up 10443448Sdh155122 * the structure 10453448Sdh155122 */ 10463448Sdh155122 netstack_stack_inactive(ns); 10473448Sdh155122 10484287Snordmark /* Make sure nothing increased the references */ 10494287Snordmark ASSERT(ns->netstack_refcnt == 0); 10504287Snordmark ASSERT(ns->netstack_numzones == 0); 10514287Snordmark 10523448Sdh155122 /* Finally remove from list of netstacks */ 10533448Sdh155122 mutex_enter(&netstack_g_lock); 10543448Sdh155122 found = B_FALSE; 10553448Sdh155122 for (nsp = &netstack_head; *nsp != NULL; 10563448Sdh155122 nsp = &(*nsp)->netstack_next) { 10573448Sdh155122 if (*nsp == ns) { 10583448Sdh155122 *nsp = ns->netstack_next; 10593448Sdh155122 ns->netstack_next = NULL; 10603448Sdh155122 found = B_TRUE; 10613448Sdh155122 break; 10623448Sdh155122 } 10633448Sdh155122 } 10643448Sdh155122 ASSERT(found); 10653448Sdh155122 mutex_exit(&netstack_g_lock); 10663448Sdh155122 10674287Snordmark /* Make sure nothing increased the references */ 10684287Snordmark ASSERT(ns->netstack_refcnt == 0); 10694287Snordmark ASSERT(ns->netstack_numzones == 0); 10704287Snordmark 10713448Sdh155122 ASSERT(ns->netstack_flags & NSF_CLOSING); 1072*5880Snordmark 1073*5880Snordmark for (i = 0; i < NS_MAX; i++) { 1074*5880Snordmark nm_state_t *nms = &ns->netstack_m_state[i]; 1075*5880Snordmark 1076*5880Snordmark cv_destroy(&nms->nms_cv); 1077*5880Snordmark } 1078*5880Snordmark mutex_destroy(&ns->netstack_lock); 1079*5880Snordmark cv_destroy(&ns->netstack_cv); 10803448Sdh155122 kmem_free(ns, sizeof (*ns)); 10813448Sdh155122 } 10823448Sdh155122 } 10833448Sdh155122 10843448Sdh155122 void 10853448Sdh155122 netstack_hold(netstack_t *ns) 10863448Sdh155122 { 10873448Sdh155122 mutex_enter(&ns->netstack_lock); 10883448Sdh155122 ns->netstack_refcnt++; 10893448Sdh155122 ASSERT(ns->netstack_refcnt > 0); 10903448Sdh155122 mutex_exit(&ns->netstack_lock); 10913448Sdh155122 DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns); 10923448Sdh155122 } 10933448Sdh155122 10943448Sdh155122 /* 10953448Sdh155122 * To support kstat_create_netstack() using kstat_zone_add we need 10963448Sdh155122 * to track both 10973448Sdh155122 * - all zoneids that use the global/shared stack 10983448Sdh155122 * - all kstats that have been added for the shared stack 10993448Sdh155122 */ 11003448Sdh155122 kstat_t * 11013448Sdh155122 kstat_create_netstack(char *ks_module, int ks_instance, char *ks_name, 11023448Sdh155122 char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags, 11033448Sdh155122 netstackid_t ks_netstackid) 11043448Sdh155122 { 11053448Sdh155122 kstat_t *ks; 11063448Sdh155122 11073448Sdh155122 if (ks_netstackid == GLOBAL_NETSTACKID) { 11083448Sdh155122 ks = kstat_create_zone(ks_module, ks_instance, ks_name, 11093448Sdh155122 ks_class, ks_type, ks_ndata, ks_flags, GLOBAL_ZONEID); 11103448Sdh155122 if (ks != NULL) 11113448Sdh155122 netstack_shared_kstat_add(ks); 11123448Sdh155122 return (ks); 11133448Sdh155122 } else { 11143448Sdh155122 zoneid_t zoneid = ks_netstackid; 11153448Sdh155122 11163448Sdh155122 return (kstat_create_zone(ks_module, ks_instance, ks_name, 1117*5880Snordmark ks_class, ks_type, ks_ndata, ks_flags, zoneid)); 11183448Sdh155122 } 11193448Sdh155122 } 11203448Sdh155122 11213448Sdh155122 void 11223448Sdh155122 kstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid) 11233448Sdh155122 { 11243448Sdh155122 if (ks_netstackid == GLOBAL_NETSTACKID) { 11253448Sdh155122 netstack_shared_kstat_remove(ks); 11263448Sdh155122 } 11273448Sdh155122 kstat_delete(ks); 11283448Sdh155122 } 11293448Sdh155122 11303448Sdh155122 static void 11313448Sdh155122 netstack_shared_zone_add(zoneid_t zoneid) 11323448Sdh155122 { 11333448Sdh155122 struct shared_zone_list *sz; 11343448Sdh155122 struct shared_kstat_list *sk; 11353448Sdh155122 11363448Sdh155122 sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP); 11373448Sdh155122 sz->sz_zoneid = zoneid; 11383448Sdh155122 11393448Sdh155122 /* Insert in list */ 11403448Sdh155122 mutex_enter(&netstack_shared_lock); 11413448Sdh155122 sz->sz_next = netstack_shared_zones; 11423448Sdh155122 netstack_shared_zones = sz; 11433448Sdh155122 11443448Sdh155122 /* 11453448Sdh155122 * Perform kstat_zone_add for each existing shared stack kstat. 11463448Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_add. 11473448Sdh155122 */ 11483448Sdh155122 for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) { 11493448Sdh155122 kstat_zone_add(sk->sk_kstat, zoneid); 11503448Sdh155122 } 11513448Sdh155122 mutex_exit(&netstack_shared_lock); 11523448Sdh155122 } 11533448Sdh155122 11543448Sdh155122 static void 11553448Sdh155122 netstack_shared_zone_remove(zoneid_t zoneid) 11563448Sdh155122 { 11573448Sdh155122 struct shared_zone_list **szp, *sz; 11583448Sdh155122 struct shared_kstat_list *sk; 11593448Sdh155122 11603448Sdh155122 /* Find in list */ 11613448Sdh155122 mutex_enter(&netstack_shared_lock); 11623448Sdh155122 sz = NULL; 11633448Sdh155122 for (szp = &netstack_shared_zones; *szp != NULL; 11643448Sdh155122 szp = &((*szp)->sz_next)) { 11653448Sdh155122 if ((*szp)->sz_zoneid == zoneid) { 11663448Sdh155122 sz = *szp; 11673448Sdh155122 break; 11683448Sdh155122 } 11693448Sdh155122 } 11703448Sdh155122 /* We must find it */ 11713448Sdh155122 ASSERT(sz != NULL); 11723448Sdh155122 *szp = sz->sz_next; 11733448Sdh155122 sz->sz_next = NULL; 11743448Sdh155122 11753448Sdh155122 /* 11763448Sdh155122 * Perform kstat_zone_remove for each existing shared stack kstat. 11773448Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_remove. 11783448Sdh155122 */ 11793448Sdh155122 for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) { 11803448Sdh155122 kstat_zone_remove(sk->sk_kstat, zoneid); 11813448Sdh155122 } 11823448Sdh155122 mutex_exit(&netstack_shared_lock); 11833448Sdh155122 11843448Sdh155122 kmem_free(sz, sizeof (*sz)); 11853448Sdh155122 } 11863448Sdh155122 11873448Sdh155122 static void 11883448Sdh155122 netstack_shared_kstat_add(kstat_t *ks) 11893448Sdh155122 { 11903448Sdh155122 struct shared_zone_list *sz; 11913448Sdh155122 struct shared_kstat_list *sk; 11923448Sdh155122 11933448Sdh155122 sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP); 11943448Sdh155122 sk->sk_kstat = ks; 11953448Sdh155122 11963448Sdh155122 /* Insert in list */ 11973448Sdh155122 mutex_enter(&netstack_shared_lock); 11983448Sdh155122 sk->sk_next = netstack_shared_kstats; 11993448Sdh155122 netstack_shared_kstats = sk; 12003448Sdh155122 12013448Sdh155122 /* 12023448Sdh155122 * Perform kstat_zone_add for each existing shared stack zone. 12033448Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_add. 12043448Sdh155122 */ 12053448Sdh155122 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) { 12063448Sdh155122 kstat_zone_add(ks, sz->sz_zoneid); 12073448Sdh155122 } 12083448Sdh155122 mutex_exit(&netstack_shared_lock); 12093448Sdh155122 } 12103448Sdh155122 12113448Sdh155122 static void 12123448Sdh155122 netstack_shared_kstat_remove(kstat_t *ks) 12133448Sdh155122 { 12143448Sdh155122 struct shared_zone_list *sz; 12153448Sdh155122 struct shared_kstat_list **skp, *sk; 12163448Sdh155122 12173448Sdh155122 /* Find in list */ 12183448Sdh155122 mutex_enter(&netstack_shared_lock); 12193448Sdh155122 sk = NULL; 12203448Sdh155122 for (skp = &netstack_shared_kstats; *skp != NULL; 12213448Sdh155122 skp = &((*skp)->sk_next)) { 12223448Sdh155122 if ((*skp)->sk_kstat == ks) { 12233448Sdh155122 sk = *skp; 12243448Sdh155122 break; 12253448Sdh155122 } 12263448Sdh155122 } 12273448Sdh155122 /* Must find it */ 12283448Sdh155122 ASSERT(sk != NULL); 12293448Sdh155122 *skp = sk->sk_next; 12303448Sdh155122 sk->sk_next = NULL; 12313448Sdh155122 12323448Sdh155122 /* 12333448Sdh155122 * Perform kstat_zone_remove for each existing shared stack kstat. 12343448Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_remove. 12353448Sdh155122 */ 12363448Sdh155122 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) { 12373448Sdh155122 kstat_zone_remove(ks, sz->sz_zoneid); 12383448Sdh155122 } 12393448Sdh155122 mutex_exit(&netstack_shared_lock); 12403448Sdh155122 kmem_free(sk, sizeof (*sk)); 12413448Sdh155122 } 12423448Sdh155122 12433448Sdh155122 /* 12443448Sdh155122 * If a zoneid is part of the shared zone, return true 12453448Sdh155122 */ 12463448Sdh155122 static boolean_t 12473448Sdh155122 netstack_find_shared_zoneid(zoneid_t zoneid) 12483448Sdh155122 { 12493448Sdh155122 struct shared_zone_list *sz; 12503448Sdh155122 12513448Sdh155122 mutex_enter(&netstack_shared_lock); 12523448Sdh155122 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) { 12533448Sdh155122 if (sz->sz_zoneid == zoneid) { 12543448Sdh155122 mutex_exit(&netstack_shared_lock); 12553448Sdh155122 return (B_TRUE); 12563448Sdh155122 } 12573448Sdh155122 } 12583448Sdh155122 mutex_exit(&netstack_shared_lock); 12593448Sdh155122 return (B_FALSE); 12603448Sdh155122 } 12613448Sdh155122 12623448Sdh155122 /* 12633448Sdh155122 * Hide the fact that zoneids and netstackids are allocated from 12643448Sdh155122 * the same space in the current implementation. 1265*5880Snordmark * We currently do not check that the stackid/zoneids are valid, since there 1266*5880Snordmark * is no need for that. But this should only be done for ids that are 1267*5880Snordmark * valid. 12683448Sdh155122 */ 12693448Sdh155122 zoneid_t 12703448Sdh155122 netstackid_to_zoneid(netstackid_t stackid) 12713448Sdh155122 { 12723448Sdh155122 return (stackid); 12733448Sdh155122 } 12743448Sdh155122 12753448Sdh155122 netstackid_t 12763448Sdh155122 zoneid_to_netstackid(zoneid_t zoneid) 12773448Sdh155122 { 12783448Sdh155122 if (netstack_find_shared_zoneid(zoneid)) 12793448Sdh155122 return (GLOBAL_ZONEID); 12803448Sdh155122 else 12813448Sdh155122 return (zoneid); 12823448Sdh155122 } 12833448Sdh155122 12843448Sdh155122 /* 12853448Sdh155122 * Simplistic support for walking all the handles. 12863448Sdh155122 * Example usage: 12873448Sdh155122 * netstack_handle_t nh; 12883448Sdh155122 * netstack_t *ns; 12893448Sdh155122 * 12903448Sdh155122 * netstack_next_init(&nh); 12913448Sdh155122 * while ((ns = netstack_next(&nh)) != NULL) { 12923448Sdh155122 * do something; 12933448Sdh155122 * netstack_rele(ns); 12943448Sdh155122 * } 12953448Sdh155122 * netstack_next_fini(&nh); 12963448Sdh155122 */ 12973448Sdh155122 void 12983448Sdh155122 netstack_next_init(netstack_handle_t *handle) 12993448Sdh155122 { 13003448Sdh155122 *handle = 0; 13013448Sdh155122 } 13023448Sdh155122 13033448Sdh155122 /* ARGSUSED */ 13043448Sdh155122 void 13053448Sdh155122 netstack_next_fini(netstack_handle_t *handle) 13063448Sdh155122 { 13073448Sdh155122 } 13083448Sdh155122 13093448Sdh155122 netstack_t * 13103448Sdh155122 netstack_next(netstack_handle_t *handle) 13113448Sdh155122 { 13123448Sdh155122 netstack_t *ns; 13133448Sdh155122 int i, end; 13143448Sdh155122 13153448Sdh155122 end = *handle; 13163448Sdh155122 /* Walk skipping *handle number of instances */ 13173448Sdh155122 13183448Sdh155122 /* Look if there is a matching stack instance */ 13193448Sdh155122 mutex_enter(&netstack_g_lock); 13203448Sdh155122 ns = netstack_head; 13213448Sdh155122 for (i = 0; i < end; i++) { 13223448Sdh155122 if (ns == NULL) 13233448Sdh155122 break; 13243448Sdh155122 ns = ns->netstack_next; 13253448Sdh155122 } 13263448Sdh155122 /* skip those with that aren't really here */ 13273448Sdh155122 while (ns != NULL) { 13283448Sdh155122 mutex_enter(&ns->netstack_lock); 13293448Sdh155122 if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) { 13303448Sdh155122 mutex_exit(&ns->netstack_lock); 13313448Sdh155122 break; 13323448Sdh155122 } 13333448Sdh155122 mutex_exit(&ns->netstack_lock); 13343448Sdh155122 end++; 13353448Sdh155122 ns = ns->netstack_next; 13363448Sdh155122 } 13373448Sdh155122 if (ns != NULL) { 13383448Sdh155122 *handle = end + 1; 13393448Sdh155122 netstack_hold(ns); 13403448Sdh155122 } 13413448Sdh155122 mutex_exit(&netstack_g_lock); 13423448Sdh155122 return (ns); 13433448Sdh155122 } 1344