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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Datalink management routines. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/door.h> 34 #include <sys/zone.h> 35 #include <sys/modctl.h> 36 #include <sys/file.h> 37 #include <sys/modhash.h> 38 #include <sys/kstat.h> 39 #include <sys/vnode.h> 40 #include <sys/cmn_err.h> 41 #include <sys/vlan.h> 42 #include <sys/softmac.h> 43 #include <sys/dls.h> 44 #include <sys/dls_impl.h> 45 46 static kmem_cache_t *i_dls_devnet_cachep; 47 static kmutex_t i_dls_mgmt_lock; 48 static krwlock_t i_dls_devnet_lock; 49 static mod_hash_t *i_dls_devnet_id_hash; 50 static mod_hash_t *i_dls_devnet_hash; 51 52 boolean_t devnet_need_rebuild; 53 54 #define VLAN_HASHSZ 67 /* prime */ 55 56 /* Upcall door handle */ 57 static door_handle_t dls_mgmt_dh = NULL; 58 59 /* 60 * This structure is used to keep the <linkid, macname, vid> mapping. 61 */ 62 typedef struct dls_devnet_s { 63 datalink_id_t dd_vlanid; 64 datalink_id_t dd_linkid; 65 char dd_mac[MAXNAMELEN]; 66 uint16_t dd_vid; 67 char dd_spa[MAXSPALEN]; 68 boolean_t dd_explicit; 69 kstat_t *dd_ksp; 70 71 uint32_t dd_ref; 72 73 kmutex_t dd_mutex; 74 kcondvar_t dd_cv; 75 uint32_t dd_tref; 76 77 kmutex_t dd_zid_mutex; 78 zoneid_t dd_zid; 79 80 boolean_t dd_prop_loaded; 81 taskqid_t dd_prop_taskid; 82 } dls_devnet_t; 83 84 85 /*ARGSUSED*/ 86 static int 87 i_dls_devnet_constructor(void *buf, void *arg, int kmflag) 88 { 89 dls_devnet_t *ddp = buf; 90 91 bzero(buf, sizeof (dls_devnet_t)); 92 mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL); 93 mutex_init(&ddp->dd_zid_mutex, NULL, MUTEX_DEFAULT, NULL); 94 cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL); 95 return (0); 96 } 97 98 /*ARGSUSED*/ 99 static void 100 i_dls_devnet_destructor(void *buf, void *arg) 101 { 102 dls_devnet_t *ddp = buf; 103 104 ASSERT(ddp->dd_ksp == NULL); 105 ASSERT(ddp->dd_ref == 0); 106 ASSERT(ddp->dd_tref == 0); 107 ASSERT(!ddp->dd_explicit); 108 mutex_destroy(&ddp->dd_mutex); 109 mutex_destroy(&ddp->dd_zid_mutex); 110 cv_destroy(&ddp->dd_cv); 111 } 112 113 /* 114 * Module initialization and finalization functions. 115 */ 116 void 117 dls_mgmt_init(void) 118 { 119 mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL); 120 rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL); 121 122 /* 123 * Create a kmem_cache of dls_devnet_t structures. 124 */ 125 i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache", 126 sizeof (dls_devnet_t), 0, i_dls_devnet_constructor, 127 i_dls_devnet_destructor, NULL, NULL, NULL, 0); 128 ASSERT(i_dls_devnet_cachep != NULL); 129 130 /* 131 * Create a hash table, keyed by dd_vlanid, of dls_devnet_t. 132 */ 133 i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash", 134 VLAN_HASHSZ, mod_hash_null_valdtor); 135 136 /* 137 * Create a hash table, keyed by dd_spa. 138 */ 139 i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash", 140 VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 141 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 142 143 devnet_need_rebuild = B_FALSE; 144 } 145 146 void 147 dls_mgmt_fini(void) 148 { 149 mod_hash_destroy_hash(i_dls_devnet_hash); 150 mod_hash_destroy_hash(i_dls_devnet_id_hash); 151 kmem_cache_destroy(i_dls_devnet_cachep); 152 rw_destroy(&i_dls_devnet_lock); 153 mutex_destroy(&i_dls_mgmt_lock); 154 } 155 156 int 157 dls_mgmt_door_set(boolean_t start) 158 { 159 int err; 160 161 /* handle daemon restart */ 162 mutex_enter(&i_dls_mgmt_lock); 163 if (dls_mgmt_dh != NULL) { 164 door_ki_rele(dls_mgmt_dh); 165 dls_mgmt_dh = NULL; 166 } 167 168 if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) { 169 mutex_exit(&i_dls_mgmt_lock); 170 return (err); 171 } 172 173 mutex_exit(&i_dls_mgmt_lock); 174 175 /* 176 * Create and associate <link name, linkid> mapping for network devices 177 * which are already attached before the daemon is started. 178 */ 179 if (start) 180 softmac_recreate(); 181 return (0); 182 } 183 184 static boolean_t 185 i_dls_mgmt_door_revoked(door_handle_t dh) 186 { 187 struct door_info info; 188 extern int sys_shutdown; 189 190 ASSERT(dh != NULL); 191 192 if (sys_shutdown) { 193 cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n"); 194 return (B_TRUE); 195 } 196 197 if (door_ki_info(dh, &info) != 0) 198 return (B_TRUE); 199 200 return ((info.di_attributes & DOOR_REVOKED) != 0); 201 } 202 203 /* 204 * Upcall to the datalink management daemon (dlmgmtd). 205 */ 206 static int 207 i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize) 208 { 209 door_arg_t darg, save_arg; 210 door_handle_t dh; 211 int err; 212 int retry = 0; 213 214 #define MAXRETRYNUM 3 215 216 ASSERT(arg); 217 darg.data_ptr = arg; 218 darg.data_size = asize; 219 darg.desc_ptr = NULL; 220 darg.desc_num = 0; 221 darg.rbuf = rbuf; 222 darg.rsize = rsize; 223 save_arg = darg; 224 225 retry: 226 mutex_enter(&i_dls_mgmt_lock); 227 dh = dls_mgmt_dh; 228 if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) { 229 mutex_exit(&i_dls_mgmt_lock); 230 return (EBADF); 231 } 232 door_ki_hold(dh); 233 mutex_exit(&i_dls_mgmt_lock); 234 235 for (;;) { 236 retry++; 237 if ((err = door_ki_upcall_limited(dh, &darg, kcred, 238 SIZE_MAX, 0)) == 0) 239 break; 240 241 /* 242 * handle door call errors 243 */ 244 darg = save_arg; 245 switch (err) { 246 case EINTR: 247 /* 248 * If the operation which caused this door upcall gets 249 * interrupted, return directly. 250 */ 251 goto done; 252 case EAGAIN: 253 /* 254 * Repeat upcall if the maximum attempt limit has not 255 * been reached. 256 */ 257 if (retry < MAXRETRYNUM) { 258 delay(2 * hz); 259 break; 260 } 261 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err); 262 goto done; 263 default: 264 /* A fatal door error */ 265 if (i_dls_mgmt_door_revoked(dh)) { 266 cmn_err(CE_NOTE, 267 "dls: dlmgmtd door service revoked\n"); 268 269 if (retry < MAXRETRYNUM) { 270 door_ki_rele(dh); 271 goto retry; 272 } 273 } 274 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err); 275 goto done; 276 } 277 } 278 279 if (darg.rbuf != rbuf) { 280 /* 281 * The size of the input rbuf was not big enough, so the 282 * upcall allocated the rbuf itself. If this happens, assume 283 * that this was an invalid door call request. 284 */ 285 kmem_free(darg.rbuf, darg.rsize); 286 err = ENOSPC; 287 goto done; 288 } 289 290 if (darg.rsize != rsize) { 291 err = EINVAL; 292 goto done; 293 } 294 295 err = ((dlmgmt_retval_t *)rbuf)->lr_err; 296 297 done: 298 door_ki_rele(dh); 299 return (err); 300 } 301 302 /* 303 * Request the datalink management daemon to create a link with the attributes 304 * below. Upon success, zero is returned and linkidp contains the linkid for 305 * the new link; otherwise, an errno is returned. 306 * 307 * - dev physical dev_t. required for all physical links, 308 * including GLDv3 links. It will be used to force the 309 * attachment of a physical device, hence the 310 * registration of its mac 311 * - class datalink class 312 * - media type media type; DL_OTHER means unknown 313 * - vid VLAN ID (for VLANs) 314 * - persist whether to persist the datalink 315 */ 316 int 317 dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class, 318 uint32_t media, boolean_t persist, datalink_id_t *linkidp) 319 { 320 dlmgmt_upcall_arg_create_t create; 321 dlmgmt_create_retval_t retval; 322 int err; 323 324 create.ld_cmd = DLMGMT_CMD_DLS_CREATE; 325 create.ld_class = class; 326 create.ld_media = media; 327 create.ld_phymaj = getmajor(dev); 328 create.ld_phyinst = getminor(dev); 329 create.ld_persist = persist; 330 if (strlcpy(create.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN) 331 return (EINVAL); 332 333 if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval, 334 sizeof (retval))) == 0) { 335 *linkidp = retval.lr_linkid; 336 } 337 return (err); 338 } 339 340 /* 341 * Request the datalink management daemon to destroy the specified link. 342 * Returns zero upon success, or an errno upon failure. 343 */ 344 int 345 dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist) 346 { 347 dlmgmt_upcall_arg_destroy_t destroy; 348 dlmgmt_destroy_retval_t retval; 349 350 destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY; 351 destroy.ld_linkid = linkid; 352 destroy.ld_persist = persist; 353 354 return (i_dls_mgmt_upcall(&destroy, sizeof (destroy), 355 &retval, sizeof (retval))); 356 } 357 358 /* 359 * Request the datalink management daemon to verify/update the information 360 * for a physical link. Upon success, get its linkid. 361 * 362 * - media type media type 363 * - novanity whether this physical datalink supports vanity naming. 364 * physical links that do not use the GLDv3 MAC plugin 365 * cannot suport vanity naming 366 * 367 * This function could fail with ENOENT or EEXIST. Two cases return EEXIST: 368 * 369 * 1. A link with devname already exists, but the media type does not match. 370 * In this case, mediap will bee set to the media type of the existing link. 371 * 2. A link with devname already exists, but its link name does not match 372 * the device name, although this link does not support vanity naming. 373 */ 374 int 375 dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity, 376 uint32_t *mediap, datalink_id_t *linkidp) 377 { 378 dlmgmt_upcall_arg_update_t update; 379 dlmgmt_update_retval_t retval; 380 int err; 381 382 update.ld_cmd = DLMGMT_CMD_DLS_UPDATE; 383 384 if (strlcpy(update.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN) 385 return (EINVAL); 386 387 update.ld_media = media; 388 update.ld_novanity = novanity; 389 390 if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval, 391 sizeof (retval))) == EEXIST) { 392 *linkidp = retval.lr_linkid; 393 *mediap = retval.lr_media; 394 } else if (err == 0) { 395 *linkidp = retval.lr_linkid; 396 } 397 398 return (err); 399 } 400 401 /* 402 * Request the datalink management daemon to get the information for a link. 403 * Returns zero upon success, or an errno upon failure. 404 * 405 * Only fills in information for argument pointers that are non-NULL. 406 * Note that the link argument is expected to be MAXLINKNAMELEN bytes. 407 */ 408 int 409 dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link, 410 datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp) 411 { 412 dlmgmt_door_getname_t getname; 413 dlmgmt_getname_retval_t retval; 414 int err, len; 415 416 getname.ld_cmd = DLMGMT_CMD_GETNAME; 417 getname.ld_linkid = linkid; 418 419 if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval, 420 sizeof (retval))) != 0) { 421 return (err); 422 } 423 424 len = strlen(retval.lr_link); 425 if (len <= 1 || len >= MAXLINKNAMELEN) 426 return (EINVAL); 427 428 if (link != NULL) 429 (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN); 430 if (classp != NULL) 431 *classp = retval.lr_class; 432 if (mediap != NULL) 433 *mediap = retval.lr_media; 434 if (flagsp != NULL) 435 *flagsp = retval.lr_flags; 436 return (0); 437 } 438 439 /* 440 * Request the datalink management daemon to get the linkid for a link. 441 * Returns a non-zero error code on failure. The linkid argument is only 442 * set on success (when zero is returned.) 443 */ 444 int 445 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid) 446 { 447 dlmgmt_door_getlinkid_t getlinkid; 448 dlmgmt_getlinkid_retval_t retval; 449 int err; 450 451 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 452 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 453 454 if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval, 455 sizeof (retval))) == 0) { 456 *linkid = retval.lr_linkid; 457 } 458 return (err); 459 } 460 461 datalink_id_t 462 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class, 463 datalink_media_t dmedia, uint32_t flags) 464 { 465 dlmgmt_door_getnext_t getnext; 466 dlmgmt_getnext_retval_t retval; 467 468 getnext.ld_cmd = DLMGMT_CMD_GETNEXT; 469 getnext.ld_class = class; 470 getnext.ld_dmedia = dmedia; 471 getnext.ld_flags = flags; 472 getnext.ld_linkid = linkid; 473 474 if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval, 475 sizeof (retval)) != 0) { 476 return (DATALINK_INVALID_LINKID); 477 } 478 479 return (retval.lr_linkid); 480 } 481 482 static int 483 i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr, 484 void *attrval, size_t *attrszp) 485 { 486 dlmgmt_upcall_arg_getattr_t getattr; 487 dlmgmt_getattr_retval_t retval; 488 int err; 489 490 getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR; 491 getattr.ld_linkid = linkid; 492 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); 493 494 if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval, 495 sizeof (retval))) == 0) { 496 if (*attrszp < retval.lr_attrsz) 497 return (EINVAL); 498 *attrszp = retval.lr_attrsz; 499 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 500 } 501 502 return (err); 503 } 504 505 /* 506 * Note that this function can only get devp successfully for non-VLAN link. 507 */ 508 int 509 dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp) 510 { 511 uint64_t maj, inst; 512 size_t attrsz = sizeof (uint64_t); 513 514 if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 || 515 attrsz != sizeof (uint64_t) || 516 i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 || 517 attrsz != sizeof (uint64_t)) { 518 return (EINVAL); 519 } 520 521 *devp = makedevice((major_t)maj, (minor_t)inst); 522 return (0); 523 } 524 525 /* 526 * Request the datalink management daemon to push in 527 * all properties associated with the link. 528 * Returns a non-zero error code on failure. 529 */ 530 int 531 dls_mgmt_linkprop_init(datalink_id_t linkid) 532 { 533 dlmgmt_door_linkprop_init_t li; 534 dlmgmt_linkprop_init_retval_t retval; 535 int err; 536 537 li.ld_cmd = DLMGMT_CMD_LINKPROP_INIT; 538 li.ld_linkid = linkid; 539 540 err = i_dls_mgmt_upcall(&li, sizeof (li), &retval, sizeof (retval)); 541 return (err); 542 } 543 544 static void 545 dls_devnet_prop_task(void *arg) 546 { 547 dls_devnet_t *ddp = arg; 548 549 (void) dls_mgmt_linkprop_init(ddp->dd_vlanid); 550 551 mutex_enter(&ddp->dd_mutex); 552 ddp->dd_prop_loaded = B_TRUE; 553 ddp->dd_prop_taskid = NULL; 554 cv_broadcast(&ddp->dd_cv); 555 mutex_exit(&ddp->dd_mutex); 556 } 557 558 /* 559 * Ensure property loading task is completed. 560 */ 561 void 562 dls_devnet_prop_task_wait(dls_dl_handle_t ddp) 563 { 564 mutex_enter(&ddp->dd_mutex); 565 while (ddp->dd_prop_taskid != NULL) 566 cv_wait(&ddp->dd_cv, &ddp->dd_mutex); 567 mutex_exit(&ddp->dd_mutex); 568 } 569 570 /* 571 * Hold the vanity naming structure (dls_devnet_t) temporarily. The request to 572 * delete the dls_devnet_t will wait until the temporary reference is released. 573 */ 574 int 575 dls_devnet_hold_tmp(datalink_id_t linkid, dls_dl_handle_t *ddhp) 576 { 577 dls_devnet_t *ddp; 578 dls_dev_handle_t ddh = NULL; 579 dev_t phydev = 0; 580 int err; 581 582 /* 583 * Hold this link to prevent it being detached (if physical link). 584 */ 585 if (dls_mgmt_get_phydev(linkid, &phydev) == 0) 586 (void) softmac_hold_device(phydev, &ddh); 587 588 rw_enter(&i_dls_devnet_lock, RW_READER); 589 if ((err = mod_hash_find(i_dls_devnet_id_hash, 590 (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) { 591 ASSERT(err == MH_ERR_NOTFOUND); 592 rw_exit(&i_dls_devnet_lock); 593 softmac_rele_device(ddh); 594 return (ENOENT); 595 } 596 597 /* 598 * At least one reference was held when this datalink was created. 599 */ 600 ASSERT(ddp->dd_ref > 0); 601 mutex_enter(&ddp->dd_mutex); 602 ddp->dd_tref++; 603 mutex_exit(&ddp->dd_mutex); 604 rw_exit(&i_dls_devnet_lock); 605 softmac_rele_device(ddh); 606 607 done: 608 *ddhp = ddp; 609 return (0); 610 } 611 612 void 613 dls_devnet_rele_tmp(dls_dl_handle_t dlh) 614 { 615 dls_devnet_t *ddp = dlh; 616 617 mutex_enter(&ddp->dd_mutex); 618 ASSERT(ddp->dd_tref != 0); 619 if (--ddp->dd_tref == 0) 620 cv_signal(&ddp->dd_cv); 621 mutex_exit(&ddp->dd_mutex); 622 } 623 624 /* 625 * "link" kstats related functions. 626 */ 627 628 /* 629 * Query the "link" kstats. 630 */ 631 static int 632 dls_devnet_stat_update(kstat_t *ksp, int rw) 633 { 634 dls_devnet_t *ddp = ksp->ks_private; 635 dls_vlan_t *dvp; 636 int err; 637 638 err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, B_FALSE); 639 if (err != 0) 640 return (err); 641 642 err = dls_stat_update(ksp, dvp, rw); 643 dls_vlan_rele(dvp); 644 return (err); 645 } 646 647 /* 648 * Create the "link" kstats. 649 */ 650 static void 651 dls_devnet_stat_create(dls_devnet_t *ddp) 652 { 653 char link[MAXLINKNAMELEN]; 654 kstat_t *ksp; 655 656 if ((dls_mgmt_get_linkinfo(ddp->dd_vlanid, link, 657 NULL, NULL, NULL)) != 0) { 658 return; 659 } 660 661 if (dls_stat_create("link", 0, link, dls_devnet_stat_update, 662 ddp, &ksp) != 0) { 663 return; 664 } 665 666 ASSERT(ksp != NULL); 667 ddp->dd_ksp = ksp; 668 } 669 670 /* 671 * Destroy the "link" kstats. 672 */ 673 static void 674 dls_devnet_stat_destroy(dls_devnet_t *ddp) 675 { 676 if (ddp->dd_ksp == NULL) 677 return; 678 679 kstat_delete(ddp->dd_ksp); 680 ddp->dd_ksp = NULL; 681 } 682 683 /* 684 * The link has been renamed. Destroy the old non-legacy kstats ("link kstats") 685 * and create the new set using the new name. 686 */ 687 static void 688 dls_devnet_stat_rename(dls_devnet_t *ddp, const char *link) 689 { 690 kstat_t *ksp; 691 692 if (ddp->dd_ksp != NULL) { 693 kstat_delete(ddp->dd_ksp); 694 ddp->dd_ksp = NULL; 695 } 696 697 if (dls_stat_create("link", 0, link, dls_devnet_stat_update, 698 ddp, &ksp) != 0) { 699 return; 700 } 701 702 ASSERT(ksp != NULL); 703 ddp->dd_ksp = ksp; 704 } 705 706 /* 707 * Associate a linkid with a given link (identified by <macname/vid>) 708 * 709 * Several cases: 710 * a. implicit VLAN creation: (non-NULL "vlan") 711 * b. explicit VLAN creation: (NULL "vlan") 712 * c. explicit non-VLAN creation: 713 * (NULL "vlan" and linkid could be INVALID_LINKID if the physical device 714 * was created before the daemon was started) 715 */ 716 static int 717 dls_devnet_set(const char *macname, uint16_t vid, 718 datalink_id_t vlan_linkid, datalink_id_t linkid, const char *vlan, 719 dls_devnet_t **ddpp) 720 { 721 dls_devnet_t *ddp = NULL; 722 char spa[MAXSPALEN]; 723 boolean_t explicit = (vlan == NULL); 724 datalink_class_t class; 725 int err; 726 727 ASSERT(vid != VLAN_ID_NONE || explicit); 728 ASSERT(vlan_linkid != DATALINK_INVALID_LINKID || !explicit || 729 vid == VLAN_ID_NONE); 730 731 (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); 732 rw_enter(&i_dls_devnet_lock, RW_WRITER); 733 if ((err = mod_hash_find(i_dls_devnet_hash, 734 (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) == 0) { 735 char link[MAXLINKNAMELEN]; 736 737 if (explicit) { 738 if ((vid != VLAN_ID_NONE) || 739 (ddp->dd_vlanid != DATALINK_INVALID_LINKID)) { 740 err = EEXIST; 741 goto done; 742 } 743 744 /* 745 * This might be a physical link that has already 746 * been created, but which does not have a vlan_linkid 747 * because dlmgmtd was not running when it was created. 748 */ 749 if ((err = dls_mgmt_get_linkinfo(vlan_linkid, NULL, 750 &class, NULL, NULL)) != 0) { 751 goto done; 752 } 753 754 if (class != DATALINK_CLASS_PHYS) { 755 err = EINVAL; 756 goto done; 757 } 758 759 goto newphys; 760 } 761 762 /* 763 * Implicit VLAN, but the same name has already 764 * been associated with another linkid. Check if the name 765 * of that link matches the given VLAN name. 766 */ 767 ASSERT(vid != VLAN_ID_NONE); 768 if ((err = dls_mgmt_get_linkinfo(ddp->dd_vlanid, link, 769 NULL, NULL, NULL)) != 0) { 770 goto done; 771 } 772 773 if (strcmp(link, vlan) != 0) { 774 err = EEXIST; 775 goto done; 776 } 777 778 /* 779 * This is not an implicit created VLAN any more, return 780 * this existing datalink. 781 */ 782 ASSERT(ddp->dd_ref > 0); 783 ddp->dd_ref++; 784 goto done; 785 } 786 787 /* 788 * Request the daemon to create a new vlan_linkid for this implicitly 789 * created vlan. 790 */ 791 if (!explicit && ((err = dls_mgmt_create(vlan, 0, 792 DATALINK_CLASS_VLAN, DL_ETHER, B_FALSE, &vlan_linkid)) != 0)) { 793 goto done; 794 } 795 796 ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP); 797 ddp->dd_vid = vid; 798 ddp->dd_explicit = explicit; 799 ddp->dd_tref = 0; 800 ddp->dd_ref++; 801 ddp->dd_zid = GLOBAL_ZONEID; 802 (void) strncpy(ddp->dd_mac, macname, MAXNAMELEN); 803 (void) snprintf(ddp->dd_spa, MAXSPALEN, "%s/%d", macname, vid); 804 VERIFY(mod_hash_insert(i_dls_devnet_hash, 805 (mod_hash_key_t)ddp->dd_spa, (mod_hash_val_t)ddp) == 0); 806 807 newphys: 808 809 ddp->dd_vlanid = vlan_linkid; 810 if (ddp->dd_vlanid != DATALINK_INVALID_LINKID) { 811 ddp->dd_linkid = linkid; 812 813 VERIFY(mod_hash_insert(i_dls_devnet_id_hash, 814 (mod_hash_key_t)(uintptr_t)vlan_linkid, 815 (mod_hash_val_t)ddp) == 0); 816 devnet_need_rebuild = B_TRUE; 817 dls_devnet_stat_create(ddp); 818 819 mutex_enter(&ddp->dd_mutex); 820 if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) { 821 ddp->dd_prop_taskid = taskq_dispatch(system_taskq, 822 dls_devnet_prop_task, ddp, TQ_SLEEP); 823 } 824 mutex_exit(&ddp->dd_mutex); 825 } 826 827 err = 0; 828 done: 829 rw_exit(&i_dls_devnet_lock); 830 if (err == 0 && ddpp != NULL) 831 *ddpp = ddp; 832 return (err); 833 } 834 835 static void 836 dls_devnet_unset_common(dls_devnet_t *ddp) 837 { 838 mod_hash_val_t val; 839 840 ASSERT(RW_WRITE_HELD(&i_dls_devnet_lock)); 841 842 ASSERT(ddp->dd_ref == 0); 843 844 /* 845 * Remove this dls_devnet_t from the hash table. 846 */ 847 VERIFY(mod_hash_remove(i_dls_devnet_hash, 848 (mod_hash_key_t)ddp->dd_spa, &val) == 0); 849 850 if (ddp->dd_vlanid != DATALINK_INVALID_LINKID) { 851 VERIFY(mod_hash_remove(i_dls_devnet_id_hash, 852 (mod_hash_key_t)(uintptr_t)ddp->dd_vlanid, &val) == 0); 853 854 dls_devnet_stat_destroy(ddp); 855 devnet_need_rebuild = B_TRUE; 856 } 857 858 /* 859 * Wait until all temporary references are released. 860 */ 861 mutex_enter(&ddp->dd_mutex); 862 while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL)) 863 cv_wait(&ddp->dd_cv, &ddp->dd_mutex); 864 865 ddp->dd_prop_loaded = B_FALSE; 866 mutex_exit(&ddp->dd_mutex); 867 868 if (!ddp->dd_explicit) { 869 ASSERT(ddp->dd_vid != VLAN_ID_NONE); 870 ASSERT(ddp->dd_vlanid != DATALINK_INVALID_LINKID); 871 (void) dls_mgmt_destroy(ddp->dd_vlanid, B_FALSE); 872 } 873 874 ddp->dd_vlanid = DATALINK_INVALID_LINKID; 875 ddp->dd_zid = GLOBAL_ZONEID; 876 ddp->dd_explicit = B_FALSE; 877 kmem_cache_free(i_dls_devnet_cachep, ddp); 878 } 879 880 /* 881 * Disassociate a linkid with a given link (identified by <macname/vid>) 882 */ 883 static int 884 dls_devnet_unset(const char *macname, uint16_t vid, datalink_id_t *id) 885 { 886 dls_devnet_t *ddp; 887 char spa[MAXSPALEN]; 888 int err; 889 890 (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); 891 892 rw_enter(&i_dls_devnet_lock, RW_WRITER); 893 if ((err = mod_hash_find(i_dls_devnet_hash, 894 (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) != 0) { 895 ASSERT(err == MH_ERR_NOTFOUND); 896 rw_exit(&i_dls_devnet_lock); 897 return (ENOENT); 898 } 899 900 ASSERT(ddp->dd_ref != 0); 901 902 if (ddp->dd_ref != 1) { 903 rw_exit(&i_dls_devnet_lock); 904 return (EBUSY); 905 } 906 907 ddp->dd_ref--; 908 909 if (id != NULL) 910 *id = ddp->dd_vlanid; 911 912 dls_devnet_unset_common(ddp); 913 rw_exit(&i_dls_devnet_lock); 914 return (0); 915 } 916 917 static int 918 dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp) 919 { 920 dls_devnet_t *ddp; 921 dev_t phydev = 0; 922 dls_dev_handle_t ddh = NULL; 923 int err; 924 925 /* 926 * Hold this link to prevent it being detached in case of a 927 * physical link. 928 */ 929 if (dls_mgmt_get_phydev(linkid, &phydev) == 0) 930 (void) softmac_hold_device(phydev, &ddh); 931 932 rw_enter(&i_dls_devnet_lock, RW_WRITER); 933 if ((err = mod_hash_find(i_dls_devnet_id_hash, 934 (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) { 935 ASSERT(err == MH_ERR_NOTFOUND); 936 rw_exit(&i_dls_devnet_lock); 937 softmac_rele_device(ddh); 938 return (ENOENT); 939 } 940 941 ASSERT(ddp->dd_ref > 0); 942 ddp->dd_ref++; 943 rw_exit(&i_dls_devnet_lock); 944 softmac_rele_device(ddh); 945 946 done: 947 *ddpp = ddp; 948 return (0); 949 } 950 951 /* 952 * This funtion is called when a DLS client tries to open a device node. 953 * This dev_t could a result of a /dev/net node access (returned by 954 * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access. 955 * In both cases, this function returns 0. In the first case, bump the 956 * reference count of the dls_devnet_t structure, so that it will not be 957 * freed when devnet_inactive_callback->dls_devnet_close() is called 958 * (Note that devnet_inactive_callback() is called right after dld_open, 959 * not when the /dev/net access is done). In the second case, ddhp would 960 * be NULL. 961 * 962 * To undo this function, call dls_devnet_close() in the first case, and call 963 * dls_vlan_rele() in the second case. 964 */ 965 int 966 dls_devnet_open_by_dev(dev_t dev, dls_vlan_t **dvpp, dls_dl_handle_t *ddhp) 967 { 968 dls_dev_handle_t ddh = NULL; 969 char spa[MAXSPALEN]; 970 dls_devnet_t *ddp; 971 dls_vlan_t *dvp; 972 int err; 973 974 /* 975 * Hold this link to prevent it being detached in case of a 976 * GLDv3 physical link. 977 */ 978 if (getminor(dev) - 1 < MAC_MAX_MINOR) 979 (void) softmac_hold_device(dev, &ddh); 980 981 /* 982 * Found the dls_vlan_t with the given dev. 983 */ 984 err = dls_vlan_hold_by_dev(dev, &dvp); 985 softmac_rele_device(ddh); 986 987 if (err != 0) 988 return (err); 989 990 (void) snprintf(spa, MAXSPALEN, "%s/%d", 991 dvp->dv_dlp->dl_name, dvp->dv_id); 992 993 rw_enter(&i_dls_devnet_lock, RW_WRITER); 994 if ((err = mod_hash_find(i_dls_devnet_hash, 995 (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) != 0) { 996 ASSERT(err == MH_ERR_NOTFOUND); 997 rw_exit(&i_dls_devnet_lock); 998 *ddhp = NULL; 999 *dvpp = dvp; 1000 return (0); 1001 } 1002 1003 ASSERT(ddp->dd_ref > 0); 1004 ddp->dd_ref++; 1005 rw_exit(&i_dls_devnet_lock); 1006 *ddhp = ddp; 1007 *dvpp = dvp; 1008 return (0); 1009 } 1010 1011 static void 1012 dls_devnet_rele(dls_devnet_t *ddp) 1013 { 1014 rw_enter(&i_dls_devnet_lock, RW_WRITER); 1015 ASSERT(ddp->dd_ref != 0); 1016 if (--ddp->dd_ref != 0) { 1017 rw_exit(&i_dls_devnet_lock); 1018 return; 1019 } 1020 /* 1021 * This should only happen for implicitly-created VLAN. 1022 */ 1023 ASSERT(ddp->dd_vid != VLAN_ID_NONE); 1024 dls_devnet_unset_common(ddp); 1025 rw_exit(&i_dls_devnet_lock); 1026 } 1027 1028 static int 1029 dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp, zoneid_t zid) 1030 { 1031 char link_under[MAXLINKNAMELEN]; 1032 char drv[MAXLINKNAMELEN]; 1033 uint_t ppa; 1034 major_t major; 1035 dev_t phy_dev, tmp_dev; 1036 uint_t vid; 1037 datalink_id_t linkid; 1038 dls_devnet_t *ddp; 1039 dls_dev_handle_t ddh; 1040 int err; 1041 1042 if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0) 1043 return (dls_devnet_hold(linkid, ddpp)); 1044 1045 /* 1046 * If we failed to get the link's linkid because the dlmgmtd daemon 1047 * has not been started, return ENOENT so that the application can 1048 * fallback to open the /dev node. 1049 */ 1050 if (err == EBADF) 1051 return (ENOENT); 1052 1053 if (err != ENOENT) 1054 return (err); 1055 1056 if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS) 1057 return (ENOENT); 1058 1059 if ((vid = DLS_PPA2VID(ppa)) > VLAN_ID_MAX) 1060 return (ENOENT); 1061 1062 ppa = (uint_t)DLS_PPA2INST(ppa); 1063 (void) snprintf(link_under, sizeof (link_under), "%s%d", drv, ppa); 1064 1065 if (vid != VLAN_ID_NONE) { 1066 /* 1067 * Only global zone can implicitly create a VLAN. 1068 */ 1069 if (zid != GLOBAL_ZONEID) 1070 return (ENOENT); 1071 1072 /* 1073 * This is potentially an implicitly-created VLAN. Hold the 1074 * link this VLAN is created on. 1075 */ 1076 if (dls_mgmt_get_linkid(link_under, &linkid) == 0 && 1077 dls_devnet_hold_tmp(linkid, &ddp) == 0) { 1078 if (ddp->dd_vid != VLAN_ID_NONE) { 1079 dls_devnet_rele_tmp(ddp); 1080 return (ENOENT); 1081 } 1082 goto implicit; 1083 } 1084 } 1085 1086 /* 1087 * If this link (or the link that an implicit vlan is created on) 1088 * (a) is a physical device, (b) this is the first boot, (c) the MAC 1089 * is not registered yet, and (d) we cannot find its linkid, then the 1090 * linkname is the same as the devname. 1091 * 1092 * First filter out invalid names. 1093 */ 1094 if ((major = ddi_name_to_major(drv)) == (major_t)-1) 1095 return (ENOENT); 1096 1097 phy_dev = makedevice(major, (minor_t)ppa + 1); 1098 if (softmac_hold_device(phy_dev, &ddh) != 0) 1099 return (ENOENT); 1100 1101 /* 1102 * At this time, the MAC should be registered, check its phy_dev using 1103 * the given name. 1104 */ 1105 if ((err = dls_mgmt_get_linkid(link_under, &linkid)) != 0 || 1106 (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) { 1107 softmac_rele_device(ddh); 1108 return (err); 1109 } 1110 if (tmp_dev != phy_dev) { 1111 softmac_rele_device(ddh); 1112 return (ENOENT); 1113 } 1114 1115 if (vid == VLAN_ID_NONE) { 1116 /* 1117 * For non-VLAN, we are done. 1118 */ 1119 err = dls_devnet_hold(linkid, ddpp); 1120 softmac_rele_device(ddh); 1121 return (err); 1122 } 1123 1124 /* 1125 * If this is an implicit VLAN, temporarily hold this non-VLAN. 1126 */ 1127 VERIFY(dls_devnet_hold_tmp(linkid, &ddp) == 0); 1128 softmac_rele_device(ddh); 1129 ASSERT(ddp->dd_vid == VLAN_ID_NONE); 1130 1131 /* 1132 * Again, this is potentially an implicitly-created VLAN. 1133 */ 1134 1135 implicit: 1136 ASSERT(vid != VLAN_ID_NONE); 1137 err = dls_devnet_set(ddp->dd_mac, vid, DATALINK_INVALID_LINKID, 1138 linkid, link, ddpp); 1139 dls_devnet_rele_tmp(ddp); 1140 return (err); 1141 } 1142 1143 /* 1144 * Get linkid for the given dev. 1145 */ 1146 int 1147 dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp) 1148 { 1149 dls_vlan_t *dvp; 1150 dls_devnet_t *ddp; 1151 char spa[MAXSPALEN]; 1152 int err; 1153 1154 if ((err = dls_vlan_hold_by_dev(dev, &dvp)) != 0) 1155 return (err); 1156 1157 (void) snprintf(spa, MAXSPALEN, "%s/%d", 1158 dvp->dv_dlp->dl_name, dvp->dv_id); 1159 1160 rw_enter(&i_dls_devnet_lock, RW_READER); 1161 if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)spa, 1162 (mod_hash_val_t *)&ddp) != 0) { 1163 rw_exit(&i_dls_devnet_lock); 1164 dls_vlan_rele(dvp); 1165 return (ENOENT); 1166 } 1167 1168 *linkidp = ddp->dd_vlanid; 1169 rw_exit(&i_dls_devnet_lock); 1170 dls_vlan_rele(dvp); 1171 return (0); 1172 } 1173 1174 /* 1175 * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the 1176 * link this VLAN is created on. 1177 */ 1178 int 1179 dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp) 1180 { 1181 dls_devnet_t *ddp; 1182 int err; 1183 1184 if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0) 1185 return (err); 1186 1187 err = dls_mgmt_get_phydev(ddp->dd_linkid, devp); 1188 dls_devnet_rele_tmp(ddp); 1189 return (err); 1190 } 1191 1192 /* 1193 * Handle the renaming requests. There are two rename cases: 1194 * 1195 * 1. Request to rename a valid link (id1) to an non-existent link name 1196 * (id2). In this case id2 is DATALINK_INVALID_LINKID. Just check whether 1197 * id1 is held by any applications. 1198 * 1199 * In this case, the link's kstats need to be updated using the given name. 1200 * 1201 * 2. Request to rename a valid link (id1) to the name of a REMOVED 1202 * physical link (id2). In this case, check that id1 and its associated 1203 * mac is not held by any application, and update the link's linkid to id2. 1204 * 1205 * This case does not change the <link name, linkid> mapping, so the link's 1206 * kstats need to be updated with using name associated the given id2. 1207 */ 1208 int 1209 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link) 1210 { 1211 dls_dev_handle_t ddh = NULL; 1212 char linkname[MAXLINKNAMELEN]; 1213 int err = 0; 1214 dev_t phydev = 0; 1215 dls_devnet_t *ddp; 1216 mac_handle_t mh; 1217 mod_hash_val_t val; 1218 1219 /* 1220 * In the second case, id2 must be a REMOVED physical link. 1221 */ 1222 if ((id2 != DATALINK_INVALID_LINKID) && 1223 (dls_mgmt_get_phydev(id2, &phydev) == 0) && 1224 softmac_hold_device(phydev, &ddh) == 0) { 1225 softmac_rele_device(ddh); 1226 return (EEXIST); 1227 } 1228 1229 /* 1230 * Hold id1 to prevent it from being detached (if a physical link). 1231 */ 1232 if (dls_mgmt_get_phydev(id1, &phydev) == 0) 1233 (void) softmac_hold_device(phydev, &ddh); 1234 1235 rw_enter(&i_dls_devnet_lock, RW_WRITER); 1236 if ((err = mod_hash_find(i_dls_devnet_id_hash, 1237 (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) { 1238 ASSERT(err == MH_ERR_NOTFOUND); 1239 err = ENOENT; 1240 goto done; 1241 } 1242 1243 /* 1244 * Let the property loading thread finish. 1245 * Unfortunately, we have to drop i_dls_devnet_lock temporarily 1246 * to avoid deadlocks, and ensure ddp is still in the hash after 1247 * reacquiring it. Observe lock order as well. 1248 */ 1249 mutex_enter(&ddp->dd_mutex); 1250 if (ddp->dd_prop_taskid != NULL) { 1251 rw_exit(&i_dls_devnet_lock); 1252 while (ddp->dd_prop_taskid != NULL) 1253 cv_wait(&ddp->dd_cv, &ddp->dd_mutex); 1254 mutex_exit(&ddp->dd_mutex); 1255 rw_enter(&i_dls_devnet_lock, RW_WRITER); 1256 1257 if ((err = mod_hash_find(i_dls_devnet_id_hash, 1258 (mod_hash_key_t)(uintptr_t)id1, 1259 (mod_hash_val_t *)&ddp)) != 0) { 1260 ASSERT(err == MH_ERR_NOTFOUND); 1261 err = ENOENT; 1262 goto done; 1263 } 1264 } else { 1265 mutex_exit(&ddp->dd_mutex); 1266 } 1267 1268 /* 1269 * Return EBUSY if any applications have this link open. 1270 */ 1271 if ((ddp->dd_explicit && ddp->dd_ref > 1) || 1272 (!ddp->dd_explicit && ddp->dd_ref > 0)) { 1273 err = EBUSY; 1274 goto done; 1275 } 1276 1277 if (id2 == DATALINK_INVALID_LINKID) { 1278 (void) strlcpy(linkname, link, sizeof (linkname)); 1279 goto done; 1280 } 1281 1282 /* 1283 * The second case, check whether the MAC is used by any MAC 1284 * user. This must be a physical link so ddh must not be NULL. 1285 */ 1286 if (ddh == NULL) { 1287 err = EINVAL; 1288 goto done; 1289 } 1290 1291 if ((err = mac_open(ddp->dd_mac, &mh)) != 0) 1292 goto done; 1293 1294 /* 1295 * We release the reference of the MAC which mac_open() is 1296 * holding. Note that this mac will not be unregistered 1297 * because the physical device is hold. 1298 */ 1299 mac_close(mh); 1300 1301 /* 1302 * Check if there is any other MAC clients, if not, hold this mac 1303 * exclusively until we are done. 1304 */ 1305 if ((err = mac_hold_exclusive(mh)) != 0) 1306 goto done; 1307 1308 /* 1309 * Update the link's linkid. 1310 */ 1311 if ((err = mod_hash_find(i_dls_devnet_id_hash, 1312 (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) { 1313 mac_rele_exclusive(mh); 1314 err = EEXIST; 1315 goto done; 1316 } 1317 1318 err = dls_mgmt_get_linkinfo(id2, linkname, NULL, NULL, NULL); 1319 if (err != 0) { 1320 mac_rele_exclusive(mh); 1321 goto done; 1322 } 1323 1324 (void) mod_hash_remove(i_dls_devnet_id_hash, 1325 (mod_hash_key_t)(uintptr_t)id1, &val); 1326 1327 ddp->dd_vlanid = id2; 1328 (void) mod_hash_insert(i_dls_devnet_id_hash, 1329 (mod_hash_key_t)(uintptr_t)ddp->dd_vlanid, (mod_hash_val_t)ddp); 1330 1331 /* load properties for new id */ 1332 mutex_enter(&ddp->dd_mutex); 1333 ddp->dd_prop_loaded = B_FALSE; 1334 ddp->dd_prop_taskid = taskq_dispatch(system_taskq, 1335 dls_devnet_prop_task, ddp, TQ_SLEEP); 1336 mutex_exit(&ddp->dd_mutex); 1337 1338 mac_rele_exclusive(mh); 1339 1340 done: 1341 /* 1342 * Change the name of the kstat based on the new link name. 1343 */ 1344 if (err == 0) 1345 dls_devnet_stat_rename(ddp, linkname); 1346 1347 rw_exit(&i_dls_devnet_lock); 1348 softmac_rele_device(ddh); 1349 return (err); 1350 } 1351 1352 int 1353 dls_devnet_setzid(const char *link, zoneid_t zid) 1354 { 1355 dls_devnet_t *ddp; 1356 int err; 1357 zoneid_t old_zid; 1358 1359 if ((err = dls_devnet_hold_by_name(link, &ddp, GLOBAL_ZONEID)) != 0) 1360 return (err); 1361 1362 mutex_enter(&ddp->dd_zid_mutex); 1363 if ((old_zid = ddp->dd_zid) == zid) { 1364 mutex_exit(&ddp->dd_zid_mutex); 1365 dls_devnet_rele(ddp); 1366 return (0); 1367 } 1368 1369 if ((err = dls_vlan_setzid(ddp->dd_mac, ddp->dd_vid, zid)) != 0) { 1370 mutex_exit(&ddp->dd_zid_mutex); 1371 dls_devnet_rele(ddp); 1372 return (err); 1373 } 1374 1375 ddp->dd_zid = zid; 1376 devnet_need_rebuild = B_TRUE; 1377 mutex_exit(&ddp->dd_zid_mutex); 1378 1379 /* 1380 * Keep this open reference only if it belonged to the global zone 1381 * and is now assigned to a non-global zone. 1382 */ 1383 if (old_zid != GLOBAL_ZONEID || zid == GLOBAL_ZONEID) 1384 dls_devnet_rele(ddp); 1385 1386 /* 1387 * Then release this link if it belonged to an non-global zone 1388 * but is now assigned back to the global zone. 1389 */ 1390 if (old_zid != GLOBAL_ZONEID && zid == GLOBAL_ZONEID) 1391 dls_devnet_rele(ddp); 1392 1393 return (0); 1394 } 1395 1396 int 1397 dls_devnet_getzid(datalink_id_t linkid, zoneid_t *zidp) 1398 { 1399 dls_devnet_t *ddp; 1400 int err; 1401 1402 if ((err = dls_devnet_hold_tmp(linkid, &ddp)) != 0) 1403 return (err); 1404 1405 mutex_enter(&ddp->dd_zid_mutex); 1406 *zidp = ddp->dd_zid; 1407 mutex_exit(&ddp->dd_zid_mutex); 1408 1409 dls_devnet_rele_tmp(ddp); 1410 return (0); 1411 } 1412 1413 /* 1414 * Access a vanity naming node. 1415 */ 1416 int 1417 dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp) 1418 { 1419 dls_devnet_t *ddp; 1420 dls_vlan_t *dvp; 1421 zoneid_t zid = getzoneid(); 1422 int err; 1423 1424 if ((err = dls_devnet_hold_by_name(link, &ddp, zid)) != 0) 1425 return (err); 1426 1427 /* 1428 * Opening a link that does not belong to the current non-global zone 1429 * is not allowed. 1430 */ 1431 if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) { 1432 dls_devnet_rele(ddp); 1433 return (ENOENT); 1434 } 1435 1436 err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, B_TRUE); 1437 if (err != 0) { 1438 dls_devnet_rele(ddp); 1439 return (err); 1440 } 1441 1442 dls_devnet_prop_task_wait(ddp); 1443 1444 *dhp = ddp; 1445 *devp = dvp->dv_dev; 1446 return (0); 1447 } 1448 1449 /* 1450 * Close access to a vanity naming node. 1451 */ 1452 void 1453 dls_devnet_close(dls_dl_handle_t dlh) 1454 { 1455 dls_devnet_t *ddp = dlh; 1456 dls_vlan_t *dvp; 1457 1458 /* 1459 * The VLAN is hold in dls_open_devnet_link(). 1460 */ 1461 VERIFY((dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, 1462 B_FALSE)) == 0); 1463 dls_vlan_rele(dvp); 1464 dls_vlan_rele(dvp); 1465 dls_devnet_rele(ddp); 1466 } 1467 1468 /* 1469 * This is used by /dev/net to rebuild the nodes for readdir(). It is not 1470 * critical and no protection is needed. 1471 */ 1472 boolean_t 1473 dls_devnet_rebuild() 1474 { 1475 boolean_t updated = devnet_need_rebuild; 1476 1477 devnet_need_rebuild = B_FALSE; 1478 return (updated); 1479 } 1480 1481 int 1482 dls_devnet_create(mac_handle_t mh, datalink_id_t linkid) 1483 { 1484 int err; 1485 1486 if ((err = dls_vlan_create(mac_name(mh), 0, B_FALSE)) != 0) 1487 return (err); 1488 1489 err = dls_devnet_set(mac_name(mh), 0, linkid, linkid, NULL, NULL); 1490 if (err != 0) 1491 (void) dls_vlan_destroy(mac_name(mh), 0); 1492 1493 return (err); 1494 } 1495 1496 /* 1497 * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash. 1498 * This is called in the case that the dlmgmtd daemon is started later than 1499 * the physical devices get attached, and the linkid is only known after the 1500 * daemon starts. 1501 */ 1502 int 1503 dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid) 1504 { 1505 ASSERT(linkid != DATALINK_INVALID_LINKID); 1506 return (dls_devnet_set(mac_name(mh), 0, linkid, linkid, NULL, NULL)); 1507 } 1508 1509 int 1510 dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp) 1511 { 1512 int err; 1513 1514 *idp = DATALINK_INVALID_LINKID; 1515 err = dls_devnet_unset(mac_name(mh), 0, idp); 1516 if (err != 0 && err != ENOENT) 1517 return (err); 1518 1519 if ((err = dls_vlan_destroy(mac_name(mh), 0)) == 0) 1520 return (0); 1521 1522 (void) dls_devnet_set(mac_name(mh), 0, *idp, *idp, NULL, NULL); 1523 return (err); 1524 } 1525 1526 int 1527 dls_devnet_create_vlan(datalink_id_t vlanid, datalink_id_t linkid, 1528 uint16_t vid, boolean_t force) 1529 { 1530 dls_devnet_t *lnddp, *ddp; 1531 dls_vlan_t *dvp; 1532 int err; 1533 1534 /* 1535 * Hold the link the VLAN is being created on (which must not be a 1536 * VLAN). 1537 */ 1538 ASSERT(vid != VLAN_ID_NONE); 1539 if ((err = dls_devnet_hold_tmp(linkid, &lnddp)) != 0) 1540 return (err); 1541 1542 if (lnddp->dd_vid != VLAN_ID_NONE) { 1543 err = EINVAL; 1544 goto done; 1545 } 1546 1547 /* 1548 * A new link. 1549 */ 1550 err = dls_devnet_set(lnddp->dd_mac, vid, vlanid, linkid, NULL, &ddp); 1551 if (err != 0) 1552 goto done; 1553 1554 /* 1555 * Hold the dls_vlan_t (and create it if needed). 1556 */ 1557 err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, force, B_TRUE); 1558 if (err != 0) 1559 VERIFY(dls_devnet_unset(lnddp->dd_mac, vid, NULL) == 0); 1560 1561 done: 1562 dls_devnet_rele_tmp(lnddp); 1563 return (err); 1564 } 1565 1566 int 1567 dls_devnet_destroy_vlan(datalink_id_t vlanid) 1568 { 1569 char macname[MAXNAMELEN]; 1570 uint16_t vid; 1571 dls_devnet_t *ddp; 1572 dls_vlan_t *dvp; 1573 int err; 1574 1575 if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0) 1576 return (err); 1577 1578 if (ddp->dd_vid == VLAN_ID_NONE) { 1579 dls_devnet_rele_tmp(ddp); 1580 return (EINVAL); 1581 } 1582 1583 if (!ddp->dd_explicit) { 1584 dls_devnet_rele_tmp(ddp); 1585 return (EBUSY); 1586 } 1587 1588 (void) strncpy(macname, ddp->dd_mac, MAXNAMELEN); 1589 vid = ddp->dd_vid; 1590 1591 /* 1592 * It is safe to release the temporary reference we just held, as the 1593 * reference from VLAN creation is still held. 1594 */ 1595 dls_devnet_rele_tmp(ddp); 1596 1597 if ((err = dls_devnet_unset(macname, vid, NULL)) != 0) 1598 return (err); 1599 1600 /* 1601 * This VLAN has already been held as the result of VLAN creation. 1602 */ 1603 VERIFY(dls_vlan_hold(macname, vid, &dvp, B_FALSE, B_FALSE) == 0); 1604 1605 /* 1606 * Release the reference which was held when this VLAN was created, 1607 * and the reference which was just held. 1608 */ 1609 dls_vlan_rele(dvp); 1610 dls_vlan_rele(dvp); 1611 return (0); 1612 } 1613 1614 const char * 1615 dls_devnet_mac(dls_dl_handle_t ddh) 1616 { 1617 return (ddh->dd_mac); 1618 } 1619 1620 uint16_t 1621 dls_devnet_vid(dls_dl_handle_t ddh) 1622 { 1623 return (ddh->dd_vid); 1624 } 1625 1626 datalink_id_t 1627 dls_devnet_linkid(dls_dl_handle_t ddh) 1628 { 1629 return (ddh->dd_linkid); 1630 } 1631 1632 boolean_t 1633 dls_devnet_is_explicit(dls_dl_handle_t ddh) 1634 { 1635 return (ddh->dd_explicit); 1636 } 1637