f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * CDDL HEADER START
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * The contents of this file are subject to the terms of the
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Common Development and Distribution License (the "License").
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * You may not use this file except in compliance with the License.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * or http://www.opensolaris.org/os/licensing.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * See the License for the specific language governing permissions
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * and limitations under the License.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * When distributing Covered Code, include this CDDL HEADER in each
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If applicable, add the following below this CDDL HEADER, with the
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * fields enclosed by brackets "[]" replaced with your own identifying
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * information: Portions Copyright [yyyy] [name of copyright owner]
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * CDDL HEADER END
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Use is subject to license terms.
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill * Copyright (c) 2016, Joyent, Inc. All rights reserved.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/param.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/sysmacros.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/vm.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/proc.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/tuneable.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/systm.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/cmn_err.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/debug.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/sdt.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/mutex.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/bitmap.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/atomic.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/kobj.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/disp.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <vm/seg_kmem.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/zone.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#include <sys/netstack.h>
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * What we use so that the zones framework can tell us about new zones,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * which we use to create new stacks.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic zone_key_t netstack_zone_key;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic int netstack_initialized = 0;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Track the registered netstacks.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * The global lock protects
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * - ns_reg
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * - the list starting at netstack_head and following the netstack_next
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * pointers.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic kmutex_t netstack_g_lock;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Registry of netstacks with their create/shutdown/destory functions.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic struct netstack_registry ns_reg[NS_MAX];
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Global list of existing stacks. We use this when a new zone with
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * an exclusive IP instance is created.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note that in some cases a netstack_t needs to stay around after the zone
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * has gone away. This is because there might be outstanding references
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * (from TCP TIME_WAIT connections, IPsec state, etc). The netstack_t data
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * structure and all the foo_stack_t's hanging off of it will be cleaned up
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * when the last reference to it is dropped.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * However, the same zone might be rebooted. That is handled using the
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * assumption that the zones framework picks a new zoneid each time a zone
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * is (re)booted. We assert for that condition in netstack_zone_create().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Thus the old netstack_t can take its time for things to time out.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic netstack_t *netstack_head;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * To support kstat_create_netstack() using kstat_zone_add we need
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * to track both
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * - all zoneids that use the global/shared stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * - all kstats that have been added for the shared stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstruct shared_zone_list {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_zone_list *sz_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zoneid_t sz_zoneid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh};
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstruct shared_kstat_list {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_kstat_list *sk_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_t *sk_kstat;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh};
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic kmutex_t netstack_shared_lock; /* protects the following two */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic struct shared_zone_list *netstack_shared_zones;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic struct shared_kstat_list *netstack_shared_kstats;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void *netstack_zone_create(zoneid_t zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_zone_shutdown(zoneid_t zoneid, void *arg);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_zone_destroy(zoneid_t zoneid, void *arg);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_shared_zone_add(zoneid_t zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_shared_zone_remove(zoneid_t zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_shared_kstat_add(kstat_t *ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_shared_kstat_remove(kstat_t *ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmarktypedef boolean_t applyfn_t(kmutex_t *, netstack_t *, int);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic void apply_all_netstacks(int, applyfn_t *);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic void apply_all_modules(netstack_t *, applyfn_t *);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic void apply_all_modules_reverse(netstack_t *, applyfn_t *);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t netstack_apply_create(kmutex_t *, netstack_t *, int);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t netstack_apply_shutdown(kmutex_t *, netstack_t *, int);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t netstack_apply_destroy(kmutex_t *, netstack_t *, int);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t wait_for_zone_creator(netstack_t *, kmutex_t *);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t wait_for_nms_inprogress(netstack_t *, nm_state_t *,
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark kmutex_t *);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_init(void)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_initialized = 1;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * We want to be informed each time a zone is created or
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * destroyed in the kernel, so we can maintain the
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * stack instance information.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone_key_create(&netstack_zone_key, netstack_zone_create,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_zone_shutdown, netstack_zone_destroy);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Register a new module with the framework.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * This registers interest in changes to the set of netstacks.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * The createfn and destroyfn are required, but the shutdownfn can be
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * NULL.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note that due to the current zsd implementation, when the create
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * function is called the zone isn't fully present, thus functions
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * like zone_find_by_* will fail, hence the create function can not
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * use many zones kernel functions including zcmn_err().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_register(int moduleid,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void *(*module_create)(netstackid_t, netstack_t *),
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void (*module_shutdown)(netstackid_t, void *),
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void (*module_destroy)(netstackid_t, void *))
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(netstack_initialized);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(moduleid >= 0 && moduleid < NS_MAX);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(module_create != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Make instances created after this point in time run the create
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * callback.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_create == NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_flags == 0);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_create = module_create;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_shutdown = module_shutdown;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_destroy = module_destroy;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_flags = NRF_REGISTERED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Determine the set of stacks that exist before we drop the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Set NSS_CREATE_NEEDED for each of those.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstacks which have been deleted will have NSS_CREATE_COMPLETED
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * set, but check NSF_CLOSING to be sure.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[moduleid];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (!(ns->netstack_flags & NSF_CLOSING) &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_CREATE_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_CREATE_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__create__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * At this point in time a new instance can be created or an instance
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * can be destroyed, or some other module can register or unregister.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Make sure we either run all the create functions for this moduleid
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * or we wait for any other creators for this moduleid.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_netstacks(moduleid, netstack_apply_create);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_unregister(int moduleid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(moduleid >= 0 && moduleid < NS_MAX);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_create != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Determine the set of stacks that exist before we drop the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Set NSS_SHUTDOWN_NEEDED and NSS_DESTROY_NEEDED for each of those.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * That ensures that when we return all the callbacks for existing
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * instances have completed. And since we set NRF_DYING no new
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * instances can use this module.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi boolean_t created = B_FALSE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[moduleid];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi /*
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * We need to be careful here. We could actually have a netstack
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * being created as we speak waiting for us to let go of this
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * lock to proceed. It may have set NSS_CREATE_NEEDED, but not
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * have gotten to the point of completing it yet. If
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * NSS_CREATE_NEEDED, we can safely just remove it here and
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * never create the module. However, if NSS_CREATE_INPROGRESS is
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * set, we need to still flag this module for shutdown and
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * deletion, just as though it had reached NSS_CREATE_COMPLETED.
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi *
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * It is safe to do that because of two different guarantees
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * that exist in the system. The first is that before we do a
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * create, shutdown, or destroy, we ensure that nothing else is
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * in progress in the system for this netstack and wait for it
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * to complete. Secondly, because the zone is being created, we
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * know that the following call to apply_all_netstack will block
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi * on the zone finishing its initialization.
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi */
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi if (nms->nms_flags & NSS_CREATE_NEEDED)
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi nms->nms_flags &= ~NSS_CREATE_NEEDED;
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi if (nms->nms_flags & NSS_CREATE_INPROGRESS ||
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi nms->nms_flags & NSS_CREATE_COMPLETED)
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi created = B_TRUE;
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi if (ns_reg[moduleid].nr_shutdown != NULL && created &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_CREATE_COMPLETED) &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__shutdown__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) &&
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi ns_reg[moduleid].nr_destroy != NULL && created &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_DESTROY_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_DESTROY_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__destroy__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Prevent any new netstack from calling the registered create
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * function, while keeping the function pointers in place until the
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * shutdown and destroy callbacks are complete.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns_reg[moduleid].nr_flags |= NRF_DYING;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_netstacks(moduleid, netstack_apply_shutdown);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_netstacks(moduleid, netstack_apply_destroy);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Clear the nms_flags so that we can handle this module
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * being loaded again.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Also remove the registered functions.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(ns_reg[moduleid].nr_flags & NRF_DYING);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[moduleid];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (nms->nms_flags & NSS_DESTROY_COMPLETED) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags = 0;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__destroy__done,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_create = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_shutdown = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_destroy = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[moduleid].nr_flags = 0;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Lookup and/or allocate a netstack for this zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_zone_create(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t stackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t **nsp;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone_t *zone;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh int i;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(netstack_initialized);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone = zone_find_by_id_nolock(zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(zone != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (zone->zone_flags & ZF_NET_EXCL) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh stackid = zoneid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh } else {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Look for the stack instance for the global */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh stackid = GLOBAL_NETSTACKID;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Allocate even if it isn't needed; simplifies locking */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Look if there is a matching stack instance */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (nsp = &netstack_head; *nsp != NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh nsp = &((*nsp)->netstack_next)) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((*nsp)->netstack_stackid == stackid) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Should never find a pre-existing exclusive stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill VERIFY(stackid == GLOBAL_NETSTACKID);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kmem_free(ns, sizeof (netstack_t));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = *nsp;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_numzones++;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__inc__numzones,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Record that we have a new shared stack zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_shared_zone_add(zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone->zone_netstack = ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Not found */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_init(&ns->netstack_cv, NULL, CV_DEFAULT, NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_stackid = zoneid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_numzones = 1;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_flags = NSF_UNINIT;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *nsp = ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone->zone_netstack = ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Mark this netstack as having a CREATE running so
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * any netstack_register/netstack_unregister waits for
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * the existing create callbacks to complete in moduleid order
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns->netstack_flags |= NSF_ZONE_CREATE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Determine the set of module create functions that need to be
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * called before we drop the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Set NSS_CREATE_NEEDED for each of those.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Skip any with NRF_DYING set, since those are in the process of
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * going away, by checking for flags being exactly NRF_REGISTERED.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[i];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_init(&nms->nms_cv, NULL, CV_DEFAULT, NULL);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if ((ns_reg[i].nr_flags == NRF_REGISTERED) &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_CREATE_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_CREATE_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__create__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, i);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_modules(ns, netstack_apply_create);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_flags &= ~NSF_UNINIT;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(ns->netstack_flags & NSF_ZONE_CREATE);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns->netstack_flags &= ~NSF_ZONE_CREATE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_broadcast(&ns->netstack_cv);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_zone_shutdown(zoneid_t zoneid, void *arg)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns = (netstack_t *)arg;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh int i;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(arg != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_numzones > 0);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns->netstack_numzones != 1) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Stack instance being used by other zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Mark this netstack as having a SHUTDOWN running so
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * any netstack_register/netstack_unregister waits for
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * the existing create callbacks to complete in moduleid order
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns->netstack_flags |= NSF_ZONE_SHUTDOWN;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Determine the set of stacks that exist before we drop the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Set NSS_SHUTDOWN_NEEDED for each of those.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[i];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[i].nr_shutdown != NULL &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_CREATE_COMPLETED) &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__shutdown__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, i);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /*
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * Call the shutdown function for all registered modules for this
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * netstack.
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark */
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed apply_all_modules_reverse(ns, netstack_apply_shutdown);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(ns->netstack_flags & NSF_ZONE_SHUTDOWN);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns->netstack_flags &= ~NSF_ZONE_SHUTDOWN;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_broadcast(&ns->netstack_cv);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Common routine to release a zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If this was the last zone using the stack instance then prepare to
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * have the refcnt dropping to zero free the zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_zone_destroy(zoneid_t zoneid, void *arg)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns = (netstack_t *)arg;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(arg != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_numzones > 0);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_numzones--;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns->netstack_numzones != 0) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Stack instance being used by other zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Record that we a shared stack zone has gone away */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_shared_zone_remove(zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * Set CLOSING so that netstack_find_by will not find it.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_flags |= NSF_CLOSING;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* No other thread can call zone_destroy for this stack */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Decrease refcnt to account for the one in netstack_zone_init()
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_rele(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Called when the reference count drops to zero.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the destroy functions for each registered module.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_stack_inactive(netstack_t *ns)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh int i;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Mark this netstack as having a DESTROY running so
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * any netstack_register/netstack_unregister waits for
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * the existing destroy callbacks to complete in reverse moduleid order
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns->netstack_flags |= NSF_ZONE_DESTROY;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If the shutdown callback wasn't called earlier (e.g., if this is
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * a netstack shared between multiple zones), then we schedule it now.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Determine the set of stacks that exist before we drop the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Set NSS_DESTROY_NEEDED for each of those. That
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * ensures that when we return all the callbacks for existing
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * instances have completed.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[i];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[i].nr_shutdown != NULL &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_CREATE_COMPLETED) &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__shutdown__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, i);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns_reg[i].nr_destroy != NULL &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_CREATE_COMPLETED) &&
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (nms->nms_flags & NSS_DESTROY_ALL) == 0) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_DESTROY_NEEDED;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__destroy__needed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, i);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /*
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * Call the shutdown and destroy functions for all registered modules
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * for this netstack.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Since there are some ordering dependencies between the modules we
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * tear them down in the reverse order of what was used to create them.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Since a netstack_t is never reused (when a zone is rebooted it gets
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * a new zoneid == netstackid i.e. a new netstack_t is allocated) we
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * leave nms_flags the way it is i.e. with NSS_DESTROY_COMPLETED set.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * That is different than in the netstack_unregister() case.
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark */
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed apply_all_modules_reverse(ns, netstack_apply_shutdown);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_modules_reverse(ns, netstack_apply_destroy);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(ns->netstack_flags & NSF_ZONE_DESTROY);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns->netstack_flags &= ~NSF_ZONE_DESTROY;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_broadcast(&ns->netstack_cv);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark}
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark/*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Apply a function to all netstacks for a particular moduleid.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * If there is any zone activity (due to a zone being created, shutdown,
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * or destroyed) we wait for that to complete before we proceed. This ensures
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * that the moduleids are processed in order when a zone is created or
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * destroyed.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * The applyfn has to drop netstack_g_lock if it does some work.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * In that case we don't follow netstack_next,
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * even if it is possible to do so without any hazards. This is
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * because we want the design to allow for the list of netstacks threaded
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * by netstack_next to change in any arbitrary way during the time the
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * lock was dropped.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * It is safe to restart the loop at netstack_head since the applyfn
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * changes netstack_m_state as it processes things, so a subsequent
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * pass through will have no effect in applyfn, hence the loop will terminate
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * in at worst O(N^2).
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic void
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkapply_all_netstacks(int moduleid, applyfn_t *applyfn)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark{
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark netstack_t *ns;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns = netstack_head;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark while (ns != NULL) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (wait_for_zone_creator(ns, &netstack_g_lock)) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Lock dropped - restart at head */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns = netstack_head;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark } else if ((applyfn)(&netstack_g_lock, ns, moduleid)) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Lock dropped - restart at head */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns = netstack_head;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark } else {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ns = ns->netstack_next;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark}
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark/*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Apply a function to all moduleids for a particular netstack.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Since the netstack linkage doesn't matter in this case we can
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * ignore whether the function drops the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic void
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkapply_all_modules(netstack_t *ns, applyfn_t *applyfn)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark{
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark int i;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * We don't care whether the lock was dropped
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * since we are not iterating over netstack_head.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (void) (applyfn)(&netstack_g_lock, ns, i);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark}
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark/* Like the above but in reverse moduleid order */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic void
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkapply_all_modules_reverse(netstack_t *ns, applyfn_t *applyfn)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark{
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark int i;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&netstack_g_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark for (i = NS_MAX-1; i >= 0; i--) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * We don't care whether the lock was dropped
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * since we are not iterating over netstack_head.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark (void) (applyfn)(&netstack_g_lock, ns, i);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the create function for the ns and moduleid if CREATE_NEEDED
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * is set.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * If some other thread gets here first and sets *_INPROGRESS, then
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * we wait for that thread to complete so that we can ensure that
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * all the callbacks are done when we've looped over all netstacks/moduleids.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * When we call the create function, we temporarily drop the netstack_lock
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * held by the caller, and return true to tell the caller it needs to
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * re-evalute the state.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic boolean_t
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void *result;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t stackid;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[moduleid];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark boolean_t dropped = B_FALSE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(MUTEX_HELD(lockp));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (wait_for_nms_inprogress(ns, nms, lockp))
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (nms->nms_flags & NSS_CREATE_NEEDED) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags &= ~NSS_CREATE_NEEDED;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_CREATE_INPROGRESS;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__create__inprogress,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(lockp);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_create != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh stackid = ns->netstack_stackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__create__start,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t, stackid,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh result = (ns_reg[moduleid].nr_create)(stackid, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__create__end,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void *, result, netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(result != NULL);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(lockp);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_modules[moduleid] = result;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags &= ~NSS_CREATE_INPROGRESS;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_CREATE_COMPLETED;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_broadcast(&nms->nms_cv);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__create__completed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh } else {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * is set.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * If some other thread gets here first and sets *_INPROGRESS, then
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * we wait for that thread to complete so that we can ensure that
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * all the callbacks are done when we've looped over all netstacks/moduleids.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * When we call the shutdown function, we temporarily drop the netstack_lock
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * held by the caller, and return true to tell the caller it needs to
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * re-evalute the state.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic boolean_t
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t stackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void * netstack_module;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[moduleid];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark boolean_t dropped = B_FALSE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(MUTEX_HELD(lockp));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (wait_for_nms_inprogress(ns, nms, lockp))
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (nms->nms_flags & NSS_SHUTDOWN_NEEDED) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags &= ~NSS_SHUTDOWN_NEEDED;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_SHUTDOWN_INPROGRESS;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__shutdown__inprogress,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(lockp);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_shutdown != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh stackid = ns->netstack_stackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_module = ns->netstack_modules[moduleid];
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__shutdown__start,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t, stackid,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void *, netstack_module);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh (ns_reg[moduleid].nr_shutdown)(stackid, netstack_module);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__shutdown__end,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(lockp);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags &= ~NSS_SHUTDOWN_INPROGRESS;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_SHUTDOWN_COMPLETED;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_broadcast(&nms->nms_cv);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__shutdown__completed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh } else {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the destroy function for the ns and moduleid if DESTROY_NEEDED
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * is set.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * If some other thread gets here first and sets *_INPROGRESS, then
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * we wait for that thread to complete so that we can ensure that
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * all the callbacks are done when we've looped over all netstacks/moduleids.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * When we call the destroy function, we temporarily drop the netstack_lock
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * held by the caller, and return true to tell the caller it needs to
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * re-evalute the state.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic boolean_t
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t stackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void * netstack_module;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[moduleid];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark boolean_t dropped = B_FALSE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(MUTEX_HELD(lockp));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (wait_for_nms_inprogress(ns, nms, lockp))
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (nms->nms_flags & NSS_DESTROY_NEEDED) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags &= ~NSS_DESTROY_NEEDED;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_DESTROY_INPROGRESS;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__destroy__inprogress,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(lockp);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns_reg[moduleid].nr_destroy != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh stackid = ns->netstack_stackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_module = ns->netstack_modules[moduleid];
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__destroy__start,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t, stackid,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh void *, netstack_module);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh (ns_reg[moduleid].nr_destroy)(stackid, netstack_module);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__destroy__end,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(lockp);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_modules[moduleid] = NULL;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags &= ~NSS_DESTROY_INPROGRESS;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nms->nms_flags |= NSS_DESTROY_COMPLETED;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_broadcast(&nms->nms_cv);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE2(netstack__destroy__completed,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *, ns, int, moduleid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh } else {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark/*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * If somebody is creating the netstack (due to a new zone being created)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * then we wait for them to complete. This ensures that any additional
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * netstack_register() doesn't cause the create functions to run out of
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * order.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Note that we do not need such a global wait in the case of the shutdown
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * and destroy callbacks, since in that case it is sufficient for both
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * threads to set NEEDED and wait for INPROGRESS to ensure ordering.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Returns true if lockp was temporarily dropped while waiting.
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkwait_for_zone_creator(netstack_t *ns, kmutex_t *lockp)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark boolean_t dropped = B_FALSE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark while (ns->netstack_flags & NSF_ZONE_CREATE) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark DTRACE_PROBE1(netstack__wait__zone__inprogress,
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark netstack_t *, ns);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (lockp != NULL) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(lockp);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_wait(&ns->netstack_cv, &ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (lockp != NULL) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* First drop netstack_lock to preserve order */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(lockp);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark/*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Wait for any INPROGRESS flag to be cleared for the netstack/moduleid
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * combination.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Returns true if lockp was temporarily dropped while waiting.
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkstatic boolean_t
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkwait_for_nms_inprogress(netstack_t *ns, nm_state_t *nms, kmutex_t *lockp)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark boolean_t dropped = B_FALSE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark while (nms->nms_flags & NSS_ALL_INPROGRESS) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark DTRACE_PROBE2(netstack__wait__nms__inprogress,
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark netstack_t *, ns, nm_state_t *, nms);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (lockp != NULL) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark dropped = B_TRUE;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(lockp);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_wait(&nms->nms_cv, &ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark if (lockp != NULL) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* First drop netstack_lock to preserve order */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_exit(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(lockp);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark return (dropped);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Get the stack instance used in caller's zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Increases the reference count, caller must do a netstack_rele.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * It can't be called after zone_destroy() has started.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
fd00680555e8f4173d02435c3b015e23cb232c49nordmarknetstack_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_get_current(void)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = curproc->p_zone->zone_netstack;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_hold(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Find a stack instance given the cred.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * This is used by the modules to potentially allow for a future when
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * something other than the zoneid is used to determine the stack.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_find_by_cred(const cred_t *cr)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zoneid_t zoneid = crgetzoneid(cr);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Handle the case when cr_zone is NULL */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (zoneid == (zoneid_t)-1)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zoneid = GLOBAL_ZONEID;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* For performance ... */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (curproc->p_zone->zone_id == zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (netstack_get_current());
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh else
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (netstack_find_by_zoneid(zoneid));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Find a stack instance given the zoneid.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Increases the reference count if found; caller must do a
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If there is no exact match then assume the shared stack instance
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * matches.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Skip the unitialized ones.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_find_by_zoneid(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone_t *zone;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone = zone_find_by_id(zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (zone == NULL)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = zone->zone_netstack;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh else
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_hold(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone_rele(zone);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Find a stack instance given the zoneid. Can only be called from
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * the create callback. See the comments in zone_find_by_id_nolock why
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * that limitation exists.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Increases the reference count if found; caller must do a
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If there is no exact match then assume the shared stack instance
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * matches.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Skip the unitialized ones.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_find_by_zoneid_nolock(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone_t *zone;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zone = zone_find_by_id_nolock(zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (zone == NULL)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = zone->zone_netstack;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh else
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_hold(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* zone_find_by_id_nolock does not have a hold on the zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Find a stack instance given the stackid with exact match?
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Increases the reference count if found; caller must do a
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Skip the unitialized ones.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_find_by_stackid(netstackid_t stackid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns->netstack_stackid == stackid &&
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_hold(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrillboolean_t
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrillnetstack_inuse_by_stackid(netstackid_t stackid)
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill{
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill netstack_t *ns;
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill boolean_t rval = B_FALSE;
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill mutex_enter(&netstack_g_lock);
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill if (ns->netstack_stackid == stackid) {
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill rval = B_TRUE;
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill break;
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill }
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill }
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill mutex_exit(&netstack_g_lock);
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill return (rval);
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill}
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_rele(netstack_t *ns)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t **nsp;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh boolean_t found;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh int refcnt, numzones;
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark int i;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_refcnt > 0);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_refcnt--;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * As we drop the lock additional netstack_rele()s can come in
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * and decrement the refcnt to zero and free the netstack_t.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Store pointers in local variables and if we were not the last
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * then don't reference the netstack_t after that.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh refcnt = ns->netstack_refcnt;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh numzones = ns->netstack_numzones;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__dec__ref, netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (refcnt == 0 && numzones == 0) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Time to call the destroy functions and free up
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * the structure
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_stack_inactive(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /* Make sure nothing increased the references */
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark ASSERT(ns->netstack_refcnt == 0);
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark ASSERT(ns->netstack_numzones == 0);
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Finally remove from list of netstacks */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh found = B_FALSE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (nsp = &netstack_head; *nsp != NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh nsp = &(*nsp)->netstack_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (*nsp == ns) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *nsp = ns->netstack_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_next = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh found = B_TRUE;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh break;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(found);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /* Make sure nothing increased the references */
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark ASSERT(ns->netstack_refcnt == 0);
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark ASSERT(ns->netstack_numzones == 0);
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_flags & NSF_CLOSING);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark nm_state_t *nms = &ns->netstack_m_state[i];
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_destroy(&nms->nms_cv);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark }
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark mutex_destroy(&ns->netstack_lock);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark cv_destroy(&ns->netstack_cv);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kmem_free(ns, sizeof (*ns));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_hold(netstack_t *ns)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_refcnt++;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(ns->netstack_refcnt > 0);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * To support kstat_create_netstack() using kstat_zone_add we need
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * to track both
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * - all zoneids that use the global/shared stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * - all kstats that have been added for the shared stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhkstat_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhkstat_create_netstack(char *ks_module, int ks_instance, char *ks_name,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstackid_t ks_netstackid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_t *ks;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ks_netstackid == GLOBAL_NETSTACKID) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ks = kstat_create_zone(ks_module, ks_instance, ks_name,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ks_class, ks_type, ks_ndata, ks_flags, GLOBAL_ZONEID);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ks != NULL)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_shared_kstat_add(ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh } else {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh zoneid_t zoneid = ks_netstackid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (kstat_create_zone(ks_module, ks_instance, ks_name,
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ks_class, ks_type, ks_ndata, ks_flags, zoneid));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhkstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ks_netstackid == GLOBAL_NETSTACKID) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_shared_kstat_remove(ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_delete(ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_shared_zone_add(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_zone_list *sz;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_kstat_list *sk;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz->sz_zoneid = zoneid;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Insert in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz->sz_next = netstack_shared_zones;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_shared_zones = sz;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_add for each existing shared stack kstat.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_add.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_zone_add(sk->sk_kstat, zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_shared_zone_remove(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_zone_list **szp, *sz;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_kstat_list *sk;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Find in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (szp = &netstack_shared_zones; *szp != NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh szp = &((*szp)->sz_next)) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((*szp)->sz_zoneid == zoneid) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz = *szp;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh break;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* We must find it */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(sz != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *szp = sz->sz_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz->sz_next = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_remove for each existing shared stack kstat.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_zone_remove(sk->sk_kstat, zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kmem_free(sz, sizeof (*sz));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_shared_kstat_add(kstat_t *ks)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_zone_list *sz;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_kstat_list *sk;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk->sk_kstat = ks;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Insert in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk->sk_next = netstack_shared_kstats;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_shared_kstats = sk;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_add for each existing shared stack zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_add.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_zone_add(ks, sz->sz_zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_shared_kstat_remove(kstat_t *ks)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_zone_list *sz;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_kstat_list **skp, *sk;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Find in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (skp = &netstack_shared_kstats; *skp != NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh skp = &((*skp)->sk_next)) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((*skp)->sk_kstat == ks) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk = *skp;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh break;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Must find it */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ASSERT(sk != NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *skp = sk->sk_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk->sk_next = NULL;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_remove for each existing shared stack kstat.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kstat_zone_remove(ks, sz->sz_zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh kmem_free(sk, sizeof (*sk));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If a zoneid is part of the shared zone, return true
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic boolean_t
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_find_shared_zoneid(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh struct shared_zone_list *sz;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (sz->sz_zoneid == zoneid) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (B_TRUE);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_shared_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (B_FALSE);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Hide the fact that zoneids and netstackids are allocated from
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * the same space in the current implementation.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * We currently do not check that the stackid/zoneids are valid, since there
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * is no need for that. But this should only be done for ids that are
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * valid.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhzoneid_t
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstackid_to_zoneid(netstackid_t stackid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (stackid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstackid_t
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhzoneid_to_netstackid(zoneid_t zoneid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (netstack_find_shared_zoneid(zoneid))
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (GLOBAL_ZONEID);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh else
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (zoneid);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedzoneid_t
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reednetstack_get_zoneid(netstack_t *ns)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (netstackid_to_zoneid(ns->netstack_stackid));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/*
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Simplistic support for walking all the handles.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Example usage:
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_handle_t nh;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_next_init(&nh);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * while ((ns = netstack_next(&nh)) != NULL) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * do something;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_next_fini(&nh);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_next_init(netstack_handle_t *handle)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *handle = 0;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhvoid
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_next_fini(netstack_handle_t *handle)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_t *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_next(netstack_handle_t *handle)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh{
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh int i, end;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh end = *handle;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Walk skipping *handle number of instances */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Look if there is a matching stack instance */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = netstack_head;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (i = 0; i < end; i++) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns == NULL)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh break;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = ns->netstack_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* skip those with that aren't really here */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh while (ns != NULL) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_enter(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh break;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&ns->netstack_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh end++;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = ns->netstack_next;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if (ns != NULL) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh *handle = end + 1;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh netstack_hold(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh }
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_exit(&netstack_g_lock);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh}