1f4b3ec61Sdh155122 /* 2f4b3ec61Sdh155122 * CDDL HEADER START 3f4b3ec61Sdh155122 * 4f4b3ec61Sdh155122 * The contents of this file are subject to the terms of the 5f4b3ec61Sdh155122 * Common Development and Distribution License (the "License"). 6f4b3ec61Sdh155122 * You may not use this file except in compliance with the License. 7f4b3ec61Sdh155122 * 8f4b3ec61Sdh155122 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9f4b3ec61Sdh155122 * or http://www.opensolaris.org/os/licensing. 10f4b3ec61Sdh155122 * See the License for the specific language governing permissions 11f4b3ec61Sdh155122 * and limitations under the License. 12f4b3ec61Sdh155122 * 13f4b3ec61Sdh155122 * When distributing Covered Code, include this CDDL HEADER in each 14f4b3ec61Sdh155122 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15f4b3ec61Sdh155122 * If applicable, add the following below this CDDL HEADER, with the 16f4b3ec61Sdh155122 * fields enclosed by brackets "[]" replaced with your own identifying 17f4b3ec61Sdh155122 * information: Portions Copyright [yyyy] [name of copyright owner] 18f4b3ec61Sdh155122 * 19f4b3ec61Sdh155122 * CDDL HEADER END 20f4b3ec61Sdh155122 */ 21f4b3ec61Sdh155122 22f4b3ec61Sdh155122 /* 23f4b3ec61Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24f4b3ec61Sdh155122 * Use is subject to license terms. 25f4b3ec61Sdh155122 */ 26f4b3ec61Sdh155122 27f4b3ec61Sdh155122 #pragma ident "%Z%%M% %I% %E% SMI" 28f4b3ec61Sdh155122 29f4b3ec61Sdh155122 #include <sys/param.h> 30f4b3ec61Sdh155122 #include <sys/sysmacros.h> 31f4b3ec61Sdh155122 #include <sys/vm.h> 32f4b3ec61Sdh155122 #include <sys/proc.h> 33f4b3ec61Sdh155122 #include <sys/tuneable.h> 34f4b3ec61Sdh155122 #include <sys/systm.h> 35f4b3ec61Sdh155122 #include <sys/cmn_err.h> 36f4b3ec61Sdh155122 #include <sys/debug.h> 37f4b3ec61Sdh155122 #include <sys/sdt.h> 38f4b3ec61Sdh155122 #include <sys/mutex.h> 39f4b3ec61Sdh155122 #include <sys/bitmap.h> 40f4b3ec61Sdh155122 #include <sys/atomic.h> 41f4b3ec61Sdh155122 #include <sys/kobj.h> 42f4b3ec61Sdh155122 #include <sys/disp.h> 43f4b3ec61Sdh155122 #include <vm/seg_kmem.h> 44f4b3ec61Sdh155122 #include <sys/zone.h> 45f4b3ec61Sdh155122 #include <sys/netstack.h> 46f4b3ec61Sdh155122 47f4b3ec61Sdh155122 /* 48f4b3ec61Sdh155122 * What we use so that the zones framework can tell us about new zones, 49f4b3ec61Sdh155122 * which we use to create new stacks. 50f4b3ec61Sdh155122 */ 51f4b3ec61Sdh155122 static zone_key_t netstack_zone_key; 52f4b3ec61Sdh155122 53f4b3ec61Sdh155122 static int netstack_initialized = 0; 54f4b3ec61Sdh155122 55f4b3ec61Sdh155122 /* 56f4b3ec61Sdh155122 * Track the registered netstacks. 57f4b3ec61Sdh155122 * The global lock protects 58f4b3ec61Sdh155122 * - ns_reg 59f4b3ec61Sdh155122 * - the list starting at netstack_head and following the netstack_next 60f4b3ec61Sdh155122 * pointers. 61f4b3ec61Sdh155122 */ 62f4b3ec61Sdh155122 static kmutex_t netstack_g_lock; 63f4b3ec61Sdh155122 64f4b3ec61Sdh155122 /* 65f4b3ec61Sdh155122 * Registry of netstacks with their create/shutdown/destory functions. 66f4b3ec61Sdh155122 */ 67f4b3ec61Sdh155122 static struct netstack_registry ns_reg[NS_MAX]; 68f4b3ec61Sdh155122 69f4b3ec61Sdh155122 /* 70f4b3ec61Sdh155122 * Global list of existing stacks. We use this when a new zone with 71f4b3ec61Sdh155122 * an exclusive IP instance is created. 72f4b3ec61Sdh155122 * 73f4b3ec61Sdh155122 * Note that in some cases a netstack_t needs to stay around after the zone 74f4b3ec61Sdh155122 * has gone away. This is because there might be outstanding references 75f4b3ec61Sdh155122 * (from TCP TIME_WAIT connections, IPsec state, etc). The netstack_t data 76f4b3ec61Sdh155122 * structure and all the foo_stack_t's hanging off of it will be cleaned up 77f4b3ec61Sdh155122 * when the last reference to it is dropped. 78f4b3ec61Sdh155122 * However, the same zone might be rebooted. That is handled using the 79f4b3ec61Sdh155122 * assumption that the zones framework picks a new zoneid each time a zone 80f4b3ec61Sdh155122 * is (re)booted. We assert for that condition in netstack_zone_create(). 81f4b3ec61Sdh155122 * Thus the old netstack_t can take its time for things to time out. 82f4b3ec61Sdh155122 */ 83f4b3ec61Sdh155122 static netstack_t *netstack_head; 84f4b3ec61Sdh155122 85f4b3ec61Sdh155122 /* 86f4b3ec61Sdh155122 * To support kstat_create_netstack() using kstat_zone_add we need 87f4b3ec61Sdh155122 * to track both 88f4b3ec61Sdh155122 * - all zoneids that use the global/shared stack 89f4b3ec61Sdh155122 * - all kstats that have been added for the shared stack 90f4b3ec61Sdh155122 */ 91f4b3ec61Sdh155122 struct shared_zone_list { 92f4b3ec61Sdh155122 struct shared_zone_list *sz_next; 93f4b3ec61Sdh155122 zoneid_t sz_zoneid; 94f4b3ec61Sdh155122 }; 95f4b3ec61Sdh155122 96f4b3ec61Sdh155122 struct shared_kstat_list { 97f4b3ec61Sdh155122 struct shared_kstat_list *sk_next; 98f4b3ec61Sdh155122 kstat_t *sk_kstat; 99f4b3ec61Sdh155122 }; 100f4b3ec61Sdh155122 101f4b3ec61Sdh155122 static kmutex_t netstack_shared_lock; /* protects the following two */ 102f4b3ec61Sdh155122 static struct shared_zone_list *netstack_shared_zones; 103f4b3ec61Sdh155122 static struct shared_kstat_list *netstack_shared_kstats; 104f4b3ec61Sdh155122 105f4b3ec61Sdh155122 static void *netstack_zone_create(zoneid_t zoneid); 106f4b3ec61Sdh155122 static void netstack_zone_shutdown(zoneid_t zoneid, void *arg); 107f4b3ec61Sdh155122 static void netstack_zone_destroy(zoneid_t zoneid, void *arg); 108f4b3ec61Sdh155122 109f4b3ec61Sdh155122 static void netstack_do_create(void); 110f4b3ec61Sdh155122 static void netstack_do_shutdown(void); 111f4b3ec61Sdh155122 static void netstack_do_destroy(void); 112f4b3ec61Sdh155122 113f4b3ec61Sdh155122 static void netstack_shared_zone_add(zoneid_t zoneid); 114f4b3ec61Sdh155122 static void netstack_shared_zone_remove(zoneid_t zoneid); 115f4b3ec61Sdh155122 static void netstack_shared_kstat_add(kstat_t *ks); 116f4b3ec61Sdh155122 static void netstack_shared_kstat_remove(kstat_t *ks); 117f4b3ec61Sdh155122 118f4b3ec61Sdh155122 119f4b3ec61Sdh155122 void 120f4b3ec61Sdh155122 netstack_init(void) 121f4b3ec61Sdh155122 { 122f4b3ec61Sdh155122 mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL); 123f4b3ec61Sdh155122 mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL); 124f4b3ec61Sdh155122 125f4b3ec61Sdh155122 netstack_initialized = 1; 126f4b3ec61Sdh155122 127f4b3ec61Sdh155122 /* 128f4b3ec61Sdh155122 * We want to be informed each time a zone is created or 129f4b3ec61Sdh155122 * destroyed in the kernel, so we can maintain the 130f4b3ec61Sdh155122 * stack instance information. 131f4b3ec61Sdh155122 */ 132f4b3ec61Sdh155122 zone_key_create(&netstack_zone_key, netstack_zone_create, 133f4b3ec61Sdh155122 netstack_zone_shutdown, netstack_zone_destroy); 134f4b3ec61Sdh155122 } 135f4b3ec61Sdh155122 136f4b3ec61Sdh155122 /* 137f4b3ec61Sdh155122 * Register a new module with the framework. 138f4b3ec61Sdh155122 * This registers interest in changes to the set of netstacks. 139f4b3ec61Sdh155122 * The createfn and destroyfn are required, but the shutdownfn can be 140f4b3ec61Sdh155122 * NULL. 141f4b3ec61Sdh155122 * Note that due to the current zsd implementation, when the create 142f4b3ec61Sdh155122 * function is called the zone isn't fully present, thus functions 143f4b3ec61Sdh155122 * like zone_find_by_* will fail, hence the create function can not 144f4b3ec61Sdh155122 * use many zones kernel functions including zcmn_err(). 145f4b3ec61Sdh155122 */ 146f4b3ec61Sdh155122 void 147f4b3ec61Sdh155122 netstack_register(int moduleid, 148f4b3ec61Sdh155122 void *(*module_create)(netstackid_t, netstack_t *), 149f4b3ec61Sdh155122 void (*module_shutdown)(netstackid_t, void *), 150f4b3ec61Sdh155122 void (*module_destroy)(netstackid_t, void *)) 151f4b3ec61Sdh155122 { 152f4b3ec61Sdh155122 netstack_t *ns; 153f4b3ec61Sdh155122 154f4b3ec61Sdh155122 ASSERT(netstack_initialized); 155f4b3ec61Sdh155122 ASSERT(moduleid >= 0 && moduleid < NS_MAX); 156f4b3ec61Sdh155122 ASSERT(module_create != NULL); 157f4b3ec61Sdh155122 158f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 159f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_create == NULL); 160f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_flags == 0); 161f4b3ec61Sdh155122 ns_reg[moduleid].nr_create = module_create; 162f4b3ec61Sdh155122 ns_reg[moduleid].nr_shutdown = module_shutdown; 163f4b3ec61Sdh155122 ns_reg[moduleid].nr_destroy = module_destroy; 164f4b3ec61Sdh155122 ns_reg[moduleid].nr_flags = NRF_REGISTERED; 165f4b3ec61Sdh155122 166f4b3ec61Sdh155122 /* 167f4b3ec61Sdh155122 * Determine the set of stacks that exist before we drop the lock. 168f4b3ec61Sdh155122 * Set CREATE_NEEDED for each of those. 169f4b3ec61Sdh155122 * netstacks which have been deleted will have NSS_CREATE_COMPLETED 170f4b3ec61Sdh155122 * set, but check NSF_CLOSING to be sure. 171f4b3ec61Sdh155122 */ 172f4b3ec61Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 173f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 174f4b3ec61Sdh155122 if (!(ns->netstack_flags & NSF_CLOSING) && 175f4b3ec61Sdh155122 (ns->netstack_m_state[moduleid] & NSS_CREATE_ALL) == 0) { 176f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_CREATE_NEEDED; 177f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__create__needed, 178f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 179f4b3ec61Sdh155122 } 180f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 181f4b3ec61Sdh155122 } 182f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 183f4b3ec61Sdh155122 184f4b3ec61Sdh155122 /* 185f4b3ec61Sdh155122 * Call the create function for each stack that has CREATE_NEEDED. 186f4b3ec61Sdh155122 * Set CREATE_INPROGRESS, drop lock, and after done, 187f4b3ec61Sdh155122 * set CREATE_COMPLETE 188f4b3ec61Sdh155122 */ 189f4b3ec61Sdh155122 netstack_do_create(); 190f4b3ec61Sdh155122 } 191f4b3ec61Sdh155122 192f4b3ec61Sdh155122 void 193f4b3ec61Sdh155122 netstack_unregister(int moduleid) 194f4b3ec61Sdh155122 { 195f4b3ec61Sdh155122 netstack_t *ns; 196f4b3ec61Sdh155122 197f4b3ec61Sdh155122 ASSERT(moduleid >= 0 && moduleid < NS_MAX); 198f4b3ec61Sdh155122 199f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_create != NULL); 200f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED); 201f4b3ec61Sdh155122 202f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 203f4b3ec61Sdh155122 /* 204f4b3ec61Sdh155122 * Determine the set of stacks that exist before we drop the lock. 205f4b3ec61Sdh155122 * Set SHUTDOWN_NEEDED and DESTROY_NEEDED for each of those. 206f4b3ec61Sdh155122 */ 207f4b3ec61Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 208f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 209f4b3ec61Sdh155122 if (ns_reg[moduleid].nr_shutdown != NULL && 210f4b3ec61Sdh155122 (ns->netstack_m_state[moduleid] & NSS_CREATE_COMPLETED) && 211f4b3ec61Sdh155122 (ns->netstack_m_state[moduleid] & NSS_SHUTDOWN_ALL) == 0) { 212f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_SHUTDOWN_NEEDED; 213f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__shutdown__needed, 214f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 215f4b3ec61Sdh155122 } 216f4b3ec61Sdh155122 if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) && 217f4b3ec61Sdh155122 ns_reg[moduleid].nr_destroy != NULL && 218f4b3ec61Sdh155122 (ns->netstack_m_state[moduleid] & NSS_CREATE_COMPLETED) && 219f4b3ec61Sdh155122 (ns->netstack_m_state[moduleid] & NSS_DESTROY_ALL) == 0) { 220f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_DESTROY_NEEDED; 221f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__destroy__needed, 222f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 223f4b3ec61Sdh155122 } 224f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 225f4b3ec61Sdh155122 } 226f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 227f4b3ec61Sdh155122 228f4b3ec61Sdh155122 netstack_do_shutdown(); 229f4b3ec61Sdh155122 netstack_do_destroy(); 230f4b3ec61Sdh155122 231f4b3ec61Sdh155122 /* 232f4b3ec61Sdh155122 * Clear the netstack_m_state so that we can handle this module 233f4b3ec61Sdh155122 * being loaded again. 234f4b3ec61Sdh155122 */ 235f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 236f4b3ec61Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 237f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 238f4b3ec61Sdh155122 if (ns->netstack_m_state[moduleid] & NSS_DESTROY_COMPLETED) { 239f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] = 0; 240f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__destroy__done, 241f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 242f4b3ec61Sdh155122 } 243f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 244f4b3ec61Sdh155122 } 245f4b3ec61Sdh155122 246f4b3ec61Sdh155122 ns_reg[moduleid].nr_create = NULL; 247f4b3ec61Sdh155122 ns_reg[moduleid].nr_shutdown = NULL; 248f4b3ec61Sdh155122 ns_reg[moduleid].nr_destroy = NULL; 249f4b3ec61Sdh155122 ns_reg[moduleid].nr_flags = 0; 250f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 251f4b3ec61Sdh155122 } 252f4b3ec61Sdh155122 253f4b3ec61Sdh155122 /* 254f4b3ec61Sdh155122 * Lookup and/or allocate a netstack for this zone. 255f4b3ec61Sdh155122 */ 256f4b3ec61Sdh155122 static void * 257f4b3ec61Sdh155122 netstack_zone_create(zoneid_t zoneid) 258f4b3ec61Sdh155122 { 259f4b3ec61Sdh155122 netstackid_t stackid; 260f4b3ec61Sdh155122 netstack_t *ns; 261f4b3ec61Sdh155122 netstack_t **nsp; 262f4b3ec61Sdh155122 zone_t *zone; 263f4b3ec61Sdh155122 int i; 264f4b3ec61Sdh155122 265f4b3ec61Sdh155122 ASSERT(netstack_initialized); 266f4b3ec61Sdh155122 267f4b3ec61Sdh155122 zone = zone_find_by_id_nolock(zoneid); 268f4b3ec61Sdh155122 ASSERT(zone != NULL); 269f4b3ec61Sdh155122 270f4b3ec61Sdh155122 if (zone->zone_flags & ZF_NET_EXCL) { 271f4b3ec61Sdh155122 stackid = zoneid; 272f4b3ec61Sdh155122 } else { 273f4b3ec61Sdh155122 /* Look for the stack instance for the global */ 274f4b3ec61Sdh155122 stackid = GLOBAL_NETSTACKID; 275f4b3ec61Sdh155122 } 276f4b3ec61Sdh155122 277f4b3ec61Sdh155122 /* Allocate even if it isn't needed; simplifies locking */ 278f4b3ec61Sdh155122 ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP); 279f4b3ec61Sdh155122 280f4b3ec61Sdh155122 /* Look if there is a matching stack instance */ 281f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 282f4b3ec61Sdh155122 for (nsp = &netstack_head; *nsp != NULL; 283f4b3ec61Sdh155122 nsp = &((*nsp)->netstack_next)) { 284f4b3ec61Sdh155122 if ((*nsp)->netstack_stackid == stackid) { 285f4b3ec61Sdh155122 /* 286f4b3ec61Sdh155122 * Should never find a pre-existing exclusive stack 287f4b3ec61Sdh155122 */ 288f4b3ec61Sdh155122 ASSERT(stackid == GLOBAL_NETSTACKID); 289f4b3ec61Sdh155122 kmem_free(ns, sizeof (netstack_t)); 290f4b3ec61Sdh155122 ns = *nsp; 291f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 292f4b3ec61Sdh155122 ns->netstack_numzones++; 293f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 294f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 295f4b3ec61Sdh155122 DTRACE_PROBE1(netstack__inc__numzones, 296f4b3ec61Sdh155122 netstack_t *, ns); 297f4b3ec61Sdh155122 /* Record that we have a new shared stack zone */ 298f4b3ec61Sdh155122 netstack_shared_zone_add(zoneid); 299f4b3ec61Sdh155122 zone->zone_netstack = ns; 300f4b3ec61Sdh155122 return (ns); 301f4b3ec61Sdh155122 } 302f4b3ec61Sdh155122 } 303f4b3ec61Sdh155122 /* Not found */ 304f4b3ec61Sdh155122 mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL); 305f4b3ec61Sdh155122 ns->netstack_stackid = zoneid; 306f4b3ec61Sdh155122 ns->netstack_numzones = 1; 307f4b3ec61Sdh155122 ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */ 308f4b3ec61Sdh155122 ns->netstack_flags = NSF_UNINIT; 309f4b3ec61Sdh155122 *nsp = ns; 310f4b3ec61Sdh155122 zone->zone_netstack = ns; 311f4b3ec61Sdh155122 312f4b3ec61Sdh155122 /* 313f4b3ec61Sdh155122 * Determine the set of module create functions that need to be 314f4b3ec61Sdh155122 * called before we drop the lock. 315f4b3ec61Sdh155122 */ 316f4b3ec61Sdh155122 for (i = 0; i < NS_MAX; i++) { 317f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 318f4b3ec61Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 319f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_CREATE_ALL) == 0) { 320f4b3ec61Sdh155122 ns->netstack_m_state[i] |= NSS_CREATE_NEEDED; 321f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__create__needed, 322f4b3ec61Sdh155122 netstack_t *, ns, int, i); 323f4b3ec61Sdh155122 } 324f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 325f4b3ec61Sdh155122 } 326f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 327f4b3ec61Sdh155122 328f4b3ec61Sdh155122 netstack_do_create(); 329f4b3ec61Sdh155122 330f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 331f4b3ec61Sdh155122 ns->netstack_flags &= ~NSF_UNINIT; 332f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 333f4b3ec61Sdh155122 334f4b3ec61Sdh155122 return (ns); 335f4b3ec61Sdh155122 } 336f4b3ec61Sdh155122 337f4b3ec61Sdh155122 /* ARGSUSED */ 338f4b3ec61Sdh155122 static void 339f4b3ec61Sdh155122 netstack_zone_shutdown(zoneid_t zoneid, void *arg) 340f4b3ec61Sdh155122 { 341f4b3ec61Sdh155122 netstack_t *ns = (netstack_t *)arg; 342f4b3ec61Sdh155122 int i; 343f4b3ec61Sdh155122 344f4b3ec61Sdh155122 ASSERT(arg != NULL); 345f4b3ec61Sdh155122 346f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 347f4b3ec61Sdh155122 ASSERT(ns->netstack_numzones > 0); 348f4b3ec61Sdh155122 if (ns->netstack_numzones != 1) { 349f4b3ec61Sdh155122 /* Stack instance being used by other zone */ 350f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 351f4b3ec61Sdh155122 ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID); 352f4b3ec61Sdh155122 return; 353f4b3ec61Sdh155122 } 354f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 355f4b3ec61Sdh155122 356f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 357f4b3ec61Sdh155122 /* 358f4b3ec61Sdh155122 * Determine the set of stacks that exist before we drop the lock. 359f4b3ec61Sdh155122 * Set SHUTDOWN_NEEDED for each of those. 360f4b3ec61Sdh155122 */ 361f4b3ec61Sdh155122 for (i = 0; i < NS_MAX; i++) { 362f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 363f4b3ec61Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 364f4b3ec61Sdh155122 ns_reg[i].nr_shutdown != NULL && 365f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_CREATE_COMPLETED) && 366f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_SHUTDOWN_ALL) == 0) { 367f4b3ec61Sdh155122 ns->netstack_m_state[i] |= NSS_SHUTDOWN_NEEDED; 368f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__shutdown__needed, 369f4b3ec61Sdh155122 netstack_t *, ns, int, i); 370f4b3ec61Sdh155122 } 371f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 372f4b3ec61Sdh155122 } 373f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 374f4b3ec61Sdh155122 375f4b3ec61Sdh155122 /* Call the shutdown function for all registered modules */ 376f4b3ec61Sdh155122 netstack_do_shutdown(); 377f4b3ec61Sdh155122 } 378f4b3ec61Sdh155122 379f4b3ec61Sdh155122 /* 380f4b3ec61Sdh155122 * Common routine to release a zone. 381f4b3ec61Sdh155122 * If this was the last zone using the stack instance then prepare to 382f4b3ec61Sdh155122 * have the refcnt dropping to zero free the zone. 383f4b3ec61Sdh155122 */ 384f4b3ec61Sdh155122 /* ARGSUSED */ 385f4b3ec61Sdh155122 static void 386f4b3ec61Sdh155122 netstack_zone_destroy(zoneid_t zoneid, void *arg) 387f4b3ec61Sdh155122 { 388f4b3ec61Sdh155122 netstack_t *ns = (netstack_t *)arg; 389f4b3ec61Sdh155122 390f4b3ec61Sdh155122 ASSERT(arg != NULL); 391f4b3ec61Sdh155122 392f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 393f4b3ec61Sdh155122 ASSERT(ns->netstack_numzones > 0); 394f4b3ec61Sdh155122 ns->netstack_numzones--; 395f4b3ec61Sdh155122 if (ns->netstack_numzones != 0) { 396f4b3ec61Sdh155122 /* Stack instance being used by other zone */ 397f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 398f4b3ec61Sdh155122 ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID); 399f4b3ec61Sdh155122 /* Record that we a shared stack zone has gone away */ 400f4b3ec61Sdh155122 netstack_shared_zone_remove(zoneid); 401f4b3ec61Sdh155122 return; 402f4b3ec61Sdh155122 } 403f4b3ec61Sdh155122 /* 404f4b3ec61Sdh155122 * Set CLOSING so that netstack_find_by will not find it 405f4b3ec61Sdh155122 * and decrement the reference count. 406f4b3ec61Sdh155122 */ 407f4b3ec61Sdh155122 ns->netstack_flags |= NSF_CLOSING; 408f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 409f4b3ec61Sdh155122 DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns); 410f4b3ec61Sdh155122 /* No other thread can call zone_destroy for this stack */ 411f4b3ec61Sdh155122 412f4b3ec61Sdh155122 /* 413f4b3ec61Sdh155122 * Decrease refcnt to account for the one in netstack_zone_init() 414f4b3ec61Sdh155122 */ 415f4b3ec61Sdh155122 netstack_rele(ns); 416f4b3ec61Sdh155122 } 417f4b3ec61Sdh155122 418f4b3ec61Sdh155122 /* 419f4b3ec61Sdh155122 * Called when the reference count drops to zero. 420f4b3ec61Sdh155122 * Call the destroy functions for each registered module. 421f4b3ec61Sdh155122 */ 422f4b3ec61Sdh155122 static void 423f4b3ec61Sdh155122 netstack_stack_inactive(netstack_t *ns) 424f4b3ec61Sdh155122 { 425f4b3ec61Sdh155122 int i; 426f4b3ec61Sdh155122 427f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 428f4b3ec61Sdh155122 /* 429f4b3ec61Sdh155122 * If the shutdown callback wasn't called earlier (e.g., if this is 430f4b3ec61Sdh155122 * a netstack shared between multiple zones), then we call it now. 431f4b3ec61Sdh155122 */ 432f4b3ec61Sdh155122 for (i = 0; i < NS_MAX; i++) { 433f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 434f4b3ec61Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 435f4b3ec61Sdh155122 ns_reg[i].nr_shutdown != NULL && 436f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_CREATE_COMPLETED) && 437f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_SHUTDOWN_ALL) == 0) { 438f4b3ec61Sdh155122 ns->netstack_m_state[i] |= NSS_SHUTDOWN_NEEDED; 439f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__shutdown__needed, 440f4b3ec61Sdh155122 netstack_t *, ns, int, i); 441f4b3ec61Sdh155122 } 442f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 443f4b3ec61Sdh155122 } 444f4b3ec61Sdh155122 /* 445f4b3ec61Sdh155122 * Determine the set of stacks that exist before we drop the lock. 446f4b3ec61Sdh155122 * Set DESTROY_NEEDED for each of those. 447f4b3ec61Sdh155122 */ 448f4b3ec61Sdh155122 for (i = 0; i < NS_MAX; i++) { 449f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 450f4b3ec61Sdh155122 if ((ns_reg[i].nr_flags & NRF_REGISTERED) && 451f4b3ec61Sdh155122 ns_reg[i].nr_destroy != NULL && 452f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_CREATE_COMPLETED) && 453f4b3ec61Sdh155122 (ns->netstack_m_state[i] & NSS_DESTROY_ALL) == 0) { 454f4b3ec61Sdh155122 ns->netstack_m_state[i] |= NSS_DESTROY_NEEDED; 455f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__destroy__needed, 456f4b3ec61Sdh155122 netstack_t *, ns, int, i); 457f4b3ec61Sdh155122 } 458f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 459f4b3ec61Sdh155122 } 460f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 461f4b3ec61Sdh155122 462f4b3ec61Sdh155122 netstack_do_shutdown(); 463f4b3ec61Sdh155122 netstack_do_destroy(); 464f4b3ec61Sdh155122 } 465f4b3ec61Sdh155122 466f4b3ec61Sdh155122 /* 467f4b3ec61Sdh155122 * Call the create function for the ns and moduleid if CREATE_NEEDED 468f4b3ec61Sdh155122 * is set. 469f4b3ec61Sdh155122 * When it calls it, it drops the netstack_lock held by the caller, 470f4b3ec61Sdh155122 * and returns true to tell the caller it needs to re-evalute the 471f4b3ec61Sdh155122 * state.. 472f4b3ec61Sdh155122 */ 473f4b3ec61Sdh155122 static boolean_t 474f4b3ec61Sdh155122 netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid) 475f4b3ec61Sdh155122 { 476f4b3ec61Sdh155122 void *result; 477f4b3ec61Sdh155122 netstackid_t stackid; 478f4b3ec61Sdh155122 479f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(lockp)); 480f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 481f4b3ec61Sdh155122 if (ns->netstack_m_state[moduleid] & NSS_CREATE_NEEDED) { 482f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] &= ~NSS_CREATE_NEEDED; 483f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_CREATE_INPROGRESS; 484f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__create__inprogress, 485f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 486f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 487f4b3ec61Sdh155122 mutex_exit(lockp); 488f4b3ec61Sdh155122 489f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_create != NULL); 490f4b3ec61Sdh155122 stackid = ns->netstack_stackid; 491f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__create__start, 492f4b3ec61Sdh155122 netstackid_t, stackid, 493f4b3ec61Sdh155122 netstack_t *, ns); 494f4b3ec61Sdh155122 result = (ns_reg[moduleid].nr_create)(stackid, ns); 495f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__create__end, 496f4b3ec61Sdh155122 void *, result, netstack_t *, ns); 497f4b3ec61Sdh155122 498f4b3ec61Sdh155122 ASSERT(result != NULL); 499f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 500f4b3ec61Sdh155122 ns->netstack_modules[moduleid] = result; 501f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] &= ~NSS_CREATE_INPROGRESS; 502f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_CREATE_COMPLETED; 503f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__create__completed, 504f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 505f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 506f4b3ec61Sdh155122 return (B_TRUE); 507f4b3ec61Sdh155122 } else { 508f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 509f4b3ec61Sdh155122 return (B_FALSE); 510f4b3ec61Sdh155122 } 511f4b3ec61Sdh155122 } 512f4b3ec61Sdh155122 513f4b3ec61Sdh155122 /* 514f4b3ec61Sdh155122 * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED 515f4b3ec61Sdh155122 * is set. 516f4b3ec61Sdh155122 * When it calls it, it drops the netstack_lock held by the caller, 517f4b3ec61Sdh155122 * and returns true to tell the caller it needs to re-evalute the 518f4b3ec61Sdh155122 * state.. 519f4b3ec61Sdh155122 */ 520f4b3ec61Sdh155122 static boolean_t 521f4b3ec61Sdh155122 netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid) 522f4b3ec61Sdh155122 { 523f4b3ec61Sdh155122 netstackid_t stackid; 524f4b3ec61Sdh155122 void * netstack_module; 525f4b3ec61Sdh155122 526f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(lockp)); 527f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 528f4b3ec61Sdh155122 if (ns->netstack_m_state[moduleid] & NSS_SHUTDOWN_NEEDED) { 529f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] &= ~NSS_SHUTDOWN_NEEDED; 530f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_SHUTDOWN_INPROGRESS; 531f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__shutdown__inprogress, 532f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 533f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 534f4b3ec61Sdh155122 mutex_exit(lockp); 535f4b3ec61Sdh155122 536f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_shutdown != NULL); 537f4b3ec61Sdh155122 stackid = ns->netstack_stackid; 538f4b3ec61Sdh155122 netstack_module = ns->netstack_modules[moduleid]; 539f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__shutdown__start, 540f4b3ec61Sdh155122 netstackid_t, stackid, 541f4b3ec61Sdh155122 void *, netstack_module); 542f4b3ec61Sdh155122 (ns_reg[moduleid].nr_shutdown)(stackid, netstack_module); 543f4b3ec61Sdh155122 DTRACE_PROBE1(netstack__shutdown__end, 544f4b3ec61Sdh155122 netstack_t *, ns); 545f4b3ec61Sdh155122 546f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 547f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] &= ~NSS_SHUTDOWN_INPROGRESS; 548f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_SHUTDOWN_COMPLETED; 549f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__shutdown__completed, 550f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 551f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 552f4b3ec61Sdh155122 return (B_TRUE); 553f4b3ec61Sdh155122 } else { 554f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 555f4b3ec61Sdh155122 return (B_FALSE); 556f4b3ec61Sdh155122 } 557f4b3ec61Sdh155122 } 558f4b3ec61Sdh155122 559f4b3ec61Sdh155122 /* 560f4b3ec61Sdh155122 * Call the destroy function for the ns and moduleid if DESTROY_NEEDED 561f4b3ec61Sdh155122 * is set. 562f4b3ec61Sdh155122 * When it calls it, it drops the netstack_lock held by the caller, 563f4b3ec61Sdh155122 * and returns true to tell the caller it needs to re-evalute the 564f4b3ec61Sdh155122 * state.. 565f4b3ec61Sdh155122 */ 566f4b3ec61Sdh155122 static boolean_t 567f4b3ec61Sdh155122 netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid) 568f4b3ec61Sdh155122 { 569f4b3ec61Sdh155122 netstackid_t stackid; 570f4b3ec61Sdh155122 void * netstack_module; 571f4b3ec61Sdh155122 572f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(lockp)); 573f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 574f4b3ec61Sdh155122 if (ns->netstack_m_state[moduleid] & NSS_DESTROY_NEEDED) { 575f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] &= ~NSS_DESTROY_NEEDED; 576f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_DESTROY_INPROGRESS; 577f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__destroy__inprogress, 578f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 579f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 580f4b3ec61Sdh155122 mutex_exit(lockp); 581f4b3ec61Sdh155122 582f4b3ec61Sdh155122 /* XXX race against unregister? */ 583f4b3ec61Sdh155122 ASSERT(ns_reg[moduleid].nr_destroy != NULL); 584f4b3ec61Sdh155122 stackid = ns->netstack_stackid; 585f4b3ec61Sdh155122 netstack_module = ns->netstack_modules[moduleid]; 586f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__destroy__start, 587f4b3ec61Sdh155122 netstackid_t, stackid, 588f4b3ec61Sdh155122 void *, netstack_module); 589f4b3ec61Sdh155122 (ns_reg[moduleid].nr_destroy)(stackid, netstack_module); 590f4b3ec61Sdh155122 DTRACE_PROBE1(netstack__destroy__end, 591f4b3ec61Sdh155122 netstack_t *, ns); 592f4b3ec61Sdh155122 593f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 594f4b3ec61Sdh155122 ns->netstack_modules[moduleid] = NULL; 595f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] &= ~NSS_DESTROY_INPROGRESS; 596f4b3ec61Sdh155122 ns->netstack_m_state[moduleid] |= NSS_DESTROY_COMPLETED; 597f4b3ec61Sdh155122 DTRACE_PROBE2(netstack__destroy__completed, 598f4b3ec61Sdh155122 netstack_t *, ns, int, moduleid); 599f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 600f4b3ec61Sdh155122 return (B_TRUE); 601f4b3ec61Sdh155122 } else { 602f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 603f4b3ec61Sdh155122 return (B_FALSE); 604f4b3ec61Sdh155122 } 605f4b3ec61Sdh155122 } 606f4b3ec61Sdh155122 607f4b3ec61Sdh155122 static void 608f4b3ec61Sdh155122 apply_loop(netstack_t **headp, kmutex_t *lockp, 609f4b3ec61Sdh155122 boolean_t (*applyfn)(kmutex_t *, netstack_t *, int moduleid)) 610f4b3ec61Sdh155122 { 611f4b3ec61Sdh155122 netstack_t *ns; 612f4b3ec61Sdh155122 int i; 613f4b3ec61Sdh155122 boolean_t lock_dropped, result; 614f4b3ec61Sdh155122 615f4b3ec61Sdh155122 lock_dropped = B_FALSE; 616f4b3ec61Sdh155122 ns = *headp; 617f4b3ec61Sdh155122 while (ns != NULL) { 618f4b3ec61Sdh155122 for (i = 0; i < NS_MAX; i++) { 619f4b3ec61Sdh155122 result = (applyfn)(lockp, ns, i); 620f4b3ec61Sdh155122 if (result) { 621f4b3ec61Sdh155122 #ifdef NS_DEBUG 622f4b3ec61Sdh155122 (void) printf("netstack_do_apply: " 623f4b3ec61Sdh155122 "LD for %p/%d, %d\n", 624f4b3ec61Sdh155122 (void *)ns, ns->netstack_stackid, i); 625f4b3ec61Sdh155122 #endif 626f4b3ec61Sdh155122 lock_dropped = B_TRUE; 627f4b3ec61Sdh155122 mutex_enter(lockp); 628f4b3ec61Sdh155122 } 629f4b3ec61Sdh155122 } 630f4b3ec61Sdh155122 /* 631f4b3ec61Sdh155122 * If at least one applyfn call caused lockp to be dropped, 632f4b3ec61Sdh155122 * then we don't follow netstack_next after reacquiring the 633f4b3ec61Sdh155122 * lock, even if it is possible to do so without any hazards. 634f4b3ec61Sdh155122 * This is because we want the design to allow for the list of 635f4b3ec61Sdh155122 * netstacks threaded by netstack_next to change in any 636f4b3ec61Sdh155122 * arbitrary way during the time the 'lockp' was dropped. 637f4b3ec61Sdh155122 * 638f4b3ec61Sdh155122 * It is safe to restart the loop at *headp since 639f4b3ec61Sdh155122 * the applyfn changes netstack_m_state as it processes 640f4b3ec61Sdh155122 * things, so a subsequent pass through will have no 641f4b3ec61Sdh155122 * effect in applyfn, hence the loop will terminate 642f4b3ec61Sdh155122 * in at worst O(N^2). 643f4b3ec61Sdh155122 */ 644f4b3ec61Sdh155122 if (lock_dropped) { 645f4b3ec61Sdh155122 #ifdef NS_DEBUG 646f4b3ec61Sdh155122 (void) printf("netstack_do_apply: " 647f4b3ec61Sdh155122 "Lock Dropped for %p/%d, %d\n", 648f4b3ec61Sdh155122 (void *)ns, ns->netstack_stackid, i); 649f4b3ec61Sdh155122 #endif 650f4b3ec61Sdh155122 lock_dropped = B_FALSE; 651f4b3ec61Sdh155122 ns = *headp; 652f4b3ec61Sdh155122 } else { 653f4b3ec61Sdh155122 ns = ns->netstack_next; 654f4b3ec61Sdh155122 } 655f4b3ec61Sdh155122 } 656f4b3ec61Sdh155122 } 657f4b3ec61Sdh155122 658f4b3ec61Sdh155122 /* Like above, but in the reverse order of moduleids */ 659f4b3ec61Sdh155122 static void 660f4b3ec61Sdh155122 apply_loop_reverse(netstack_t **headp, kmutex_t *lockp, 661f4b3ec61Sdh155122 boolean_t (*applyfn)(kmutex_t *, netstack_t *, int moduleid)) 662f4b3ec61Sdh155122 { 663f4b3ec61Sdh155122 netstack_t *ns; 664f4b3ec61Sdh155122 int i; 665f4b3ec61Sdh155122 boolean_t lock_dropped, result; 666f4b3ec61Sdh155122 667f4b3ec61Sdh155122 lock_dropped = B_FALSE; 668f4b3ec61Sdh155122 ns = *headp; 669f4b3ec61Sdh155122 while (ns != NULL) { 670f4b3ec61Sdh155122 for (i = NS_MAX-1; i >= 0; i--) { 671f4b3ec61Sdh155122 result = (applyfn)(lockp, ns, i); 672f4b3ec61Sdh155122 if (result) { 673f4b3ec61Sdh155122 #ifdef NS_DEBUG 674f4b3ec61Sdh155122 (void) printf("netstack_do_apply: " 675f4b3ec61Sdh155122 "LD for %p/%d, %d\n", 676f4b3ec61Sdh155122 (void *)ns, ns->netstack_stackid, i); 677f4b3ec61Sdh155122 #endif 678f4b3ec61Sdh155122 lock_dropped = B_TRUE; 679f4b3ec61Sdh155122 mutex_enter(lockp); 680f4b3ec61Sdh155122 } 681f4b3ec61Sdh155122 } 682f4b3ec61Sdh155122 /* 683f4b3ec61Sdh155122 * If at least one applyfn call caused lockp to be dropped, 684f4b3ec61Sdh155122 * then we don't follow netstack_next after reacquiring the 685f4b3ec61Sdh155122 * lock, even if it is possible to do so without any hazards. 686f4b3ec61Sdh155122 * This is because we want the design to allow for the list of 687f4b3ec61Sdh155122 * netstacks threaded by netstack_next to change in any 688f4b3ec61Sdh155122 * arbitrary way during the time the 'lockp' was dropped. 689f4b3ec61Sdh155122 * 690f4b3ec61Sdh155122 * It is safe to restart the loop at *headp since 691f4b3ec61Sdh155122 * the applyfn changes netstack_m_state as it processes 692f4b3ec61Sdh155122 * things, so a subsequent pass through will have no 693f4b3ec61Sdh155122 * effect in applyfn, hence the loop will terminate 694f4b3ec61Sdh155122 * in at worst O(N^2). 695f4b3ec61Sdh155122 */ 696f4b3ec61Sdh155122 if (lock_dropped) { 697f4b3ec61Sdh155122 #ifdef NS_DEBUG 698f4b3ec61Sdh155122 (void) printf("netstack_do_apply: " 699f4b3ec61Sdh155122 "Lock Dropped for %p/%d, %d\n", 700f4b3ec61Sdh155122 (void *)ns, ns->netstack_stackid, i); 701f4b3ec61Sdh155122 #endif 702f4b3ec61Sdh155122 lock_dropped = B_FALSE; 703f4b3ec61Sdh155122 ns = *headp; 704f4b3ec61Sdh155122 } else { 705f4b3ec61Sdh155122 ns = ns->netstack_next; 706f4b3ec61Sdh155122 } 707f4b3ec61Sdh155122 } 708f4b3ec61Sdh155122 } 709f4b3ec61Sdh155122 710f4b3ec61Sdh155122 /* 711f4b3ec61Sdh155122 * Apply a function to all module/netstack combinations. 712f4b3ec61Sdh155122 * The applyfn returns true if it had dropped the locks. 713f4b3ec61Sdh155122 */ 714f4b3ec61Sdh155122 static void 715f4b3ec61Sdh155122 netstack_do_apply(int reverse, 716f4b3ec61Sdh155122 boolean_t (*applyfn)(kmutex_t *, netstack_t *, int moduleid)) 717f4b3ec61Sdh155122 { 718f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 719f4b3ec61Sdh155122 if (reverse) 720f4b3ec61Sdh155122 apply_loop_reverse(&netstack_head, &netstack_g_lock, applyfn); 721f4b3ec61Sdh155122 else 722f4b3ec61Sdh155122 apply_loop(&netstack_head, &netstack_g_lock, applyfn); 723f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 724f4b3ec61Sdh155122 } 725f4b3ec61Sdh155122 726f4b3ec61Sdh155122 /* 727f4b3ec61Sdh155122 * Run the create function for all modules x stack combinations 728f4b3ec61Sdh155122 * that have NSS_CREATE_NEEDED set. 729f4b3ec61Sdh155122 * 730f4b3ec61Sdh155122 * Call the create function for each stack that has CREATE_NEEDED. 731f4b3ec61Sdh155122 * Set CREATE_INPROGRESS, drop lock, and after done, 732f4b3ec61Sdh155122 * set CREATE_COMPLETE 733f4b3ec61Sdh155122 */ 734f4b3ec61Sdh155122 static void 735f4b3ec61Sdh155122 netstack_do_create(void) 736f4b3ec61Sdh155122 { 737f4b3ec61Sdh155122 netstack_do_apply(B_FALSE, netstack_apply_create); 738f4b3ec61Sdh155122 } 739f4b3ec61Sdh155122 740f4b3ec61Sdh155122 /* 741f4b3ec61Sdh155122 * Run the shutdown function for all modules x stack combinations 742f4b3ec61Sdh155122 * that have NSS_SHUTDOWN_NEEDED set. 743f4b3ec61Sdh155122 * 744f4b3ec61Sdh155122 * Call the shutdown function for each stack that has SHUTDOWN_NEEDED. 745f4b3ec61Sdh155122 * Set SHUTDOWN_INPROGRESS, drop lock, and after done, 746f4b3ec61Sdh155122 * set SHUTDOWN_COMPLETE 747f4b3ec61Sdh155122 */ 748f4b3ec61Sdh155122 static void 749f4b3ec61Sdh155122 netstack_do_shutdown(void) 750f4b3ec61Sdh155122 { 751f4b3ec61Sdh155122 netstack_do_apply(B_FALSE, netstack_apply_shutdown); 752f4b3ec61Sdh155122 } 753f4b3ec61Sdh155122 754f4b3ec61Sdh155122 /* 755f4b3ec61Sdh155122 * Run the destroy function for all modules x stack combinations 756f4b3ec61Sdh155122 * that have NSS_DESTROY_NEEDED set. 757f4b3ec61Sdh155122 * 758f4b3ec61Sdh155122 * Call the destroy function for each stack that has DESTROY_NEEDED. 759f4b3ec61Sdh155122 * Set DESTROY_INPROGRESS, drop lock, and after done, 760f4b3ec61Sdh155122 * set DESTROY_COMPLETE 761f4b3ec61Sdh155122 * 762f4b3ec61Sdh155122 * Since a netstack_t is never reused (when a zone is rebooted it gets 763f4b3ec61Sdh155122 * a new zoneid == netstackid i.e. a new netstack_t is allocated) we leave 764f4b3ec61Sdh155122 * netstack_m_state the way it is i.e. with NSS_DESTROY_COMPLETED set. 765f4b3ec61Sdh155122 */ 766f4b3ec61Sdh155122 static void 767f4b3ec61Sdh155122 netstack_do_destroy(void) 768f4b3ec61Sdh155122 { 769f4b3ec61Sdh155122 /* 770f4b3ec61Sdh155122 * Have to walk the moduleids in reverse order since some 771f4b3ec61Sdh155122 * modules make implicit assumptions about the order 772f4b3ec61Sdh155122 */ 773f4b3ec61Sdh155122 netstack_do_apply(B_TRUE, netstack_apply_destroy); 774f4b3ec61Sdh155122 } 775f4b3ec61Sdh155122 776f4b3ec61Sdh155122 /* 777f4b3ec61Sdh155122 * Get the stack instance used in caller's zone. 778f4b3ec61Sdh155122 * Increases the reference count, caller must do a netstack_rele. 779f4b3ec61Sdh155122 * It can't be called after zone_destroy() has started. 780f4b3ec61Sdh155122 */ 781*fd006805Snordmark netstack_t * 782f4b3ec61Sdh155122 netstack_get_current(void) 783f4b3ec61Sdh155122 { 784f4b3ec61Sdh155122 netstack_t *ns; 785f4b3ec61Sdh155122 786f4b3ec61Sdh155122 ns = curproc->p_zone->zone_netstack; 787f4b3ec61Sdh155122 ASSERT(ns != NULL); 788f4b3ec61Sdh155122 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) 789f4b3ec61Sdh155122 return (NULL); 790f4b3ec61Sdh155122 791f4b3ec61Sdh155122 netstack_hold(ns); 792f4b3ec61Sdh155122 793f4b3ec61Sdh155122 return (ns); 794f4b3ec61Sdh155122 } 795f4b3ec61Sdh155122 796f4b3ec61Sdh155122 /* 797f4b3ec61Sdh155122 * Find a stack instance given the cred. 798f4b3ec61Sdh155122 * This is used by the modules to potentially allow for a future when 799f4b3ec61Sdh155122 * something other than the zoneid is used to determine the stack. 800f4b3ec61Sdh155122 */ 801f4b3ec61Sdh155122 netstack_t * 802f4b3ec61Sdh155122 netstack_find_by_cred(const cred_t *cr) 803f4b3ec61Sdh155122 { 804f4b3ec61Sdh155122 zoneid_t zoneid = crgetzoneid(cr); 805f4b3ec61Sdh155122 806f4b3ec61Sdh155122 /* Handle the case when cr_zone is NULL */ 807f4b3ec61Sdh155122 if (zoneid == (zoneid_t)-1) 808f4b3ec61Sdh155122 zoneid = GLOBAL_ZONEID; 809f4b3ec61Sdh155122 810f4b3ec61Sdh155122 /* For performance ... */ 811f4b3ec61Sdh155122 if (curproc->p_zone->zone_id == zoneid) 812f4b3ec61Sdh155122 return (netstack_get_current()); 813f4b3ec61Sdh155122 else 814f4b3ec61Sdh155122 return (netstack_find_by_zoneid(zoneid)); 815f4b3ec61Sdh155122 } 816f4b3ec61Sdh155122 817f4b3ec61Sdh155122 /* 818f4b3ec61Sdh155122 * Find a stack instance given the zoneid. 819f4b3ec61Sdh155122 * Increases the reference count if found; caller must do a 820f4b3ec61Sdh155122 * netstack_rele(). 821f4b3ec61Sdh155122 * 822f4b3ec61Sdh155122 * If there is no exact match then assume the shared stack instance 823f4b3ec61Sdh155122 * matches. 824f4b3ec61Sdh155122 * 825f4b3ec61Sdh155122 * Skip the unitialized ones. 826f4b3ec61Sdh155122 */ 827f4b3ec61Sdh155122 netstack_t * 828f4b3ec61Sdh155122 netstack_find_by_zoneid(zoneid_t zoneid) 829f4b3ec61Sdh155122 { 830f4b3ec61Sdh155122 netstack_t *ns; 831f4b3ec61Sdh155122 zone_t *zone; 832f4b3ec61Sdh155122 833f4b3ec61Sdh155122 zone = zone_find_by_id(zoneid); 834f4b3ec61Sdh155122 835f4b3ec61Sdh155122 if (zone == NULL) 836f4b3ec61Sdh155122 return (NULL); 837f4b3ec61Sdh155122 838f4b3ec61Sdh155122 ns = zone->zone_netstack; 839f4b3ec61Sdh155122 ASSERT(ns != NULL); 840f4b3ec61Sdh155122 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) 841f4b3ec61Sdh155122 ns = NULL; 842f4b3ec61Sdh155122 else 843f4b3ec61Sdh155122 netstack_hold(ns); 844f4b3ec61Sdh155122 845f4b3ec61Sdh155122 zone_rele(zone); 846f4b3ec61Sdh155122 return (ns); 847f4b3ec61Sdh155122 } 848f4b3ec61Sdh155122 849f4b3ec61Sdh155122 /* 850f4b3ec61Sdh155122 * Find a stack instance given the zoneid. 851f4b3ec61Sdh155122 * Increases the reference count if found; caller must do a 852f4b3ec61Sdh155122 * netstack_rele(). 853f4b3ec61Sdh155122 * 854f4b3ec61Sdh155122 * If there is no exact match then assume the shared stack instance 855f4b3ec61Sdh155122 * matches. 856f4b3ec61Sdh155122 * 857f4b3ec61Sdh155122 * Skip the unitialized ones. 858f4b3ec61Sdh155122 * 859f4b3ec61Sdh155122 * NOTE: The caller must hold zonehash_lock. 860f4b3ec61Sdh155122 */ 861f4b3ec61Sdh155122 netstack_t * 862f4b3ec61Sdh155122 netstack_find_by_zoneid_nolock(zoneid_t zoneid) 863f4b3ec61Sdh155122 { 864f4b3ec61Sdh155122 netstack_t *ns; 865f4b3ec61Sdh155122 zone_t *zone; 866f4b3ec61Sdh155122 867f4b3ec61Sdh155122 zone = zone_find_by_id_nolock(zoneid); 868f4b3ec61Sdh155122 869f4b3ec61Sdh155122 if (zone == NULL) 870f4b3ec61Sdh155122 return (NULL); 871f4b3ec61Sdh155122 872f4b3ec61Sdh155122 ns = zone->zone_netstack; 873f4b3ec61Sdh155122 ASSERT(ns != NULL); 874f4b3ec61Sdh155122 875f4b3ec61Sdh155122 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) 876f4b3ec61Sdh155122 ns = NULL; 877f4b3ec61Sdh155122 else 878f4b3ec61Sdh155122 netstack_hold(ns); 879f4b3ec61Sdh155122 880f4b3ec61Sdh155122 zone_rele(zone); 881f4b3ec61Sdh155122 return (ns); 882f4b3ec61Sdh155122 } 883f4b3ec61Sdh155122 884f4b3ec61Sdh155122 /* 885f4b3ec61Sdh155122 * Find a stack instance given the stackid with exact match? 886f4b3ec61Sdh155122 * Increases the reference count if found; caller must do a 887f4b3ec61Sdh155122 * netstack_rele(). 888f4b3ec61Sdh155122 * 889f4b3ec61Sdh155122 * Skip the unitialized ones. 890f4b3ec61Sdh155122 */ 891f4b3ec61Sdh155122 netstack_t * 892f4b3ec61Sdh155122 netstack_find_by_stackid(netstackid_t stackid) 893f4b3ec61Sdh155122 { 894f4b3ec61Sdh155122 netstack_t *ns; 895f4b3ec61Sdh155122 896f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 897f4b3ec61Sdh155122 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) { 898f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 899f4b3ec61Sdh155122 if (ns->netstack_stackid == stackid && 900f4b3ec61Sdh155122 !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) { 901f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 902f4b3ec61Sdh155122 netstack_hold(ns); 903f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 904f4b3ec61Sdh155122 return (ns); 905f4b3ec61Sdh155122 } 906f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 907f4b3ec61Sdh155122 } 908f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 909f4b3ec61Sdh155122 return (NULL); 910f4b3ec61Sdh155122 } 911f4b3ec61Sdh155122 912f4b3ec61Sdh155122 void 913f4b3ec61Sdh155122 netstack_rele(netstack_t *ns) 914f4b3ec61Sdh155122 { 915f4b3ec61Sdh155122 netstack_t **nsp; 916f4b3ec61Sdh155122 boolean_t found; 917f4b3ec61Sdh155122 int refcnt, numzones; 918f4b3ec61Sdh155122 919f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 920f4b3ec61Sdh155122 ASSERT(ns->netstack_refcnt > 0); 921f4b3ec61Sdh155122 ns->netstack_refcnt--; 922f4b3ec61Sdh155122 /* 923f4b3ec61Sdh155122 * As we drop the lock additional netstack_rele()s can come in 924f4b3ec61Sdh155122 * and decrement the refcnt to zero and free the netstack_t. 925f4b3ec61Sdh155122 * Store pointers in local variables and if we were not the last 926f4b3ec61Sdh155122 * then don't reference the netstack_t after that. 927f4b3ec61Sdh155122 */ 928f4b3ec61Sdh155122 refcnt = ns->netstack_refcnt; 929f4b3ec61Sdh155122 numzones = ns->netstack_numzones; 930f4b3ec61Sdh155122 DTRACE_PROBE1(netstack__dec__ref, netstack_t *, ns); 931f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 932f4b3ec61Sdh155122 933f4b3ec61Sdh155122 if (refcnt == 0 && numzones == 0) { 934f4b3ec61Sdh155122 /* 935f4b3ec61Sdh155122 * Time to call the destroy functions and free up 936f4b3ec61Sdh155122 * the structure 937f4b3ec61Sdh155122 */ 938f4b3ec61Sdh155122 netstack_stack_inactive(ns); 939f4b3ec61Sdh155122 940f4b3ec61Sdh155122 /* Finally remove from list of netstacks */ 941f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 942f4b3ec61Sdh155122 found = B_FALSE; 943f4b3ec61Sdh155122 for (nsp = &netstack_head; *nsp != NULL; 944f4b3ec61Sdh155122 nsp = &(*nsp)->netstack_next) { 945f4b3ec61Sdh155122 if (*nsp == ns) { 946f4b3ec61Sdh155122 *nsp = ns->netstack_next; 947f4b3ec61Sdh155122 ns->netstack_next = NULL; 948f4b3ec61Sdh155122 found = B_TRUE; 949f4b3ec61Sdh155122 break; 950f4b3ec61Sdh155122 } 951f4b3ec61Sdh155122 } 952f4b3ec61Sdh155122 ASSERT(found); 953f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 954f4b3ec61Sdh155122 955f4b3ec61Sdh155122 ASSERT(ns->netstack_flags & NSF_CLOSING); 956f4b3ec61Sdh155122 kmem_free(ns, sizeof (*ns)); 957f4b3ec61Sdh155122 } 958f4b3ec61Sdh155122 } 959f4b3ec61Sdh155122 960f4b3ec61Sdh155122 void 961f4b3ec61Sdh155122 netstack_hold(netstack_t *ns) 962f4b3ec61Sdh155122 { 963f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 964f4b3ec61Sdh155122 ns->netstack_refcnt++; 965f4b3ec61Sdh155122 ASSERT(ns->netstack_refcnt > 0); 966f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 967f4b3ec61Sdh155122 DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns); 968f4b3ec61Sdh155122 } 969f4b3ec61Sdh155122 970f4b3ec61Sdh155122 /* 971f4b3ec61Sdh155122 * To support kstat_create_netstack() using kstat_zone_add we need 972f4b3ec61Sdh155122 * to track both 973f4b3ec61Sdh155122 * - all zoneids that use the global/shared stack 974f4b3ec61Sdh155122 * - all kstats that have been added for the shared stack 975f4b3ec61Sdh155122 */ 976f4b3ec61Sdh155122 kstat_t * 977f4b3ec61Sdh155122 kstat_create_netstack(char *ks_module, int ks_instance, char *ks_name, 978f4b3ec61Sdh155122 char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags, 979f4b3ec61Sdh155122 netstackid_t ks_netstackid) 980f4b3ec61Sdh155122 { 981f4b3ec61Sdh155122 kstat_t *ks; 982f4b3ec61Sdh155122 983f4b3ec61Sdh155122 if (ks_netstackid == GLOBAL_NETSTACKID) { 984f4b3ec61Sdh155122 ks = kstat_create_zone(ks_module, ks_instance, ks_name, 985f4b3ec61Sdh155122 ks_class, ks_type, ks_ndata, ks_flags, GLOBAL_ZONEID); 986f4b3ec61Sdh155122 if (ks != NULL) 987f4b3ec61Sdh155122 netstack_shared_kstat_add(ks); 988f4b3ec61Sdh155122 return (ks); 989f4b3ec61Sdh155122 } else { 990f4b3ec61Sdh155122 zoneid_t zoneid = ks_netstackid; 991f4b3ec61Sdh155122 992f4b3ec61Sdh155122 return (kstat_create_zone(ks_module, ks_instance, ks_name, 993f4b3ec61Sdh155122 ks_class, ks_type, ks_ndata, ks_flags, zoneid)); 994f4b3ec61Sdh155122 } 995f4b3ec61Sdh155122 } 996f4b3ec61Sdh155122 997f4b3ec61Sdh155122 void 998f4b3ec61Sdh155122 kstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid) 999f4b3ec61Sdh155122 { 1000f4b3ec61Sdh155122 if (ks_netstackid == GLOBAL_NETSTACKID) { 1001f4b3ec61Sdh155122 netstack_shared_kstat_remove(ks); 1002f4b3ec61Sdh155122 } 1003f4b3ec61Sdh155122 kstat_delete(ks); 1004f4b3ec61Sdh155122 } 1005f4b3ec61Sdh155122 1006f4b3ec61Sdh155122 static void 1007f4b3ec61Sdh155122 netstack_shared_zone_add(zoneid_t zoneid) 1008f4b3ec61Sdh155122 { 1009f4b3ec61Sdh155122 struct shared_zone_list *sz; 1010f4b3ec61Sdh155122 struct shared_kstat_list *sk; 1011f4b3ec61Sdh155122 1012f4b3ec61Sdh155122 sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP); 1013f4b3ec61Sdh155122 sz->sz_zoneid = zoneid; 1014f4b3ec61Sdh155122 1015f4b3ec61Sdh155122 /* Insert in list */ 1016f4b3ec61Sdh155122 mutex_enter(&netstack_shared_lock); 1017f4b3ec61Sdh155122 sz->sz_next = netstack_shared_zones; 1018f4b3ec61Sdh155122 netstack_shared_zones = sz; 1019f4b3ec61Sdh155122 1020f4b3ec61Sdh155122 /* 1021f4b3ec61Sdh155122 * Perform kstat_zone_add for each existing shared stack kstat. 1022f4b3ec61Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_add. 1023f4b3ec61Sdh155122 */ 1024f4b3ec61Sdh155122 for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) { 1025f4b3ec61Sdh155122 kstat_zone_add(sk->sk_kstat, zoneid); 1026f4b3ec61Sdh155122 } 1027f4b3ec61Sdh155122 mutex_exit(&netstack_shared_lock); 1028f4b3ec61Sdh155122 } 1029f4b3ec61Sdh155122 1030f4b3ec61Sdh155122 static void 1031f4b3ec61Sdh155122 netstack_shared_zone_remove(zoneid_t zoneid) 1032f4b3ec61Sdh155122 { 1033f4b3ec61Sdh155122 struct shared_zone_list **szp, *sz; 1034f4b3ec61Sdh155122 struct shared_kstat_list *sk; 1035f4b3ec61Sdh155122 1036f4b3ec61Sdh155122 /* Find in list */ 1037f4b3ec61Sdh155122 mutex_enter(&netstack_shared_lock); 1038f4b3ec61Sdh155122 sz = NULL; 1039f4b3ec61Sdh155122 for (szp = &netstack_shared_zones; *szp != NULL; 1040f4b3ec61Sdh155122 szp = &((*szp)->sz_next)) { 1041f4b3ec61Sdh155122 if ((*szp)->sz_zoneid == zoneid) { 1042f4b3ec61Sdh155122 sz = *szp; 1043f4b3ec61Sdh155122 break; 1044f4b3ec61Sdh155122 } 1045f4b3ec61Sdh155122 } 1046f4b3ec61Sdh155122 /* We must find it */ 1047f4b3ec61Sdh155122 ASSERT(sz != NULL); 1048f4b3ec61Sdh155122 *szp = sz->sz_next; 1049f4b3ec61Sdh155122 sz->sz_next = NULL; 1050f4b3ec61Sdh155122 1051f4b3ec61Sdh155122 /* 1052f4b3ec61Sdh155122 * Perform kstat_zone_remove for each existing shared stack kstat. 1053f4b3ec61Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_remove. 1054f4b3ec61Sdh155122 */ 1055f4b3ec61Sdh155122 for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) { 1056f4b3ec61Sdh155122 kstat_zone_remove(sk->sk_kstat, zoneid); 1057f4b3ec61Sdh155122 } 1058f4b3ec61Sdh155122 mutex_exit(&netstack_shared_lock); 1059f4b3ec61Sdh155122 1060f4b3ec61Sdh155122 kmem_free(sz, sizeof (*sz)); 1061f4b3ec61Sdh155122 } 1062f4b3ec61Sdh155122 1063f4b3ec61Sdh155122 static void 1064f4b3ec61Sdh155122 netstack_shared_kstat_add(kstat_t *ks) 1065f4b3ec61Sdh155122 { 1066f4b3ec61Sdh155122 struct shared_zone_list *sz; 1067f4b3ec61Sdh155122 struct shared_kstat_list *sk; 1068f4b3ec61Sdh155122 1069f4b3ec61Sdh155122 sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP); 1070f4b3ec61Sdh155122 sk->sk_kstat = ks; 1071f4b3ec61Sdh155122 1072f4b3ec61Sdh155122 /* Insert in list */ 1073f4b3ec61Sdh155122 mutex_enter(&netstack_shared_lock); 1074f4b3ec61Sdh155122 sk->sk_next = netstack_shared_kstats; 1075f4b3ec61Sdh155122 netstack_shared_kstats = sk; 1076f4b3ec61Sdh155122 1077f4b3ec61Sdh155122 /* 1078f4b3ec61Sdh155122 * Perform kstat_zone_add for each existing shared stack zone. 1079f4b3ec61Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_add. 1080f4b3ec61Sdh155122 */ 1081f4b3ec61Sdh155122 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) { 1082f4b3ec61Sdh155122 kstat_zone_add(ks, sz->sz_zoneid); 1083f4b3ec61Sdh155122 } 1084f4b3ec61Sdh155122 mutex_exit(&netstack_shared_lock); 1085f4b3ec61Sdh155122 } 1086f4b3ec61Sdh155122 1087f4b3ec61Sdh155122 static void 1088f4b3ec61Sdh155122 netstack_shared_kstat_remove(kstat_t *ks) 1089f4b3ec61Sdh155122 { 1090f4b3ec61Sdh155122 struct shared_zone_list *sz; 1091f4b3ec61Sdh155122 struct shared_kstat_list **skp, *sk; 1092f4b3ec61Sdh155122 1093f4b3ec61Sdh155122 /* Find in list */ 1094f4b3ec61Sdh155122 mutex_enter(&netstack_shared_lock); 1095f4b3ec61Sdh155122 sk = NULL; 1096f4b3ec61Sdh155122 for (skp = &netstack_shared_kstats; *skp != NULL; 1097f4b3ec61Sdh155122 skp = &((*skp)->sk_next)) { 1098f4b3ec61Sdh155122 if ((*skp)->sk_kstat == ks) { 1099f4b3ec61Sdh155122 sk = *skp; 1100f4b3ec61Sdh155122 break; 1101f4b3ec61Sdh155122 } 1102f4b3ec61Sdh155122 } 1103f4b3ec61Sdh155122 /* Must find it */ 1104f4b3ec61Sdh155122 ASSERT(sk != NULL); 1105f4b3ec61Sdh155122 *skp = sk->sk_next; 1106f4b3ec61Sdh155122 sk->sk_next = NULL; 1107f4b3ec61Sdh155122 1108f4b3ec61Sdh155122 /* 1109f4b3ec61Sdh155122 * Perform kstat_zone_remove for each existing shared stack kstat. 1110f4b3ec61Sdh155122 * Note: Holds netstack_shared_lock lock across kstat_zone_remove. 1111f4b3ec61Sdh155122 */ 1112f4b3ec61Sdh155122 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) { 1113f4b3ec61Sdh155122 kstat_zone_remove(ks, sz->sz_zoneid); 1114f4b3ec61Sdh155122 } 1115f4b3ec61Sdh155122 mutex_exit(&netstack_shared_lock); 1116f4b3ec61Sdh155122 kmem_free(sk, sizeof (*sk)); 1117f4b3ec61Sdh155122 } 1118f4b3ec61Sdh155122 1119f4b3ec61Sdh155122 /* 1120f4b3ec61Sdh155122 * If a zoneid is part of the shared zone, return true 1121f4b3ec61Sdh155122 */ 1122f4b3ec61Sdh155122 static boolean_t 1123f4b3ec61Sdh155122 netstack_find_shared_zoneid(zoneid_t zoneid) 1124f4b3ec61Sdh155122 { 1125f4b3ec61Sdh155122 struct shared_zone_list *sz; 1126f4b3ec61Sdh155122 1127f4b3ec61Sdh155122 mutex_enter(&netstack_shared_lock); 1128f4b3ec61Sdh155122 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) { 1129f4b3ec61Sdh155122 if (sz->sz_zoneid == zoneid) { 1130f4b3ec61Sdh155122 mutex_exit(&netstack_shared_lock); 1131f4b3ec61Sdh155122 return (B_TRUE); 1132f4b3ec61Sdh155122 } 1133f4b3ec61Sdh155122 } 1134f4b3ec61Sdh155122 mutex_exit(&netstack_shared_lock); 1135f4b3ec61Sdh155122 return (B_FALSE); 1136f4b3ec61Sdh155122 } 1137f4b3ec61Sdh155122 1138f4b3ec61Sdh155122 /* 1139f4b3ec61Sdh155122 * Hide the fact that zoneids and netstackids are allocated from 1140f4b3ec61Sdh155122 * the same space in the current implementation. 1141f4b3ec61Sdh155122 * XXX could add checks that the stackid/zoneids are valid... 1142f4b3ec61Sdh155122 */ 1143f4b3ec61Sdh155122 zoneid_t 1144f4b3ec61Sdh155122 netstackid_to_zoneid(netstackid_t stackid) 1145f4b3ec61Sdh155122 { 1146f4b3ec61Sdh155122 return (stackid); 1147f4b3ec61Sdh155122 } 1148f4b3ec61Sdh155122 1149f4b3ec61Sdh155122 netstackid_t 1150f4b3ec61Sdh155122 zoneid_to_netstackid(zoneid_t zoneid) 1151f4b3ec61Sdh155122 { 1152f4b3ec61Sdh155122 if (netstack_find_shared_zoneid(zoneid)) 1153f4b3ec61Sdh155122 return (GLOBAL_ZONEID); 1154f4b3ec61Sdh155122 else 1155f4b3ec61Sdh155122 return (zoneid); 1156f4b3ec61Sdh155122 } 1157f4b3ec61Sdh155122 1158f4b3ec61Sdh155122 /* 1159f4b3ec61Sdh155122 * Simplistic support for walking all the handles. 1160f4b3ec61Sdh155122 * Example usage: 1161f4b3ec61Sdh155122 * netstack_handle_t nh; 1162f4b3ec61Sdh155122 * netstack_t *ns; 1163f4b3ec61Sdh155122 * 1164f4b3ec61Sdh155122 * netstack_next_init(&nh); 1165f4b3ec61Sdh155122 * while ((ns = netstack_next(&nh)) != NULL) { 1166f4b3ec61Sdh155122 * do something; 1167f4b3ec61Sdh155122 * netstack_rele(ns); 1168f4b3ec61Sdh155122 * } 1169f4b3ec61Sdh155122 * netstack_next_fini(&nh); 1170f4b3ec61Sdh155122 */ 1171f4b3ec61Sdh155122 void 1172f4b3ec61Sdh155122 netstack_next_init(netstack_handle_t *handle) 1173f4b3ec61Sdh155122 { 1174f4b3ec61Sdh155122 *handle = 0; 1175f4b3ec61Sdh155122 } 1176f4b3ec61Sdh155122 1177f4b3ec61Sdh155122 /* ARGSUSED */ 1178f4b3ec61Sdh155122 void 1179f4b3ec61Sdh155122 netstack_next_fini(netstack_handle_t *handle) 1180f4b3ec61Sdh155122 { 1181f4b3ec61Sdh155122 } 1182f4b3ec61Sdh155122 1183f4b3ec61Sdh155122 netstack_t * 1184f4b3ec61Sdh155122 netstack_next(netstack_handle_t *handle) 1185f4b3ec61Sdh155122 { 1186f4b3ec61Sdh155122 netstack_t *ns; 1187f4b3ec61Sdh155122 int i, end; 1188f4b3ec61Sdh155122 1189f4b3ec61Sdh155122 end = *handle; 1190f4b3ec61Sdh155122 /* Walk skipping *handle number of instances */ 1191f4b3ec61Sdh155122 1192f4b3ec61Sdh155122 /* Look if there is a matching stack instance */ 1193f4b3ec61Sdh155122 mutex_enter(&netstack_g_lock); 1194f4b3ec61Sdh155122 ns = netstack_head; 1195f4b3ec61Sdh155122 for (i = 0; i < end; i++) { 1196f4b3ec61Sdh155122 if (ns == NULL) 1197f4b3ec61Sdh155122 break; 1198f4b3ec61Sdh155122 ns = ns->netstack_next; 1199f4b3ec61Sdh155122 } 1200f4b3ec61Sdh155122 /* skip those with that aren't really here */ 1201f4b3ec61Sdh155122 while (ns != NULL) { 1202f4b3ec61Sdh155122 mutex_enter(&ns->netstack_lock); 1203f4b3ec61Sdh155122 if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) { 1204f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 1205f4b3ec61Sdh155122 break; 1206f4b3ec61Sdh155122 } 1207f4b3ec61Sdh155122 mutex_exit(&ns->netstack_lock); 1208f4b3ec61Sdh155122 end++; 1209f4b3ec61Sdh155122 ns = ns->netstack_next; 1210f4b3ec61Sdh155122 } 1211f4b3ec61Sdh155122 if (ns != NULL) { 1212f4b3ec61Sdh155122 *handle = end + 1; 1213f4b3ec61Sdh155122 netstack_hold(ns); 1214f4b3ec61Sdh155122 } 1215f4b3ec61Sdh155122 mutex_exit(&netstack_g_lock); 1216f4b3ec61Sdh155122 return (ns); 1217f4b3ec61Sdh155122 } 1218