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