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