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