1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Utility functions used by the dlmgmtd daemon. 28 */ 29 30 #include <assert.h> 31 #include <pthread.h> 32 #include <stddef.h> 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <errno.h> 36 #include <strings.h> 37 #include <string.h> 38 #include <syslog.h> 39 #include <stdarg.h> 40 #include <zone.h> 41 #include <errno.h> 42 #include <libdlpi.h> 43 #include "dlmgmt_impl.h" 44 45 /* 46 * There are three datalink AVL tables. The dlmgmt_name_avl tree contains all 47 * datalinks and is keyed by zoneid and link name. The dlmgmt_id_avl also 48 * contains all datalinks, and it is keyed by link ID. The dlmgmt_loan_avl is 49 * keyed by link name, and contains the set of global-zone links that are 50 * currently on loan to non-global zones. 51 */ 52 avl_tree_t dlmgmt_name_avl; 53 avl_tree_t dlmgmt_id_avl; 54 avl_tree_t dlmgmt_loan_avl; 55 56 avl_tree_t dlmgmt_dlconf_avl; 57 58 static pthread_rwlock_t dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER; 59 static pthread_mutex_t dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER; 60 static pthread_cond_t dlmgmt_avl_cv = PTHREAD_COND_INITIALIZER; 61 static pthread_rwlock_t dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER; 62 63 typedef struct dlmgmt_prefix { 64 struct dlmgmt_prefix *lp_next; 65 char lp_prefix[MAXLINKNAMELEN]; 66 zoneid_t lp_zoneid; 67 uint_t lp_nextppa; 68 } dlmgmt_prefix_t; 69 static dlmgmt_prefix_t dlmgmt_prefixlist; 70 71 datalink_id_t dlmgmt_nextlinkid; 72 static datalink_id_t dlmgmt_nextconfid = 1; 73 74 static void dlmgmt_advance_linkid(dlmgmt_link_t *); 75 static void dlmgmt_advance_ppa(dlmgmt_link_t *); 76 77 void 78 dlmgmt_log(int pri, const char *fmt, ...) 79 { 80 va_list alist; 81 82 va_start(alist, fmt); 83 if (debug) { 84 (void) vfprintf(stderr, fmt, alist); 85 (void) fputc('\n', stderr); 86 } else { 87 vsyslog(pri, fmt, alist); 88 } 89 va_end(alist); 90 } 91 92 static int 93 cmp_link_by_name(const void *v1, const void *v2) 94 { 95 const dlmgmt_link_t *link1 = v1; 96 const dlmgmt_link_t *link2 = v2; 97 int cmp; 98 99 cmp = strcmp(link1->ll_link, link2->ll_link); 100 return ((cmp == 0) ? 0 : ((cmp < 0) ? -1 : 1)); 101 } 102 103 /* 104 * Note that the zoneid associated with a link is effectively part of its 105 * name. This is essentially what results in having each zone have disjoint 106 * datalink namespaces. 107 */ 108 static int 109 cmp_link_by_zname(const void *v1, const void *v2) 110 { 111 const dlmgmt_link_t *link1 = v1; 112 const dlmgmt_link_t *link2 = v2; 113 114 if (link1->ll_zoneid < link2->ll_zoneid) 115 return (-1); 116 if (link1->ll_zoneid > link2->ll_zoneid) 117 return (1); 118 return (cmp_link_by_name(link1, link2)); 119 } 120 121 static int 122 cmp_link_by_id(const void *v1, const void *v2) 123 { 124 const dlmgmt_link_t *link1 = v1; 125 const dlmgmt_link_t *link2 = v2; 126 127 if ((uint64_t)(link1->ll_linkid) == (uint64_t)(link2->ll_linkid)) 128 return (0); 129 else if ((uint64_t)(link1->ll_linkid) < (uint64_t)(link2->ll_linkid)) 130 return (-1); 131 else 132 return (1); 133 } 134 135 static int 136 cmp_dlconf_by_id(const void *v1, const void *v2) 137 { 138 const dlmgmt_dlconf_t *dlconfp1 = v1; 139 const dlmgmt_dlconf_t *dlconfp2 = v2; 140 141 if (dlconfp1->ld_id == dlconfp2->ld_id) 142 return (0); 143 else if (dlconfp1->ld_id < dlconfp2->ld_id) 144 return (-1); 145 else 146 return (1); 147 } 148 149 void 150 dlmgmt_linktable_init(void) 151 { 152 /* 153 * Initialize the prefix list. First add the "net" prefix for the 154 * global zone to the list. 155 */ 156 dlmgmt_prefixlist.lp_next = NULL; 157 dlmgmt_prefixlist.lp_zoneid = GLOBAL_ZONEID; 158 dlmgmt_prefixlist.lp_nextppa = 0; 159 (void) strlcpy(dlmgmt_prefixlist.lp_prefix, "net", MAXLINKNAMELEN); 160 161 avl_create(&dlmgmt_name_avl, cmp_link_by_zname, sizeof (dlmgmt_link_t), 162 offsetof(dlmgmt_link_t, ll_name_node)); 163 avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t), 164 offsetof(dlmgmt_link_t, ll_id_node)); 165 avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t), 166 offsetof(dlmgmt_link_t, ll_loan_node)); 167 avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id, 168 sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node)); 169 dlmgmt_nextlinkid = 1; 170 } 171 172 void 173 dlmgmt_linktable_fini(void) 174 { 175 dlmgmt_prefix_t *lpp, *next; 176 177 for (lpp = dlmgmt_prefixlist.lp_next; lpp != NULL; lpp = next) { 178 next = lpp->lp_next; 179 free(lpp); 180 } 181 182 avl_destroy(&dlmgmt_dlconf_avl); 183 avl_destroy(&dlmgmt_name_avl); 184 avl_destroy(&dlmgmt_loan_avl); 185 avl_destroy(&dlmgmt_id_avl); 186 } 187 188 static void 189 linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp) 190 { 191 if (*headp == NULL) { 192 *headp = attrp; 193 } else { 194 (*headp)->lp_prev = attrp; 195 attrp->lp_next = *headp; 196 *headp = attrp; 197 } 198 } 199 200 static void 201 linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp) 202 { 203 dlmgmt_linkattr_t *next, *prev; 204 205 next = attrp->lp_next; 206 prev = attrp->lp_prev; 207 if (next != NULL) 208 next->lp_prev = prev; 209 if (prev != NULL) 210 prev->lp_next = next; 211 else 212 *headp = next; 213 } 214 215 dlmgmt_linkattr_t * 216 linkattr_find(dlmgmt_linkattr_t *headp, const char *attr) 217 { 218 dlmgmt_linkattr_t *attrp; 219 220 for (attrp = headp; attrp != NULL; attrp = attrp->lp_next) { 221 if (strcmp(attrp->lp_name, attr) == 0) 222 break; 223 } 224 return (attrp); 225 } 226 227 int 228 linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval, 229 size_t attrsz, dladm_datatype_t type) 230 { 231 dlmgmt_linkattr_t *attrp; 232 void *newval; 233 boolean_t new; 234 235 attrp = linkattr_find(*headp, attr); 236 if (attrp != NULL) { 237 /* 238 * It is already set. If the value changed, update it. 239 */ 240 if (linkattr_equal(headp, attr, attrval, attrsz)) 241 return (0); 242 new = B_FALSE; 243 } else { 244 /* 245 * It is not set yet, allocate the linkattr and prepend to the 246 * list. 247 */ 248 if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL) 249 return (ENOMEM); 250 251 (void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN); 252 new = B_TRUE; 253 } 254 if ((newval = calloc(1, attrsz)) == NULL) { 255 if (new) 256 free(attrp); 257 return (ENOMEM); 258 } 259 260 if (!new) 261 free(attrp->lp_val); 262 attrp->lp_val = newval; 263 bcopy(attrval, attrp->lp_val, attrsz); 264 attrp->lp_sz = attrsz; 265 attrp->lp_type = type; 266 attrp->lp_linkprop = dladm_attr_is_linkprop(attr); 267 if (new) 268 linkattr_add(headp, attrp); 269 return (0); 270 } 271 272 void 273 linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr) 274 { 275 dlmgmt_linkattr_t *attrp; 276 277 if ((attrp = linkattr_find(*headp, attr)) != NULL) { 278 linkattr_rm(headp, attrp); 279 free(attrp->lp_val); 280 free(attrp); 281 } 282 } 283 284 int 285 linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp, 286 size_t *attrszp, dladm_datatype_t *typep) 287 { 288 dlmgmt_linkattr_t *attrp; 289 290 if ((attrp = linkattr_find(*headp, attr)) == NULL) 291 return (ENOENT); 292 293 *attrvalp = attrp->lp_val; 294 *attrszp = attrp->lp_sz; 295 if (typep != NULL) 296 *typep = attrp->lp_type; 297 return (0); 298 } 299 300 boolean_t 301 linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval, 302 size_t attrsz) 303 { 304 void *saved_attrval; 305 size_t saved_attrsz; 306 307 if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0) 308 return (B_FALSE); 309 310 return ((saved_attrsz == attrsz) && 311 (memcmp(saved_attrval, attrval, attrsz) == 0)); 312 } 313 314 void 315 linkattr_destroy(dlmgmt_link_t *linkp) 316 { 317 dlmgmt_linkattr_t *next, *attrp; 318 319 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 320 next = attrp->lp_next; 321 free(attrp->lp_val); 322 free(attrp); 323 } 324 } 325 326 static int 327 dlmgmt_table_readwritelock(boolean_t write) 328 { 329 if (write) 330 return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock)); 331 else 332 return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock)); 333 } 334 335 void 336 dlmgmt_table_lock(boolean_t write) 337 { 338 (void) pthread_mutex_lock(&dlmgmt_avl_mutex); 339 while (dlmgmt_table_readwritelock(write) == EBUSY) 340 (void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex); 341 342 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex); 343 } 344 345 void 346 dlmgmt_table_unlock(void) 347 { 348 (void) pthread_rwlock_unlock(&dlmgmt_avl_lock); 349 (void) pthread_mutex_lock(&dlmgmt_avl_mutex); 350 (void) pthread_cond_broadcast(&dlmgmt_avl_cv); 351 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex); 352 } 353 354 void 355 link_destroy(dlmgmt_link_t *linkp) 356 { 357 linkattr_destroy(linkp); 358 free(linkp); 359 } 360 361 /* 362 * Set the DLMGMT_ACTIVE flag on the link to note that it is active. When a 363 * link becomes active and it belongs to a non-global zone, it is also added 364 * to that zone. 365 */ 366 int 367 link_activate(dlmgmt_link_t *linkp) 368 { 369 int err = 0; 370 zoneid_t zoneid = ALL_ZONES; 371 372 if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) { 373 /* 374 * This link was already added to a non-global zone. This can 375 * happen if dlmgmtd is restarted. 376 */ 377 if (zoneid != linkp->ll_zoneid) { 378 if (link_by_name(linkp->ll_link, zoneid) != NULL) { 379 err = EEXIST; 380 goto done; 381 } 382 383 if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL) 384 avl_remove(&dlmgmt_name_avl, linkp); 385 386 linkp->ll_zoneid = zoneid; 387 avl_add(&dlmgmt_name_avl, linkp); 388 avl_add(&dlmgmt_loan_avl, linkp); 389 linkp->ll_onloan = B_TRUE; 390 } 391 } else if (linkp->ll_zoneid != GLOBAL_ZONEID) { 392 err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid); 393 } 394 done: 395 if (err == 0) 396 linkp->ll_flags |= DLMGMT_ACTIVE; 397 return (err); 398 } 399 400 /* 401 * Is linkp visible from the caller's zoneid? It is if the link is in the 402 * same zone as the caller, or if the caller is in the global zone and the 403 * link is on loan to a non-global zone. 404 */ 405 boolean_t 406 link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid) 407 { 408 return (linkp->ll_zoneid == zoneid || 409 (zoneid == GLOBAL_ZONEID && linkp->ll_onloan)); 410 } 411 412 dlmgmt_link_t * 413 link_by_id(datalink_id_t linkid, zoneid_t zoneid) 414 { 415 dlmgmt_link_t link, *linkp; 416 417 link.ll_linkid = linkid; 418 if ((linkp = avl_find(&dlmgmt_id_avl, &link, NULL)) == NULL) 419 return (NULL); 420 if (zoneid != GLOBAL_ZONEID && linkp->ll_zoneid != zoneid) 421 return (NULL); 422 return (linkp); 423 } 424 425 dlmgmt_link_t * 426 link_by_name(const char *name, zoneid_t zoneid) 427 { 428 dlmgmt_link_t link, *linkp; 429 430 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN); 431 link.ll_zoneid = zoneid; 432 linkp = avl_find(&dlmgmt_name_avl, &link, NULL); 433 if (linkp == NULL && zoneid == GLOBAL_ZONEID) { 434 /* The link could be on loan to a non-global zone? */ 435 linkp = avl_find(&dlmgmt_loan_avl, &link, NULL); 436 } 437 return (linkp); 438 } 439 440 int 441 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media, 442 zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp) 443 { 444 dlmgmt_link_t *linkp = NULL; 445 avl_index_t name_where, id_where; 446 int err = 0; 447 448 if (!dladm_valid_linkname(name)) 449 return (EINVAL); 450 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID) 451 return (ENOSPC); 452 453 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) { 454 err = ENOMEM; 455 goto done; 456 } 457 458 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN); 459 linkp->ll_class = class; 460 linkp->ll_media = media; 461 linkp->ll_linkid = dlmgmt_nextlinkid; 462 linkp->ll_zoneid = zoneid; 463 linkp->ll_gen = 0; 464 465 if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL || 466 avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) { 467 err = EEXIST; 468 goto done; 469 } 470 471 avl_insert(&dlmgmt_name_avl, linkp, name_where); 472 avl_insert(&dlmgmt_id_avl, linkp, id_where); 473 474 if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) { 475 avl_remove(&dlmgmt_name_avl, linkp); 476 avl_remove(&dlmgmt_id_avl, linkp); 477 goto done; 478 } 479 480 linkp->ll_flags = flags; 481 dlmgmt_advance(linkp); 482 *linkpp = linkp; 483 484 done: 485 if (err != 0) 486 free(linkp); 487 return (err); 488 } 489 490 int 491 dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags) 492 { 493 if ((linkp->ll_flags & flags) == 0) { 494 /* 495 * The link does not exist in the specified space. 496 */ 497 return (ENOENT); 498 } 499 500 linkp->ll_flags &= ~flags; 501 if (flags & DLMGMT_PERSIST) { 502 dlmgmt_linkattr_t *next, *attrp; 503 504 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 505 next = attrp->lp_next; 506 free(attrp->lp_val); 507 free(attrp); 508 } 509 linkp->ll_head = NULL; 510 } 511 512 if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) { 513 (void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid); 514 if (linkp->ll_onloan) 515 avl_remove(&dlmgmt_loan_avl, linkp); 516 } 517 518 if (linkp->ll_flags == 0) { 519 avl_remove(&dlmgmt_id_avl, linkp); 520 avl_remove(&dlmgmt_name_avl, linkp); 521 link_destroy(linkp); 522 } 523 524 return (0); 525 } 526 527 int 528 dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr, 529 dlmgmt_getattr_retval_t *retvalp) 530 { 531 int err; 532 void *attrval; 533 size_t attrsz; 534 dladm_datatype_t attrtype; 535 536 err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype); 537 if (err != 0) 538 return (err); 539 540 assert(attrsz > 0); 541 if (attrsz > MAXLINKATTRVALLEN) 542 return (EINVAL); 543 544 retvalp->lr_type = attrtype; 545 retvalp->lr_attrsz = attrsz; 546 bcopy(attrval, retvalp->lr_attrval, attrsz); 547 return (0); 548 } 549 550 void 551 dlmgmt_dlconf_table_lock(boolean_t write) 552 { 553 if (write) 554 (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock); 555 else 556 (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock); 557 } 558 559 void 560 dlmgmt_dlconf_table_unlock(void) 561 { 562 (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock); 563 } 564 565 int 566 dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class, 567 uint32_t media, zoneid_t zoneid, dlmgmt_dlconf_t **dlconfpp) 568 { 569 dlmgmt_dlconf_t *dlconfp = NULL; 570 int err = 0; 571 572 if (dlmgmt_nextconfid == 0) { 573 err = ENOSPC; 574 goto done; 575 } 576 577 if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) { 578 err = ENOMEM; 579 goto done; 580 } 581 582 (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN); 583 dlconfp->ld_linkid = linkid; 584 dlconfp->ld_class = class; 585 dlconfp->ld_media = media; 586 dlconfp->ld_id = dlmgmt_nextconfid; 587 dlconfp->ld_zoneid = zoneid; 588 589 done: 590 *dlconfpp = dlconfp; 591 return (err); 592 } 593 594 void 595 dlconf_destroy(dlmgmt_dlconf_t *dlconfp) 596 { 597 dlmgmt_linkattr_t *next, *attrp; 598 599 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) { 600 next = attrp->lp_next; 601 free(attrp->lp_val); 602 free(attrp); 603 } 604 free(dlconfp); 605 } 606 607 int 608 dlmgmt_generate_name(const char *prefix, char *name, size_t size, 609 zoneid_t zoneid) 610 { 611 dlmgmt_prefix_t *lpp, *prev = NULL; 612 dlmgmt_link_t link, *linkp; 613 614 /* 615 * See whether the requested prefix is already in the list. 616 */ 617 for (lpp = &dlmgmt_prefixlist; lpp != NULL; 618 prev = lpp, lpp = lpp->lp_next) { 619 if (lpp->lp_zoneid == zoneid && 620 strcmp(prefix, lpp->lp_prefix) == 0) 621 break; 622 } 623 624 /* 625 * Not found. 626 */ 627 if (lpp == NULL) { 628 assert(prev != NULL); 629 630 /* 631 * First add this new prefix into the prefix list. 632 */ 633 if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL) 634 return (ENOMEM); 635 636 prev->lp_next = lpp; 637 lpp->lp_next = NULL; 638 lpp->lp_zoneid = zoneid; 639 lpp->lp_nextppa = 0; 640 (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN); 641 642 /* 643 * Now determine this prefix's nextppa. 644 */ 645 (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d", 646 prefix, 0); 647 link.ll_zoneid = zoneid; 648 if ((linkp = avl_find(&dlmgmt_name_avl, &link, NULL)) != NULL) 649 dlmgmt_advance_ppa(linkp); 650 } 651 652 if (lpp->lp_nextppa == (uint_t)-1) 653 return (ENOSPC); 654 655 (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa); 656 return (0); 657 } 658 659 /* 660 * Advance the next available ppa value if the name prefix of the current 661 * link is in the prefix list. 662 */ 663 static void 664 dlmgmt_advance_ppa(dlmgmt_link_t *linkp) 665 { 666 dlmgmt_prefix_t *lpp; 667 char prefix[MAXLINKNAMELEN]; 668 char linkname[MAXLINKNAMELEN]; 669 uint_t start, ppa; 670 671 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 672 673 /* 674 * See whether the requested prefix is already in the list. 675 */ 676 for (lpp = &dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) { 677 if (lpp->lp_zoneid == linkp->ll_zoneid && 678 strcmp(prefix, lpp->lp_prefix) == 0) 679 break; 680 } 681 682 /* 683 * If the link name prefix is in the list, advance the 684 * next available ppa for the <prefix>N name. 685 */ 686 if (lpp == NULL || lpp->lp_nextppa != ppa) 687 return; 688 689 start = lpp->lp_nextppa++; 690 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 691 while (lpp->lp_nextppa != start) { 692 if (lpp->lp_nextppa == (uint_t)-1) { 693 /* 694 * wrapped around. search from <prefix>1. 695 */ 696 lpp->lp_nextppa = 0; 697 (void) snprintf(linkname, MAXLINKNAMELEN, 698 "%s%d", lpp->lp_prefix, lpp->lp_nextppa); 699 linkp = link_by_name(linkname, lpp->lp_zoneid); 700 if (linkp == NULL) 701 return; 702 } else { 703 if (linkp == NULL) 704 return; 705 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 706 if ((strcmp(prefix, lpp->lp_prefix) != 0) || 707 (ppa != lpp->lp_nextppa)) { 708 return; 709 } 710 } 711 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 712 lpp->lp_nextppa++; 713 } 714 lpp->lp_nextppa = (uint_t)-1; 715 } 716 717 /* 718 * Advance to the next available linkid value. 719 */ 720 static void 721 dlmgmt_advance_linkid(dlmgmt_link_t *linkp) 722 { 723 datalink_id_t start; 724 725 if (linkp->ll_linkid != dlmgmt_nextlinkid) 726 return; 727 728 start = dlmgmt_nextlinkid; 729 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 730 731 do { 732 if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) { 733 /* 734 * wrapped around. search from 1. 735 */ 736 dlmgmt_nextlinkid = 1; 737 if ((linkp = link_by_id(1, GLOBAL_ZONEID)) == NULL) 738 return; 739 } else { 740 dlmgmt_nextlinkid++; 741 if (linkp == NULL) 742 return; 743 if (linkp->ll_linkid != dlmgmt_nextlinkid) 744 return; 745 } 746 747 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 748 } while (dlmgmt_nextlinkid != start); 749 750 dlmgmt_nextlinkid = DATALINK_INVALID_LINKID; 751 } 752 753 /* 754 * Advance various global values, for example, next linkid value, next ppa for 755 * various prefix etc. 756 */ 757 void 758 dlmgmt_advance(dlmgmt_link_t *linkp) 759 { 760 dlmgmt_advance_linkid(linkp); 761 dlmgmt_advance_ppa(linkp); 762 } 763 764 /* 765 * Advance to the next available dlconf id. 766 */ 767 void 768 dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp) 769 { 770 uint_t start; 771 772 start = dlmgmt_nextconfid++; 773 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp); 774 while (dlmgmt_nextconfid != start) { 775 if (dlmgmt_nextconfid == 0) { 776 dlmgmt_dlconf_t dlconf; 777 778 /* 779 * wrapped around. search from 1. 780 */ 781 dlconf.ld_id = dlmgmt_nextconfid = 1; 782 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL); 783 if (dlconfp == NULL) 784 return; 785 } else { 786 if ((dlconfp == NULL) || 787 (dlconfp->ld_id != dlmgmt_nextconfid)) { 788 return; 789 } 790 } 791 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp); 792 dlmgmt_nextconfid++; 793 } 794 dlmgmt_nextconfid = 0; 795 } 796