17ddc9b1aSDarren Reed /* 27ddc9b1aSDarren Reed * CDDL HEADER START 37ddc9b1aSDarren Reed * 47ddc9b1aSDarren Reed * The contents of this file are subject to the terms of the 57ddc9b1aSDarren Reed * Common Development and Distribution License (the "License"). 67ddc9b1aSDarren Reed * You may not use this file except in compliance with the License. 77ddc9b1aSDarren Reed * 87ddc9b1aSDarren Reed * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97ddc9b1aSDarren Reed * or http://www.opensolaris.org/os/licensing. 107ddc9b1aSDarren Reed * See the License for the specific language governing permissions 117ddc9b1aSDarren Reed * and limitations under the License. 127ddc9b1aSDarren Reed * 137ddc9b1aSDarren Reed * When distributing Covered Code, include this CDDL HEADER in each 147ddc9b1aSDarren Reed * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157ddc9b1aSDarren Reed * If applicable, add the following below this CDDL HEADER, with the 167ddc9b1aSDarren Reed * fields enclosed by brackets "[]" replaced with your own identifying 177ddc9b1aSDarren Reed * information: Portions Copyright [yyyy] [name of copyright owner] 187ddc9b1aSDarren Reed * 197ddc9b1aSDarren Reed * CDDL HEADER END 207ddc9b1aSDarren Reed */ 217ddc9b1aSDarren Reed /* 227ddc9b1aSDarren Reed * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237ddc9b1aSDarren Reed * Use is subject to license terms. 247ddc9b1aSDarren Reed */ 257ddc9b1aSDarren Reed 267ddc9b1aSDarren Reed #include <sys/param.h> 277ddc9b1aSDarren Reed #include <sys/atomic.h> 287ddc9b1aSDarren Reed #include <sys/kmem.h> 297ddc9b1aSDarren Reed #include <sys/rwlock.h> 307ddc9b1aSDarren Reed #include <sys/errno.h> 317ddc9b1aSDarren Reed #include <sys/queue.h> 327ddc9b1aSDarren Reed #include <sys/sunddi.h> 337ddc9b1aSDarren Reed #include <inet/common.h> 347ddc9b1aSDarren Reed #include <inet/led.h> 357ddc9b1aSDarren Reed #include <inet/ip.h> 367ddc9b1aSDarren Reed #include <sys/neti.h> 377ddc9b1aSDarren Reed #include <sys/zone.h> 387ddc9b1aSDarren Reed #include <sys/sdt.h> 397ddc9b1aSDarren Reed 407ddc9b1aSDarren Reed 41*8ad74188SDarren Reed typedef boolean_t napplyfn_t(neti_stack_t *, void *); 427ddc9b1aSDarren Reed 437ddc9b1aSDarren Reed static void *neti_stack_init(netstackid_t stackid, netstack_t *ns); 447ddc9b1aSDarren Reed static void neti_stack_fini(netstackid_t stackid, void *arg); 457ddc9b1aSDarren Reed static net_instance_int_t *net_instance_int_create(net_instance_t *nin, 467ddc9b1aSDarren Reed net_instance_int_t *parent); 477ddc9b1aSDarren Reed static void neti_stack_shutdown(netstackid_t stackid, void *arg); 487ddc9b1aSDarren Reed static void net_instance_int_free(net_instance_int_t *nini); 497ddc9b1aSDarren Reed 50*8ad74188SDarren Reed static boolean_t neti_stack_apply_create(neti_stack_t *, void *); 51*8ad74188SDarren Reed static boolean_t neti_stack_apply_destroy(neti_stack_t *, void *); 52*8ad74188SDarren Reed static boolean_t neti_stack_apply_shutdown(neti_stack_t *, void *); 537ddc9b1aSDarren Reed static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *); 547ddc9b1aSDarren Reed static void neti_apply_all_stacks(void *, napplyfn_t *); 55*8ad74188SDarren Reed static boolean_t wait_for_nini_inprogress(neti_stack_t *, 567ddc9b1aSDarren Reed net_instance_int_t *, uint32_t); 577ddc9b1aSDarren Reed 587ddc9b1aSDarren Reed static nini_head_t neti_instance_list; 597ddc9b1aSDarren Reed static neti_stack_head_t neti_stack_list; 607ddc9b1aSDarren Reed static kmutex_t neti_stack_lock; 617ddc9b1aSDarren Reed 627ddc9b1aSDarren Reed void 637ddc9b1aSDarren Reed neti_init() 647ddc9b1aSDarren Reed { 657ddc9b1aSDarren Reed mutex_init(&neti_stack_lock, NULL, MUTEX_DRIVER, NULL); 667ddc9b1aSDarren Reed 677ddc9b1aSDarren Reed LIST_INIT(&neti_instance_list); 687ddc9b1aSDarren Reed LIST_INIT(&neti_stack_list); 697ddc9b1aSDarren Reed /* 707ddc9b1aSDarren Reed * We want to be informed each time a netstack is created or 717ddc9b1aSDarren Reed * destroyed in the kernel. 727ddc9b1aSDarren Reed */ 737ddc9b1aSDarren Reed netstack_register(NS_NETI, neti_stack_init, neti_stack_shutdown, 747ddc9b1aSDarren Reed neti_stack_fini); 757ddc9b1aSDarren Reed } 767ddc9b1aSDarren Reed 777ddc9b1aSDarren Reed void 787ddc9b1aSDarren Reed neti_fini() 797ddc9b1aSDarren Reed { 807ddc9b1aSDarren Reed ASSERT(LIST_EMPTY(&neti_instance_list)); 817ddc9b1aSDarren Reed ASSERT(LIST_EMPTY(&neti_stack_list)); 827ddc9b1aSDarren Reed 837ddc9b1aSDarren Reed netstack_unregister(NS_NETI); 847ddc9b1aSDarren Reed 857ddc9b1aSDarren Reed mutex_destroy(&neti_stack_lock); 867ddc9b1aSDarren Reed } 877ddc9b1aSDarren Reed 887ddc9b1aSDarren Reed /* 897ddc9b1aSDarren Reed * Initialize the neti stack instance. Because this is called out of the 907ddc9b1aSDarren Reed * netstack framework, it is not possible for it to be called twice with 917ddc9b1aSDarren Reed * the same values for (stackid,ns). The same also applies to the other 927ddc9b1aSDarren Reed * two functions used with netstack_register: neti_stack_shutdown and 937ddc9b1aSDarren Reed * neti_stack_fini. 947ddc9b1aSDarren Reed */ 957ddc9b1aSDarren Reed static void * 967ddc9b1aSDarren Reed neti_stack_init(netstackid_t stackid, netstack_t *ns) 977ddc9b1aSDarren Reed { 987ddc9b1aSDarren Reed net_instance_int_t *dup; 997ddc9b1aSDarren Reed net_instance_int_t *n; 1007ddc9b1aSDarren Reed neti_stack_t *nts; 1017ddc9b1aSDarren Reed 1027ddc9b1aSDarren Reed nts = kmem_zalloc(sizeof (*nts), KM_SLEEP); 1037ddc9b1aSDarren Reed LIST_INIT(&nts->nts_instances); 1047ddc9b1aSDarren Reed nts->nts_id = (netid_t)stackid; 1057ddc9b1aSDarren Reed nts->nts_stackid = stackid; 1067ddc9b1aSDarren Reed nts->nts_netstack = ns; 1077ddc9b1aSDarren Reed nts->nts_zoneid = netstackid_to_zoneid(stackid); 1087ddc9b1aSDarren Reed nts->nts_flags = NSF_ZONE_CREATE; 1097ddc9b1aSDarren Reed cv_init(&nts->nts_cv, NULL, CV_DRIVER, NULL); 1107ddc9b1aSDarren Reed mutex_init(&nts->nts_lock, NULL, MUTEX_DRIVER, NULL); 1117ddc9b1aSDarren Reed 1127ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 1137ddc9b1aSDarren Reed LIST_INSERT_HEAD(&neti_stack_list, nts, nts_next); 1147ddc9b1aSDarren Reed 1157ddc9b1aSDarren Reed LIST_FOREACH(n, &neti_instance_list, nini_next) { 1167ddc9b1aSDarren Reed /* 1177ddc9b1aSDarren Reed * This function returns with the NSS_CREATE_NEEDED flag 1187ddc9b1aSDarren Reed * set in "dup", so it is adequately prepared for the 1197ddc9b1aSDarren Reed * upcoming apply. 1207ddc9b1aSDarren Reed */ 1217ddc9b1aSDarren Reed dup = net_instance_int_create(n->nini_instance, n); 1227ddc9b1aSDarren Reed 1237ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 1247ddc9b1aSDarren Reed LIST_INSERT_HEAD(&nts->nts_instances, dup, nini_next); 1257ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 1267ddc9b1aSDarren Reed } 1277ddc9b1aSDarren Reed 1287ddc9b1aSDarren Reed neti_apply_all_instances(nts, neti_stack_apply_create); 1297ddc9b1aSDarren Reed 1307ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 1317ddc9b1aSDarren Reed nts->nts_flags &= ~NSF_ZONE_CREATE; 1327ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 1337ddc9b1aSDarren Reed 1347ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 1357ddc9b1aSDarren Reed 1367ddc9b1aSDarren Reed return (nts); 1377ddc9b1aSDarren Reed } 1387ddc9b1aSDarren Reed 1397ddc9b1aSDarren Reed /* 1407ddc9b1aSDarren Reed * Run the shutdown for all of the hooks. 1417ddc9b1aSDarren Reed */ 1427ddc9b1aSDarren Reed /*ARGSUSED*/ 1437ddc9b1aSDarren Reed static void 1447ddc9b1aSDarren Reed neti_stack_shutdown(netstackid_t stackid, void *arg) 1457ddc9b1aSDarren Reed { 1467ddc9b1aSDarren Reed neti_stack_t *nts = arg; 1477ddc9b1aSDarren Reed net_instance_int_t *n; 1487ddc9b1aSDarren Reed struct net_data *nd; 1497ddc9b1aSDarren Reed 1507ddc9b1aSDarren Reed ASSERT(nts != NULL); 1517ddc9b1aSDarren Reed 1527ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 1537ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 1547ddc9b1aSDarren Reed /* 1557ddc9b1aSDarren Reed * Walk through all of the protocol stacks and mark them as shutting 1567ddc9b1aSDarren Reed * down. 1577ddc9b1aSDarren Reed */ 1587ddc9b1aSDarren Reed LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) { 1597ddc9b1aSDarren Reed nd->netd_condemned = 1; 1607ddc9b1aSDarren Reed } 1617ddc9b1aSDarren Reed 1627ddc9b1aSDarren Reed /* 1637ddc9b1aSDarren Reed * Now proceed to see which callbacks are waiting to hear about the 1647ddc9b1aSDarren Reed * impending shutdown... 1657ddc9b1aSDarren Reed */ 1667ddc9b1aSDarren Reed LIST_FOREACH(n, &nts->nts_instances, nini_next) { 1677ddc9b1aSDarren Reed if (n->nini_instance->nin_shutdown == NULL) { 1687ddc9b1aSDarren Reed /* 1697ddc9b1aSDarren Reed * If there is no shutdown function registered, 1707ddc9b1aSDarren Reed * fake that we have completed it. 1717ddc9b1aSDarren Reed */ 1727ddc9b1aSDarren Reed n->nini_flags |= NSS_SHUTDOWN_COMPLETED; 1737ddc9b1aSDarren Reed continue; 1747ddc9b1aSDarren Reed } 1757ddc9b1aSDarren Reed 1767ddc9b1aSDarren Reed /* 1777ddc9b1aSDarren Reed * We need to ensure that we don't try and shutdown something 1787ddc9b1aSDarren Reed * that is already in the process of being shutdown or 1797ddc9b1aSDarren Reed * destroyed. If it is still being created, that's ok, the 1807ddc9b1aSDarren Reed * shtudown flag is added to the mix of things to do. 1817ddc9b1aSDarren Reed */ 1827ddc9b1aSDarren Reed if ((n->nini_flags & (NSS_DESTROY_ALL|NSS_SHUTDOWN_ALL)) == 0) 1837ddc9b1aSDarren Reed n->nini_flags |= NSS_SHUTDOWN_NEEDED; 1847ddc9b1aSDarren Reed } 1857ddc9b1aSDarren Reed nts->nts_flags |= NSF_ZONE_SHUTDOWN; 1867ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 1877ddc9b1aSDarren Reed 1887ddc9b1aSDarren Reed neti_apply_all_instances(nts, neti_stack_apply_shutdown); 1897ddc9b1aSDarren Reed 1907ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 1917ddc9b1aSDarren Reed 1927ddc9b1aSDarren Reed nts->nts_netstack = NULL; 193*8ad74188SDarren Reed nts->nts_flags &= ~NSF_ZONE_SHUTDOWN; 1947ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 1957ddc9b1aSDarren Reed 1967ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 1977ddc9b1aSDarren Reed ASSERT(nts != NULL); 1987ddc9b1aSDarren Reed } 1997ddc9b1aSDarren Reed 2007ddc9b1aSDarren Reed /* 2017ddc9b1aSDarren Reed * Free the neti stack instance. 2027ddc9b1aSDarren Reed * This function relies on the netstack framework only calling the _destroy 2037ddc9b1aSDarren Reed * callback once for each stackid. The netstack framework also provides us 2047ddc9b1aSDarren Reed * with assurance that nobody else will be doing any work (_create, _shutdown) 2057ddc9b1aSDarren Reed * on it, so there is no need to set and use flags to guard against 2067ddc9b1aSDarren Reed * simultaneous execution (ie. no need to set NSF_CLOSING.) 2077ddc9b1aSDarren Reed * What is required, however, is to make sure that we don't corrupt the 2087ddc9b1aSDarren Reed * list of neti_stack_t's for other code that walks it. 2097ddc9b1aSDarren Reed */ 2107ddc9b1aSDarren Reed /*ARGSUSED*/ 2117ddc9b1aSDarren Reed static void 2127ddc9b1aSDarren Reed neti_stack_fini(netstackid_t stackid, void *arg) 2137ddc9b1aSDarren Reed { 2147ddc9b1aSDarren Reed neti_stack_t *nts = arg; 2157ddc9b1aSDarren Reed net_instance_int_t *n; 2167ddc9b1aSDarren Reed struct net_data *nd; 2177ddc9b1aSDarren Reed 2187ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 219*8ad74188SDarren Reed mutex_enter(&nts->nts_lock); 220*8ad74188SDarren Reed 2217ddc9b1aSDarren Reed LIST_REMOVE(nts, nts_next); 2227ddc9b1aSDarren Reed 2237ddc9b1aSDarren Reed /* 2247ddc9b1aSDarren Reed * Walk through all of the protocol stacks and mark them as being 2257ddc9b1aSDarren Reed * destroyed. 2267ddc9b1aSDarren Reed */ 2277ddc9b1aSDarren Reed LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) { 2287ddc9b1aSDarren Reed nd->netd_condemned = 2; 2297ddc9b1aSDarren Reed } 2307ddc9b1aSDarren Reed 2317ddc9b1aSDarren Reed LIST_FOREACH(n, &nts->nts_instances, nini_next) { 2327ddc9b1aSDarren Reed ASSERT((n->nini_flags & NSS_SHUTDOWN_ALL) != 0); 2337ddc9b1aSDarren Reed if ((n->nini_flags & NSS_DESTROY_ALL) == 0) 2347ddc9b1aSDarren Reed n->nini_flags |= NSS_DESTROY_NEEDED; 2357ddc9b1aSDarren Reed } 2367ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 2377ddc9b1aSDarren Reed 2387ddc9b1aSDarren Reed neti_apply_all_instances(nts, neti_stack_apply_destroy); 2397ddc9b1aSDarren Reed 2407ddc9b1aSDarren Reed while (!LIST_EMPTY(&nts->nts_instances)) { 2417ddc9b1aSDarren Reed n = LIST_FIRST(&nts->nts_instances); 2427ddc9b1aSDarren Reed LIST_REMOVE(n, nini_next); 2437ddc9b1aSDarren Reed 2447ddc9b1aSDarren Reed net_instance_int_free(n); 2457ddc9b1aSDarren Reed } 246*8ad74188SDarren Reed mutex_exit(&neti_stack_lock); 2477ddc9b1aSDarren Reed 2487ddc9b1aSDarren Reed ASSERT(LIST_EMPTY(&nts->nts_netd_head)); 2497ddc9b1aSDarren Reed 2507ddc9b1aSDarren Reed mutex_destroy(&nts->nts_lock); 2517ddc9b1aSDarren Reed cv_destroy(&nts->nts_cv); 2527ddc9b1aSDarren Reed 2537ddc9b1aSDarren Reed kmem_free(nts, sizeof (*nts)); 2547ddc9b1aSDarren Reed } 2557ddc9b1aSDarren Reed 2567ddc9b1aSDarren Reed static net_instance_int_t * 2577ddc9b1aSDarren Reed net_instance_int_create(net_instance_t *nin, net_instance_int_t *parent) 2587ddc9b1aSDarren Reed { 2597ddc9b1aSDarren Reed net_instance_int_t *nini; 2607ddc9b1aSDarren Reed 2617ddc9b1aSDarren Reed nini = kmem_zalloc(sizeof (net_instance_int_t), KM_SLEEP); 2627ddc9b1aSDarren Reed nini->nini_instance = nin; 2637ddc9b1aSDarren Reed nini->nini_parent = parent; 2647ddc9b1aSDarren Reed if (parent != NULL) { 2657ddc9b1aSDarren Reed /* 2667ddc9b1aSDarren Reed * If the parent pointer is non-NULL then we take that as 2677ddc9b1aSDarren Reed * an indication that the net_instance_int_t is being 2687ddc9b1aSDarren Reed * created for an active instance and there will expect 2697ddc9b1aSDarren Reed * the create function to be called. In contrast, if 2707ddc9b1aSDarren Reed * parent is NULL then this code assumes the object is 2717ddc9b1aSDarren Reed * being prepared for insertion onto the master list of 2727ddc9b1aSDarren Reed * callbacks to be called when an instance is created, etc. 2737ddc9b1aSDarren Reed */ 2747ddc9b1aSDarren Reed parent->nini_ref++; 2757ddc9b1aSDarren Reed nini->nini_flags |= NSS_CREATE_NEEDED; 2767ddc9b1aSDarren Reed } 2777ddc9b1aSDarren Reed 2787ddc9b1aSDarren Reed cv_init(&nini->nini_cv, NULL, CV_DRIVER, NULL); 2797ddc9b1aSDarren Reed 2807ddc9b1aSDarren Reed return (nini); 2817ddc9b1aSDarren Reed } 2827ddc9b1aSDarren Reed 283*8ad74188SDarren Reed /* 284*8ad74188SDarren Reed * Free'ing of a net_instance_int_t is only to be done when we know nobody 285*8ad74188SDarren Reed * else has is using it. For both parents and clones, this is indicated by 286*8ad74188SDarren Reed * nini_ref being greater than 0, however, nini_ref is managed differently 287*8ad74188SDarren Reed * for its two uses. For parents, nini_ref is increased when a new clone is 288*8ad74188SDarren Reed * created and it is decremented here. For clones, nini_ref is adjusted by 289*8ad74188SDarren Reed * code elsewhere (e.g. in neti_stack_apply_*) and is not changed here. 290*8ad74188SDarren Reed */ 2917ddc9b1aSDarren Reed static void 2927ddc9b1aSDarren Reed net_instance_int_free(net_instance_int_t *nini) 2937ddc9b1aSDarren Reed { 294*8ad74188SDarren Reed /* 295*8ad74188SDarren Reed * This mutex guards the use of nini_ref. 296*8ad74188SDarren Reed */ 297*8ad74188SDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 2987ddc9b1aSDarren Reed 299*8ad74188SDarren Reed /* 300*8ad74188SDarren Reed * For 'parent' structures, nini_ref will drop to 0 when 301*8ad74188SDarren Reed * the last clone has been free'd... but for clones, it 302*8ad74188SDarren Reed * is possible for nini_ref to be non-zero if we get in 303*8ad74188SDarren Reed * here when all the locks have been given up to execute 304*8ad74188SDarren Reed * a callback or wait_for_nini_inprogress. In that case, 305*8ad74188SDarren Reed * we do not want to free the structure and just indicate 306*8ad74188SDarren Reed * that it is on the "doomed" list, thus we set the 307*8ad74188SDarren Reed * condemned flag. 308*8ad74188SDarren Reed */ 309*8ad74188SDarren Reed if (nini->nini_parent != NULL) { 310*8ad74188SDarren Reed if (nini->nini_ref > 0) 311*8ad74188SDarren Reed nini->nini_condemned = B_TRUE; 3127ddc9b1aSDarren Reed nini->nini_parent->nini_ref--; 313*8ad74188SDarren Reed if (nini->nini_parent->nini_ref == 0) 314*8ad74188SDarren Reed net_instance_int_free(nini->nini_parent); 315*8ad74188SDarren Reed nini->nini_parent = NULL; 316*8ad74188SDarren Reed } 3177ddc9b1aSDarren Reed 318*8ad74188SDarren Reed if (nini->nini_ref == 0) { 319*8ad74188SDarren Reed cv_destroy(&nini->nini_cv); 3207ddc9b1aSDarren Reed kmem_free(nini, sizeof (*nini)); 3217ddc9b1aSDarren Reed } 322*8ad74188SDarren Reed } 3237ddc9b1aSDarren Reed 3247ddc9b1aSDarren Reed net_instance_t * 3257ddc9b1aSDarren Reed net_instance_alloc(const int version) 3267ddc9b1aSDarren Reed { 3277ddc9b1aSDarren Reed net_instance_t *nin; 3287ddc9b1aSDarren Reed 3297ddc9b1aSDarren Reed if (version != NETINFO_VERSION) 3307ddc9b1aSDarren Reed return (NULL); 3317ddc9b1aSDarren Reed 3327ddc9b1aSDarren Reed nin = kmem_zalloc(sizeof (net_instance_t), KM_SLEEP); 3337ddc9b1aSDarren Reed nin->nin_version = version; 3347ddc9b1aSDarren Reed 3357ddc9b1aSDarren Reed return (nin); 3367ddc9b1aSDarren Reed } 3377ddc9b1aSDarren Reed 3387ddc9b1aSDarren Reed void 3397ddc9b1aSDarren Reed net_instance_free(net_instance_t *nin) 3407ddc9b1aSDarren Reed { 3417ddc9b1aSDarren Reed kmem_free(nin, sizeof (*nin)); 3427ddc9b1aSDarren Reed } 3437ddc9b1aSDarren Reed 3447ddc9b1aSDarren Reed int 3457ddc9b1aSDarren Reed net_instance_register(net_instance_t *nin) 3467ddc9b1aSDarren Reed { 3477ddc9b1aSDarren Reed net_instance_int_t *parent; 3487ddc9b1aSDarren Reed net_instance_int_t *tmp; 3497ddc9b1aSDarren Reed neti_stack_t *nts; 3507ddc9b1aSDarren Reed 3517ddc9b1aSDarren Reed ASSERT(nin->nin_name != NULL); 3527ddc9b1aSDarren Reed 3537ddc9b1aSDarren Reed if (nin->nin_create == NULL || nin->nin_destroy == NULL) 3547ddc9b1aSDarren Reed return (DDI_FAILURE); 3557ddc9b1aSDarren Reed 3567ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 3577ddc9b1aSDarren Reed /* 3587ddc9b1aSDarren Reed * Search for duplicate, either on the global list or on any 3597ddc9b1aSDarren Reed * of the known instances. 3607ddc9b1aSDarren Reed */ 3617ddc9b1aSDarren Reed LIST_FOREACH(tmp, &neti_instance_list, nini_next) { 3627ddc9b1aSDarren Reed if (strcmp(nin->nin_name, tmp->nini_instance->nin_name) == 0) { 3637ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 3647ddc9b1aSDarren Reed return (DDI_FAILURE); 3657ddc9b1aSDarren Reed } 3667ddc9b1aSDarren Reed } 3677ddc9b1aSDarren Reed 3687ddc9b1aSDarren Reed /* 3697ddc9b1aSDarren Reed * Now insert and activate. 3707ddc9b1aSDarren Reed */ 3717ddc9b1aSDarren Reed parent = net_instance_int_create(nin, NULL); 3727ddc9b1aSDarren Reed ASSERT(parent != NULL); 3737ddc9b1aSDarren Reed LIST_INSERT_HEAD(&neti_instance_list, parent, nini_next); 3747ddc9b1aSDarren Reed 3757ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 3767ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 3777ddc9b1aSDarren Reed /* 3787ddc9b1aSDarren Reed * If shutdown of the zone has begun then do not add a new 3797ddc9b1aSDarren Reed * instance of the object being registered. 3807ddc9b1aSDarren Reed */ 3817ddc9b1aSDarren Reed if ((nts->nts_flags & NSF_ZONE_SHUTDOWN) || 3827ddc9b1aSDarren Reed (nts->nts_netstack == NULL)) { 3837ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 3847ddc9b1aSDarren Reed continue; 3857ddc9b1aSDarren Reed } 386*8ad74188SDarren Reed 3877ddc9b1aSDarren Reed /* 3887ddc9b1aSDarren Reed * This function returns with the NSS_CREATE_NEEDED flag 3897ddc9b1aSDarren Reed * set in "dup", so it is adequately prepared for the 3907ddc9b1aSDarren Reed * upcoming apply. 3917ddc9b1aSDarren Reed */ 3927ddc9b1aSDarren Reed tmp = net_instance_int_create(nin, parent); 3937ddc9b1aSDarren Reed ASSERT(tmp != NULL); 3947ddc9b1aSDarren Reed LIST_INSERT_HEAD(&nts->nts_instances, tmp, nini_next); 3957ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 3967ddc9b1aSDarren Reed 3977ddc9b1aSDarren Reed } 3987ddc9b1aSDarren Reed 3997ddc9b1aSDarren Reed neti_apply_all_stacks(parent, neti_stack_apply_create); 4007ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 4017ddc9b1aSDarren Reed 4027ddc9b1aSDarren Reed return (DDI_SUCCESS); 4037ddc9b1aSDarren Reed } 4047ddc9b1aSDarren Reed 4057ddc9b1aSDarren Reed /* 4067ddc9b1aSDarren Reed * While net_instance_register() isn't likely to be racing against itself, 4077ddc9b1aSDarren Reed * net_instance_unregister() can be entered from various directions that 4087ddc9b1aSDarren Reed * can compete: shutdown of a zone, unloading of a module (and it calling 4097ddc9b1aSDarren Reed * _unregister() as part of that) and the module doing an _unregister() 4107ddc9b1aSDarren Reed * anyway. 4117ddc9b1aSDarren Reed */ 4127ddc9b1aSDarren Reed int 4137ddc9b1aSDarren Reed net_instance_unregister(net_instance_t *nin) 4147ddc9b1aSDarren Reed { 4157ddc9b1aSDarren Reed net_instance_int_t *parent; 4167ddc9b1aSDarren Reed net_instance_int_t *tmp; 4177ddc9b1aSDarren Reed neti_stack_t *nts; 4187ddc9b1aSDarren Reed 4197ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 4207ddc9b1aSDarren Reed 4217ddc9b1aSDarren Reed LIST_FOREACH(tmp, &neti_instance_list, nini_next) { 4227ddc9b1aSDarren Reed if (strcmp(tmp->nini_instance->nin_name, nin->nin_name) == 0) { 4237ddc9b1aSDarren Reed LIST_REMOVE(tmp, nini_next); 4247ddc9b1aSDarren Reed break; 4257ddc9b1aSDarren Reed } 4267ddc9b1aSDarren Reed } 4277ddc9b1aSDarren Reed 4287ddc9b1aSDarren Reed if (tmp == NULL) { 4297ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 4307ddc9b1aSDarren Reed return (DDI_FAILURE); 4317ddc9b1aSDarren Reed } 4327ddc9b1aSDarren Reed parent = tmp; 4337ddc9b1aSDarren Reed 4347ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 4357ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 4367ddc9b1aSDarren Reed LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { 4377ddc9b1aSDarren Reed if (tmp->nini_parent != parent) 4387ddc9b1aSDarren Reed continue; 4397ddc9b1aSDarren Reed /* 4407ddc9b1aSDarren Reed * Netstack difference: 4417ddc9b1aSDarren Reed * In netstack.c, there is a check for 4427ddc9b1aSDarren Reed * NSS_CREATE_COMPLETED before setting the other 4437ddc9b1aSDarren Reed * _NEEDED flags. If we consider that a list 4447ddc9b1aSDarren Reed * member must always have at least the _CREATE_NEEDED 4457ddc9b1aSDarren Reed * flag set and that wait_for_nini_inprogress will 4467ddc9b1aSDarren Reed * also wait for that flag to be cleared in both of 4477ddc9b1aSDarren Reed * the shutdown and destroy apply functions. 4487ddc9b1aSDarren Reed * 4497ddc9b1aSDarren Reed * It is possible to optimize out the case where 4507ddc9b1aSDarren Reed * all three _NEEDED flags are set to being able 4517ddc9b1aSDarren Reed * to pretend everything has been done and just 4527ddc9b1aSDarren Reed * set all three _COMPLETE flags. This makes a 4537ddc9b1aSDarren Reed * special case that we then need to consider in 4547ddc9b1aSDarren Reed * other locations, so for the sake of simplicity, 4557ddc9b1aSDarren Reed * we leave it as it is. 4567ddc9b1aSDarren Reed */ 4577ddc9b1aSDarren Reed if ((tmp->nini_flags & NSS_SHUTDOWN_ALL) == 0) 4587ddc9b1aSDarren Reed tmp->nini_flags |= NSS_SHUTDOWN_NEEDED; 4597ddc9b1aSDarren Reed if ((tmp->nini_flags & NSS_DESTROY_ALL) == 0) 4607ddc9b1aSDarren Reed tmp->nini_flags |= NSS_DESTROY_NEEDED; 461*8ad74188SDarren Reed break; 4627ddc9b1aSDarren Reed } 4637ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 4647ddc9b1aSDarren Reed } 4657ddc9b1aSDarren Reed 4667ddc9b1aSDarren Reed /* 4677ddc9b1aSDarren Reed * Each of these functions ensures that the requisite _COMPLETED 4687ddc9b1aSDarren Reed * flag is present before calling the apply function. So we are 4697ddc9b1aSDarren Reed * guaranteed to have NSS_CREATE_COMPLETED|NSS_SHUTDOWN_COMPLETED 4707ddc9b1aSDarren Reed * both set after the first call here and when the second completes, 4717ddc9b1aSDarren Reed * NSS_DESTROY_COMPLETED is also set. 4727ddc9b1aSDarren Reed */ 4737ddc9b1aSDarren Reed neti_apply_all_stacks(parent, neti_stack_apply_shutdown); 4747ddc9b1aSDarren Reed neti_apply_all_stacks(parent, neti_stack_apply_destroy); 4757ddc9b1aSDarren Reed 4767ddc9b1aSDarren Reed /* 4777ddc9b1aSDarren Reed * Remove the instance callback information from each stack. 4787ddc9b1aSDarren Reed */ 4797ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 4807ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 4817ddc9b1aSDarren Reed LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { 4827ddc9b1aSDarren Reed if ((tmp->nini_parent == parent) && 4837ddc9b1aSDarren Reed (tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) && 4847ddc9b1aSDarren Reed (tmp->nini_flags & NSS_DESTROY_COMPLETED)) { 4857ddc9b1aSDarren Reed /* 4867ddc9b1aSDarren Reed * There should only be one entry that has a 4877ddc9b1aSDarren Reed * matching nini_parent so there is no need to 4887ddc9b1aSDarren Reed * worry about continuing a loop where we are 4897ddc9b1aSDarren Reed * free'ing the structure holding the 'next' 4907ddc9b1aSDarren Reed * pointer. 4917ddc9b1aSDarren Reed */ 4927ddc9b1aSDarren Reed LIST_REMOVE(tmp, nini_next); 4937ddc9b1aSDarren Reed net_instance_int_free(tmp); 4947ddc9b1aSDarren Reed break; 4957ddc9b1aSDarren Reed } 4967ddc9b1aSDarren Reed } 4977ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 4987ddc9b1aSDarren Reed } 4997ddc9b1aSDarren Reed 500*8ad74188SDarren Reed mutex_exit(&neti_stack_lock); 5017ddc9b1aSDarren Reed 5027ddc9b1aSDarren Reed return (DDI_SUCCESS); 5037ddc9b1aSDarren Reed } 5047ddc9b1aSDarren Reed 5057ddc9b1aSDarren Reed static void 5067ddc9b1aSDarren Reed neti_apply_all_instances(neti_stack_t *nts, napplyfn_t *applyfn) 5077ddc9b1aSDarren Reed { 5087ddc9b1aSDarren Reed net_instance_int_t *n; 5097ddc9b1aSDarren Reed 5107ddc9b1aSDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 5117ddc9b1aSDarren Reed 5127ddc9b1aSDarren Reed n = LIST_FIRST(&nts->nts_instances); 5137ddc9b1aSDarren Reed while (n != NULL) { 514*8ad74188SDarren Reed if ((applyfn)(nts, n->nini_parent)) { 5157ddc9b1aSDarren Reed /* Lock dropped - restart at head */ 5167ddc9b1aSDarren Reed n = LIST_FIRST(&nts->nts_instances); 5177ddc9b1aSDarren Reed } else { 5187ddc9b1aSDarren Reed n = LIST_NEXT(n, nini_next); 5197ddc9b1aSDarren Reed } 5207ddc9b1aSDarren Reed } 5217ddc9b1aSDarren Reed } 5227ddc9b1aSDarren Reed 5237ddc9b1aSDarren Reed static void 5247ddc9b1aSDarren Reed neti_apply_all_stacks(void *parent, napplyfn_t *applyfn) 5257ddc9b1aSDarren Reed { 5267ddc9b1aSDarren Reed neti_stack_t *nts; 5277ddc9b1aSDarren Reed 5287ddc9b1aSDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 5297ddc9b1aSDarren Reed 5307ddc9b1aSDarren Reed nts = LIST_FIRST(&neti_stack_list); 5317ddc9b1aSDarren Reed while (nts != NULL) { 5327ddc9b1aSDarren Reed /* 5337ddc9b1aSDarren Reed * This function differs, in that it doesn't have a call to 5347ddc9b1aSDarren Reed * a "wait_creator" call, from the zsd/netstack code. The 5357ddc9b1aSDarren Reed * waiting is pushed into the apply functions which cause 5367ddc9b1aSDarren Reed * the waiting to be done in wait_for_nini_progress with 5377ddc9b1aSDarren Reed * the passing in of cmask. 5387ddc9b1aSDarren Reed */ 539*8ad74188SDarren Reed if ((applyfn)(nts, parent)) { 5407ddc9b1aSDarren Reed /* Lock dropped - restart at head */ 5417ddc9b1aSDarren Reed nts = LIST_FIRST(&neti_stack_list); 5427ddc9b1aSDarren Reed } else { 5437ddc9b1aSDarren Reed nts = LIST_NEXT(nts, nts_next); 5447ddc9b1aSDarren Reed } 5457ddc9b1aSDarren Reed } 5467ddc9b1aSDarren Reed } 5477ddc9b1aSDarren Reed 5487ddc9b1aSDarren Reed static boolean_t 549*8ad74188SDarren Reed neti_stack_apply_create(neti_stack_t *nts, void *parent) 5507ddc9b1aSDarren Reed { 5517ddc9b1aSDarren Reed void *result; 5527ddc9b1aSDarren Reed boolean_t dropped = B_FALSE; 5537ddc9b1aSDarren Reed net_instance_int_t *tmp; 5547ddc9b1aSDarren Reed net_instance_t *nin; 5557ddc9b1aSDarren Reed 5567ddc9b1aSDarren Reed ASSERT(parent != NULL); 557*8ad74188SDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 5587ddc9b1aSDarren Reed 5597ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 5607ddc9b1aSDarren Reed 5617ddc9b1aSDarren Reed LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { 5627ddc9b1aSDarren Reed if (tmp->nini_parent == parent) 5637ddc9b1aSDarren Reed break; 5647ddc9b1aSDarren Reed } 5657ddc9b1aSDarren Reed if (tmp == NULL) { 5667ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 5677ddc9b1aSDarren Reed return (dropped); 5687ddc9b1aSDarren Reed } 5697ddc9b1aSDarren Reed 570*8ad74188SDarren Reed tmp->nini_ref++; 571*8ad74188SDarren Reed 572*8ad74188SDarren Reed if (wait_for_nini_inprogress(nts, tmp, 0)) 5737ddc9b1aSDarren Reed dropped = B_TRUE; 5747ddc9b1aSDarren Reed 575*8ad74188SDarren Reed if ((tmp->nini_flags & NSS_CREATE_NEEDED) && !tmp->nini_condemned) { 5767ddc9b1aSDarren Reed nin = tmp->nini_instance; 5777ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_CREATE_NEEDED; 5787ddc9b1aSDarren Reed tmp->nini_flags |= NSS_CREATE_INPROGRESS; 5797ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__create__inprogress, 5807ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, tmp); 5817ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 582*8ad74188SDarren Reed mutex_exit(&neti_stack_lock); 5837ddc9b1aSDarren Reed dropped = B_TRUE; 5847ddc9b1aSDarren Reed 5857ddc9b1aSDarren Reed ASSERT(tmp->nini_created == NULL); 5867ddc9b1aSDarren Reed ASSERT(nin->nin_create != NULL); 5877ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__create__start, 5887ddc9b1aSDarren Reed netstackid_t, nts->nts_id, 5897ddc9b1aSDarren Reed neti_stack_t *, nts); 5907ddc9b1aSDarren Reed result = (nin->nin_create)(nts->nts_id); 5917ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__create__end, 5927ddc9b1aSDarren Reed void *, result, neti_stack_t *, nts); 5937ddc9b1aSDarren Reed 5947ddc9b1aSDarren Reed ASSERT(result != NULL); 595*8ad74188SDarren Reed mutex_enter(&neti_stack_lock); 5967ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 5977ddc9b1aSDarren Reed tmp->nini_created = result; 5987ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_CREATE_INPROGRESS; 5997ddc9b1aSDarren Reed tmp->nini_flags |= NSS_CREATE_COMPLETED; 6007ddc9b1aSDarren Reed cv_broadcast(&tmp->nini_cv); 6017ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__create__completed, 6027ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, tmp); 6037ddc9b1aSDarren Reed } 604*8ad74188SDarren Reed tmp->nini_ref--; 605*8ad74188SDarren Reed 606*8ad74188SDarren Reed if (tmp->nini_condemned) { 607*8ad74188SDarren Reed net_instance_int_free(tmp); 608*8ad74188SDarren Reed dropped = B_TRUE; 609*8ad74188SDarren Reed } 6107ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 6117ddc9b1aSDarren Reed return (dropped); 6127ddc9b1aSDarren Reed } 6137ddc9b1aSDarren Reed 6147ddc9b1aSDarren Reed 6157ddc9b1aSDarren Reed static boolean_t 616*8ad74188SDarren Reed neti_stack_apply_shutdown(neti_stack_t *nts, void *parent) 6177ddc9b1aSDarren Reed { 6187ddc9b1aSDarren Reed boolean_t dropped = B_FALSE; 6197ddc9b1aSDarren Reed net_instance_int_t *tmp; 6207ddc9b1aSDarren Reed net_instance_t *nin; 6217ddc9b1aSDarren Reed 6227ddc9b1aSDarren Reed ASSERT(parent != NULL); 623*8ad74188SDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 6247ddc9b1aSDarren Reed 6257ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 6267ddc9b1aSDarren Reed 6277ddc9b1aSDarren Reed LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { 6287ddc9b1aSDarren Reed if (tmp->nini_parent == parent) 6297ddc9b1aSDarren Reed break; 6307ddc9b1aSDarren Reed } 6317ddc9b1aSDarren Reed if (tmp == NULL) { 6327ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 6337ddc9b1aSDarren Reed return (dropped); 6347ddc9b1aSDarren Reed } 635*8ad74188SDarren Reed ASSERT((tmp->nini_flags & NSS_SHUTDOWN_ALL) != 0); 6367ddc9b1aSDarren Reed 637*8ad74188SDarren Reed tmp->nini_ref++; 638*8ad74188SDarren Reed 639*8ad74188SDarren Reed if (wait_for_nini_inprogress(nts, tmp, NSS_CREATE_NEEDED)) 6407ddc9b1aSDarren Reed dropped = B_TRUE; 6417ddc9b1aSDarren Reed 6427ddc9b1aSDarren Reed nin = tmp->nini_instance; 6437ddc9b1aSDarren Reed if (nin->nin_shutdown == NULL) { 6447ddc9b1aSDarren Reed /* 6457ddc9b1aSDarren Reed * If there is no shutdown function, fake having completed it. 6467ddc9b1aSDarren Reed */ 6477ddc9b1aSDarren Reed if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) { 6487ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED; 6497ddc9b1aSDarren Reed tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED; 6507ddc9b1aSDarren Reed } 651*8ad74188SDarren Reed tmp->nini_ref--; 652*8ad74188SDarren Reed 653*8ad74188SDarren Reed if (tmp->nini_condemned) { 654*8ad74188SDarren Reed net_instance_int_free(tmp); 655*8ad74188SDarren Reed dropped = B_TRUE; 656*8ad74188SDarren Reed } 6577ddc9b1aSDarren Reed 6587ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 6597ddc9b1aSDarren Reed return (dropped); 6607ddc9b1aSDarren Reed } 6617ddc9b1aSDarren Reed 662*8ad74188SDarren Reed if ((tmp->nini_flags & NSS_SHUTDOWN_NEEDED) && !tmp->nini_condemned) { 6637ddc9b1aSDarren Reed ASSERT((tmp->nini_flags & NSS_CREATE_COMPLETED) != 0); 6647ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED; 6657ddc9b1aSDarren Reed tmp->nini_flags |= NSS_SHUTDOWN_INPROGRESS; 6667ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__shutdown__inprogress, 6677ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, tmp); 6687ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 669*8ad74188SDarren Reed mutex_exit(&neti_stack_lock); 6707ddc9b1aSDarren Reed dropped = B_TRUE; 6717ddc9b1aSDarren Reed 6727ddc9b1aSDarren Reed ASSERT(nin->nin_shutdown != NULL); 6737ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__shutdown__start, 6747ddc9b1aSDarren Reed netstackid_t, nts->nts_id, 6757ddc9b1aSDarren Reed neti_stack_t *, nts); 6767ddc9b1aSDarren Reed (nin->nin_shutdown)(nts->nts_id, tmp->nini_created); 6777ddc9b1aSDarren Reed DTRACE_PROBE1(neti__stack__shutdown__end, 6787ddc9b1aSDarren Reed neti_stack_t *, nts); 6797ddc9b1aSDarren Reed 680*8ad74188SDarren Reed mutex_enter(&neti_stack_lock); 6817ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 6827ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_SHUTDOWN_INPROGRESS; 6837ddc9b1aSDarren Reed tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED; 6847ddc9b1aSDarren Reed cv_broadcast(&tmp->nini_cv); 6857ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__shutdown__completed, 6867ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, tmp); 6877ddc9b1aSDarren Reed } 6887ddc9b1aSDarren Reed ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0); 689*8ad74188SDarren Reed tmp->nini_ref--; 690*8ad74188SDarren Reed 691*8ad74188SDarren Reed if (tmp->nini_condemned) { 692*8ad74188SDarren Reed net_instance_int_free(tmp); 693*8ad74188SDarren Reed dropped = B_TRUE; 694*8ad74188SDarren Reed } 6957ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 6967ddc9b1aSDarren Reed return (dropped); 6977ddc9b1aSDarren Reed } 6987ddc9b1aSDarren Reed 6997ddc9b1aSDarren Reed static boolean_t 700*8ad74188SDarren Reed neti_stack_apply_destroy(neti_stack_t *nts, void *parent) 7017ddc9b1aSDarren Reed { 7027ddc9b1aSDarren Reed boolean_t dropped = B_FALSE; 7037ddc9b1aSDarren Reed net_instance_int_t *tmp; 7047ddc9b1aSDarren Reed net_instance_t *nin; 7057ddc9b1aSDarren Reed 7067ddc9b1aSDarren Reed ASSERT(parent != NULL); 707*8ad74188SDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 7087ddc9b1aSDarren Reed 7097ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 7107ddc9b1aSDarren Reed 7117ddc9b1aSDarren Reed LIST_FOREACH(tmp, &nts->nts_instances, nini_next) { 7127ddc9b1aSDarren Reed if (tmp->nini_parent == parent) 7137ddc9b1aSDarren Reed break; 7147ddc9b1aSDarren Reed } 7157ddc9b1aSDarren Reed if (tmp == NULL) { 7167ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 7177ddc9b1aSDarren Reed return (dropped); 7187ddc9b1aSDarren Reed } 7197ddc9b1aSDarren Reed 720*8ad74188SDarren Reed tmp->nini_ref++; 721*8ad74188SDarren Reed 7227ddc9b1aSDarren Reed /* 7237ddc9b1aSDarren Reed * We pause here so that when we continue we know that we're the 7247ddc9b1aSDarren Reed * only one doing anything active with this node. 7257ddc9b1aSDarren Reed */ 726*8ad74188SDarren Reed if (wait_for_nini_inprogress(nts, tmp, 7277ddc9b1aSDarren Reed NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED)) 7287ddc9b1aSDarren Reed dropped = B_TRUE; 7297ddc9b1aSDarren Reed 730*8ad74188SDarren Reed if ((tmp->nini_flags & NSS_DESTROY_NEEDED) && !tmp->nini_condemned) { 7317ddc9b1aSDarren Reed ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0); 7327ddc9b1aSDarren Reed nin = tmp->nini_instance; 7337ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_DESTROY_NEEDED; 7347ddc9b1aSDarren Reed tmp->nini_flags |= NSS_DESTROY_INPROGRESS; 7357ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__destroy__inprogress, 7367ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, tmp); 7377ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 738*8ad74188SDarren Reed mutex_exit(&neti_stack_lock); 7397ddc9b1aSDarren Reed dropped = B_TRUE; 7407ddc9b1aSDarren Reed 7417ddc9b1aSDarren Reed ASSERT(nin->nin_destroy != NULL); 7427ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__destroy__start, 7437ddc9b1aSDarren Reed netstackid_t, nts->nts_id, 7447ddc9b1aSDarren Reed neti_stack_t *, nts); 7457ddc9b1aSDarren Reed (nin->nin_destroy)(nts->nts_id, tmp->nini_created); 7467ddc9b1aSDarren Reed DTRACE_PROBE1(neti__stack__destroy__end, 7477ddc9b1aSDarren Reed neti_stack_t *, nts); 7487ddc9b1aSDarren Reed 749*8ad74188SDarren Reed mutex_enter(&neti_stack_lock); 7507ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 7517ddc9b1aSDarren Reed tmp->nini_flags &= ~NSS_DESTROY_INPROGRESS; 7527ddc9b1aSDarren Reed tmp->nini_flags |= NSS_DESTROY_COMPLETED; 7537ddc9b1aSDarren Reed cv_broadcast(&tmp->nini_cv); 7547ddc9b1aSDarren Reed DTRACE_PROBE2(neti__stack__destroy__completed, 7557ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, tmp); 7567ddc9b1aSDarren Reed } 757*8ad74188SDarren Reed tmp->nini_ref--; 758*8ad74188SDarren Reed 759*8ad74188SDarren Reed if (tmp->nini_condemned) { 760*8ad74188SDarren Reed net_instance_int_free(tmp); 761*8ad74188SDarren Reed dropped = B_TRUE; 762*8ad74188SDarren Reed } 7637ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 7647ddc9b1aSDarren Reed return (dropped); 7657ddc9b1aSDarren Reed } 7667ddc9b1aSDarren Reed 7677ddc9b1aSDarren Reed static boolean_t 768*8ad74188SDarren Reed wait_for_nini_inprogress(neti_stack_t *nts, net_instance_int_t *nini, 769*8ad74188SDarren Reed uint32_t cmask) 7707ddc9b1aSDarren Reed { 7717ddc9b1aSDarren Reed boolean_t dropped = B_FALSE; 7727ddc9b1aSDarren Reed 773*8ad74188SDarren Reed ASSERT(mutex_owned(&neti_stack_lock)); 7747ddc9b1aSDarren Reed 7757ddc9b1aSDarren Reed while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) { 776*8ad74188SDarren Reed DTRACE_PROBE2(neti__wait__nini__inprogress, 7777ddc9b1aSDarren Reed neti_stack_t *, nts, net_instance_int_t *, nini); 7787ddc9b1aSDarren Reed dropped = B_TRUE; 779*8ad74188SDarren Reed mutex_exit(&neti_stack_lock); 7807ddc9b1aSDarren Reed 7817ddc9b1aSDarren Reed cv_wait(&nini->nini_cv, &nts->nts_lock); 7827ddc9b1aSDarren Reed 7837ddc9b1aSDarren Reed /* First drop netstack_lock to preserve order */ 7847ddc9b1aSDarren Reed mutex_exit(&nts->nts_lock); 785*8ad74188SDarren Reed DTRACE_PROBE2(wait__nini__inprogress__pause, 786*8ad74188SDarren Reed neti_stack_t *, nts, net_instance_int_t *, nini); 787*8ad74188SDarren Reed mutex_enter(&neti_stack_lock); 7887ddc9b1aSDarren Reed mutex_enter(&nts->nts_lock); 7897ddc9b1aSDarren Reed } 790*8ad74188SDarren Reed DTRACE_PROBE2(neti__wait__nini__inprogress__complete, 791*8ad74188SDarren Reed neti_stack_t *, nts, net_instance_int_t *, nini); 7927ddc9b1aSDarren Reed return (dropped); 7937ddc9b1aSDarren Reed } 7947ddc9b1aSDarren Reed 7957ddc9b1aSDarren Reed /* ======================================================================= */ 7967ddc9b1aSDarren Reed 7977ddc9b1aSDarren Reed netid_t 7987ddc9b1aSDarren Reed net_zoneidtonetid(zoneid_t zoneid) 7997ddc9b1aSDarren Reed { 8007ddc9b1aSDarren Reed 8017ddc9b1aSDarren Reed neti_stack_t *nts; 8027ddc9b1aSDarren Reed 8037ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 8047ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 8057ddc9b1aSDarren Reed if (nts->nts_zoneid == zoneid) { 8067ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8077ddc9b1aSDarren Reed return (nts->nts_id); 8087ddc9b1aSDarren Reed } 8097ddc9b1aSDarren Reed } 8107ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8117ddc9b1aSDarren Reed 8127ddc9b1aSDarren Reed return (-1); 8137ddc9b1aSDarren Reed } 8147ddc9b1aSDarren Reed 8157ddc9b1aSDarren Reed zoneid_t 8167ddc9b1aSDarren Reed net_getzoneidbynetid(netid_t netid) 8177ddc9b1aSDarren Reed { 8187ddc9b1aSDarren Reed neti_stack_t *nts; 8197ddc9b1aSDarren Reed 8207ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 8217ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 8227ddc9b1aSDarren Reed if (nts->nts_id == netid) { 8237ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8247ddc9b1aSDarren Reed return (nts->nts_zoneid); 8257ddc9b1aSDarren Reed } 8267ddc9b1aSDarren Reed } 8277ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8287ddc9b1aSDarren Reed 8297ddc9b1aSDarren Reed return (-1); 8307ddc9b1aSDarren Reed } 8317ddc9b1aSDarren Reed 8327ddc9b1aSDarren Reed netstackid_t 8337ddc9b1aSDarren Reed net_getnetstackidbynetid(netid_t netid) 8347ddc9b1aSDarren Reed { 8357ddc9b1aSDarren Reed neti_stack_t *nts; 8367ddc9b1aSDarren Reed 8377ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 8387ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 8397ddc9b1aSDarren Reed if (nts->nts_id == netid) { 8407ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8417ddc9b1aSDarren Reed return (nts->nts_stackid); 8427ddc9b1aSDarren Reed } 8437ddc9b1aSDarren Reed } 8447ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8457ddc9b1aSDarren Reed 8467ddc9b1aSDarren Reed return (-1); 8477ddc9b1aSDarren Reed } 8487ddc9b1aSDarren Reed 8497ddc9b1aSDarren Reed netid_t 8507ddc9b1aSDarren Reed net_getnetidbynetstackid(netstackid_t netstackid) 8517ddc9b1aSDarren Reed { 8527ddc9b1aSDarren Reed neti_stack_t *nts; 8537ddc9b1aSDarren Reed 8547ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 8557ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 8567ddc9b1aSDarren Reed if (nts->nts_stackid == netstackid) { 8577ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8587ddc9b1aSDarren Reed return (nts->nts_id); 8597ddc9b1aSDarren Reed } 8607ddc9b1aSDarren Reed } 8617ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8627ddc9b1aSDarren Reed 8637ddc9b1aSDarren Reed return (-1); 8647ddc9b1aSDarren Reed } 8657ddc9b1aSDarren Reed 8667ddc9b1aSDarren Reed neti_stack_t * 8677ddc9b1aSDarren Reed net_getnetistackbyid(netid_t netid) 8687ddc9b1aSDarren Reed { 8697ddc9b1aSDarren Reed neti_stack_t *nts; 8707ddc9b1aSDarren Reed 8717ddc9b1aSDarren Reed mutex_enter(&neti_stack_lock); 8727ddc9b1aSDarren Reed LIST_FOREACH(nts, &neti_stack_list, nts_next) { 8737ddc9b1aSDarren Reed if (nts->nts_id == netid) { 8747ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8757ddc9b1aSDarren Reed return (nts); 8767ddc9b1aSDarren Reed } 8777ddc9b1aSDarren Reed } 8787ddc9b1aSDarren Reed mutex_exit(&neti_stack_lock); 8797ddc9b1aSDarren Reed 8807ddc9b1aSDarren Reed return (NULL); 8817ddc9b1aSDarren Reed } 8827ddc9b1aSDarren Reed 8837ddc9b1aSDarren Reed int 8847ddc9b1aSDarren Reed net_instance_notify_register(netid_t netid, hook_notify_fn_t callback, 8857ddc9b1aSDarren Reed void *arg) 8867ddc9b1aSDarren Reed { 8877ddc9b1aSDarren Reed 8887ddc9b1aSDarren Reed return (hook_stack_notify_register(net_getnetstackidbynetid(netid), 8897ddc9b1aSDarren Reed callback, arg)); 8907ddc9b1aSDarren Reed } 8917ddc9b1aSDarren Reed 8927ddc9b1aSDarren Reed int 8937ddc9b1aSDarren Reed net_instance_notify_unregister(netid_t netid, hook_notify_fn_t callback) 8947ddc9b1aSDarren Reed { 8957ddc9b1aSDarren Reed 8967ddc9b1aSDarren Reed return (hook_stack_notify_unregister(net_getnetstackidbynetid(netid), 8977ddc9b1aSDarren Reed callback)); 8987ddc9b1aSDarren Reed } 899