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