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