f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * See the License for the specific language governing permissions
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * and limitations under the License.
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 * CDDL HEADER END
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 * What we use so that the zones framework can tell us about new zones,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * which we use to create new stacks.
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 * Registry of netstacks with their create/shutdown/destory functions.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Global list of existing stacks. We use this when a new zone with
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * an exclusive IP instance is created.
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 * 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
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic kmutex_t netstack_shared_lock; /* protects the following two */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_zone_shutdown(zoneid_t zoneid, void *arg);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void netstack_zone_destroy(zoneid_t zoneid, void *arg);
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmarktypedef boolean_t applyfn_t(kmutex_t *, netstack_t *, int);
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 *,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL);
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 zone_key_create(&netstack_zone_key, netstack_zone_create,
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 * 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().
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Make instances created after this point in time run the create
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * callback.
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 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
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.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_netstacks(moduleid, netstack_apply_create);
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 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
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 * 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 if (nms->nms_flags & NSS_CREATE_INPROGRESS ||
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi if (ns_reg[moduleid].nr_shutdown != NULL && created &&
589efa9501f3347f21e60905a96ca39427169e10Robert Mustacchi ns_reg[moduleid].nr_destroy != NULL && created &&
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 apply_all_netstacks(moduleid, netstack_apply_shutdown);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_netstacks(moduleid, netstack_apply_destroy);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Clear the nms_flags so that we can handle this module
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * being loaded again.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Also remove the registered functions.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Lookup and/or allocate a netstack for this zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void *
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Look for the stack instance for the global */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Allocate even if it isn't needed; simplifies locking */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Look if there is a matching stack instance */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Should never find a pre-existing exclusive stack
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Record that we have a new shared stack zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Not found */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */
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
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 for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Stack instance being used by other zone */
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 ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Determine the set of stacks that exist before we drop the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Set NSS_SHUTDOWN_NEEDED for each of those.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (i = 0; i < NS_MAX; i++) {
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * Call the shutdown function for all registered modules for this
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * netstack.
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed apply_all_modules_reverse(ns, netstack_apply_shutdown);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */
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/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Stack instance being used by other zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Record that we a shared stack zone has gone away */
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * Set CLOSING so that netstack_find_by will not find it.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* No other thread can call zone_destroy for this stack */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Decrease refcnt to account for the one in netstack_zone_init()
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Called when the reference count drops to zero.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the destroy functions for each registered module.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
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 ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
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 * 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 for (i = 0; i < NS_MAX; i++) {
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * Call the shutdown and destroy functions for all registered modules
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark * for this netstack.
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 * 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.
7ddc9b1afd18f260b9fb78ec7732facd91769131Darren Reed apply_all_modules_reverse(ns, netstack_apply_shutdown);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark apply_all_modules_reverse(ns, netstack_apply_destroy);
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Tell any waiting netstack_register/netstack_unregister to proceed */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Apply a function to all netstacks for a particular moduleid.
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 * 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 * 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).
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkapply_all_netstacks(int moduleid, applyfn_t *applyfn)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Lock dropped - restart at head */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark } else if ((applyfn)(&netstack_g_lock, ns, moduleid)) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* Lock dropped - restart at head */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Apply a function to all moduleids for a particular netstack.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * Since the netstack linkage doesn't matter in this case we can
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * ignore whether the function drops the lock.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkapply_all_modules(netstack_t *ns, applyfn_t *applyfn)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark for (i = 0; i < NS_MAX; i++) {
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * We don't care whether the lock was dropped
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * since we are not iterating over netstack_head.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark/* Like the above but in reverse moduleid order */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkapply_all_modules_reverse(netstack_t *ns, applyfn_t *applyfn)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * We don't care whether the lock was dropped
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark * since we are not iterating over netstack_head.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the create function for the ns and moduleid if CREATE_NEEDED
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 * 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.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED
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 * 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.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh (ns_reg[moduleid].nr_shutdown)(stackid, netstack_module);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Call the destroy function for the ns and moduleid if DESTROY_NEEDED
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 * 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.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhnetstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid)
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 * 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.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkwait_for_zone_creator(netstack_t *ns, kmutex_t *lockp)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* First drop netstack_lock to preserve order */
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.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmarkwait_for_nms_inprogress(netstack_t *ns, nm_state_t *nms, kmutex_t *lockp)
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* First drop netstack_lock to preserve order */
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 return (ns);
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 /* Handle the case when cr_zone is NULL */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* For performance ... */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Find a stack instance given the zoneid.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Increases the reference count if found; caller must do a
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If there is no exact match then assume the shared stack instance
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * matches.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Skip the unitialized ones.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
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.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Increases the reference count if found; caller must do a
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele().
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If there is no exact match then assume the shared stack instance
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * matches.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Skip the unitialized ones.
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark /* zone_find_by_id_nolock does not have a hold on the zone */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
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 * Skip the unitialized ones.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrillnetstack_inuse_by_stackid(netstackid_t stackid)
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
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 * Time to call the destroy functions and free up
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * the structure
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /* Make sure nothing increased the references */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Finally remove from list of netstacks */
23f4867fdff96a11dd674de6259a5a0d0a13251cnordmark /* Make sure nothing increased the references */
bd41d0a82bd89bc81d63ae5dfc2ba4245f74ea6cnordmark for (i = 0; i < NS_MAX; i++) {
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
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 return (ks);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (kstat_create_zone(ks_module, ks_instance, ks_name,
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhkstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Insert in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_add for each existing shared stack kstat.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_add.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Find in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* We must find it */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_remove for each existing shared stack kstat.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Insert in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_add for each existing shared stack zone.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_add.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhstatic void
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Find in list */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Must find it */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Perform kstat_zone_remove for each existing shared stack kstat.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * If a zoneid is part of the shared zone, return true
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
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
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (netstackid_to_zoneid(ns->netstack_stackid));
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Simplistic support for walking all the handles.
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * Example usage:
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_handle_t nh;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_t *ns;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_next_init(&nh);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * while ((ns = netstack_next(&nh)) != NULL) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * do something;
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_rele(ns);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh * netstack_next_fini(&nh);
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh/* ARGSUSED */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Walk skipping *handle number of instances */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* Look if there is a matching stack instance */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for (i = 0; i < end; i++) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh /* skip those with that aren't really here */
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh return (ns);