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; 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 avl_remove(&dlmgmt_name_avl, linkp); 383 linkp->ll_zoneid = zoneid; 384 avl_add(&dlmgmt_name_avl, linkp); 385 avl_add(&dlmgmt_loan_avl, linkp); 386 linkp->ll_onloan = B_TRUE; 387 } 388 } else if (linkp->ll_zoneid != GLOBAL_ZONEID) { 389 err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid); 390 } 391 done: 392 if (err == 0) 393 linkp->ll_flags |= DLMGMT_ACTIVE; 394 return (err); 395 } 396 397 /* 398 * Is linkp visible from the caller's zoneid? It is if the link is in the 399 * same zone as the caller, or if the caller is in the global zone and the 400 * link is on loan to a non-global zone. 401 */ 402 boolean_t 403 link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid) 404 { 405 return (linkp->ll_zoneid == zoneid || 406 (zoneid == GLOBAL_ZONEID && linkp->ll_onloan)); 407 } 408 409 dlmgmt_link_t * 410 link_by_id(datalink_id_t linkid, zoneid_t zoneid) 411 { 412 dlmgmt_link_t link, *linkp; 413 414 link.ll_linkid = linkid; 415 linkp = avl_find(&dlmgmt_id_avl, &link, NULL); 416 if (zoneid != GLOBAL_ZONEID && linkp->ll_zoneid != zoneid) 417 linkp = NULL; 418 return (linkp); 419 } 420 421 dlmgmt_link_t * 422 link_by_name(const char *name, zoneid_t zoneid) 423 { 424 dlmgmt_link_t link, *linkp; 425 426 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN); 427 link.ll_zoneid = zoneid; 428 linkp = avl_find(&dlmgmt_name_avl, &link, NULL); 429 if (linkp == NULL && zoneid == GLOBAL_ZONEID) { 430 /* The link could be on loan to a non-global zone? */ 431 linkp = avl_find(&dlmgmt_loan_avl, &link, NULL); 432 } 433 return (linkp); 434 } 435 436 int 437 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media, 438 zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp) 439 { 440 dlmgmt_link_t *linkp = NULL; 441 avl_index_t name_where, id_where; 442 int err = 0; 443 444 if (!dladm_valid_linkname(name)) 445 return (EINVAL); 446 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID) 447 return (ENOSPC); 448 449 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) { 450 err = ENOMEM; 451 goto done; 452 } 453 454 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN); 455 linkp->ll_class = class; 456 linkp->ll_media = media; 457 linkp->ll_linkid = dlmgmt_nextlinkid; 458 linkp->ll_zoneid = zoneid; 459 linkp->ll_gen = 0; 460 461 if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL || 462 avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) { 463 err = EEXIST; 464 goto done; 465 } 466 467 avl_insert(&dlmgmt_name_avl, linkp, name_where); 468 avl_insert(&dlmgmt_id_avl, linkp, id_where); 469 470 if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) { 471 avl_remove(&dlmgmt_name_avl, linkp); 472 avl_remove(&dlmgmt_id_avl, linkp); 473 goto done; 474 } 475 476 linkp->ll_flags = flags; 477 dlmgmt_advance(linkp); 478 *linkpp = linkp; 479 480 done: 481 if (err != 0) 482 free(linkp); 483 return (err); 484 } 485 486 int 487 dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags) 488 { 489 if ((linkp->ll_flags & flags) == 0) { 490 /* 491 * The link does not exist in the specified space. 492 */ 493 return (ENOENT); 494 } 495 496 linkp->ll_flags &= ~flags; 497 if (flags & DLMGMT_PERSIST) { 498 dlmgmt_linkattr_t *next, *attrp; 499 500 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 501 next = attrp->lp_next; 502 free(attrp->lp_val); 503 free(attrp); 504 } 505 linkp->ll_head = NULL; 506 } 507 508 if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) { 509 (void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid); 510 if (linkp->ll_onloan) 511 avl_remove(&dlmgmt_loan_avl, linkp); 512 } 513 514 if (linkp->ll_flags == 0) { 515 avl_remove(&dlmgmt_id_avl, linkp); 516 avl_remove(&dlmgmt_name_avl, linkp); 517 link_destroy(linkp); 518 } 519 520 return (0); 521 } 522 523 int 524 dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr, 525 dlmgmt_getattr_retval_t *retvalp) 526 { 527 int err; 528 void *attrval; 529 size_t attrsz; 530 dladm_datatype_t attrtype; 531 532 err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype); 533 if (err != 0) 534 return (err); 535 536 assert(attrsz > 0); 537 if (attrsz > MAXLINKATTRVALLEN) 538 return (EINVAL); 539 540 retvalp->lr_type = attrtype; 541 retvalp->lr_attrsz = attrsz; 542 bcopy(attrval, retvalp->lr_attrval, attrsz); 543 return (0); 544 } 545 546 void 547 dlmgmt_dlconf_table_lock(boolean_t write) 548 { 549 if (write) 550 (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock); 551 else 552 (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock); 553 } 554 555 void 556 dlmgmt_dlconf_table_unlock(void) 557 { 558 (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock); 559 } 560 561 int 562 dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class, 563 uint32_t media, zoneid_t zoneid, dlmgmt_dlconf_t **dlconfpp) 564 { 565 dlmgmt_dlconf_t *dlconfp = NULL; 566 int err = 0; 567 568 if (dlmgmt_nextconfid == 0) { 569 err = ENOSPC; 570 goto done; 571 } 572 573 if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) { 574 err = ENOMEM; 575 goto done; 576 } 577 578 (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN); 579 dlconfp->ld_linkid = linkid; 580 dlconfp->ld_class = class; 581 dlconfp->ld_media = media; 582 dlconfp->ld_id = dlmgmt_nextconfid; 583 dlconfp->ld_zoneid = zoneid; 584 585 done: 586 *dlconfpp = dlconfp; 587 return (err); 588 } 589 590 void 591 dlconf_destroy(dlmgmt_dlconf_t *dlconfp) 592 { 593 dlmgmt_linkattr_t *next, *attrp; 594 595 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) { 596 next = attrp->lp_next; 597 free(attrp->lp_val); 598 free(attrp); 599 } 600 free(dlconfp); 601 } 602 603 int 604 dlmgmt_generate_name(const char *prefix, char *name, size_t size, 605 zoneid_t zoneid) 606 { 607 dlmgmt_prefix_t *lpp, *prev = NULL; 608 dlmgmt_link_t link, *linkp; 609 610 /* 611 * See whether the requested prefix is already in the list. 612 */ 613 for (lpp = &dlmgmt_prefixlist; lpp != NULL; 614 prev = lpp, lpp = lpp->lp_next) { 615 if (lpp->lp_zoneid == zoneid && 616 strcmp(prefix, lpp->lp_prefix) == 0) 617 break; 618 } 619 620 /* 621 * Not found. 622 */ 623 if (lpp == NULL) { 624 assert(prev != NULL); 625 626 /* 627 * First add this new prefix into the prefix list. 628 */ 629 if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL) 630 return (ENOMEM); 631 632 prev->lp_next = lpp; 633 lpp->lp_next = NULL; 634 lpp->lp_zoneid = zoneid; 635 lpp->lp_nextppa = 0; 636 (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN); 637 638 /* 639 * Now determine this prefix's nextppa. 640 */ 641 (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d", 642 prefix, 0); 643 link.ll_zoneid = zoneid; 644 if ((linkp = avl_find(&dlmgmt_name_avl, &link, NULL)) != NULL) 645 dlmgmt_advance_ppa(linkp); 646 } 647 648 if (lpp->lp_nextppa == (uint_t)-1) 649 return (ENOSPC); 650 651 (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa); 652 return (0); 653 } 654 655 /* 656 * Advance the next available ppa value if the name prefix of the current 657 * link is in the prefix list. 658 */ 659 static void 660 dlmgmt_advance_ppa(dlmgmt_link_t *linkp) 661 { 662 dlmgmt_prefix_t *lpp; 663 char prefix[MAXLINKNAMELEN]; 664 char linkname[MAXLINKNAMELEN]; 665 uint_t start, ppa; 666 667 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 668 669 /* 670 * See whether the requested prefix is already in the list. 671 */ 672 for (lpp = &dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) { 673 if (lpp->lp_zoneid == linkp->ll_zoneid && 674 strcmp(prefix, lpp->lp_prefix) == 0) 675 break; 676 } 677 678 /* 679 * If the link name prefix is in the list, advance the 680 * next available ppa for the <prefix>N name. 681 */ 682 if (lpp == NULL || lpp->lp_nextppa != ppa) 683 return; 684 685 start = lpp->lp_nextppa++; 686 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 687 while (lpp->lp_nextppa != start) { 688 if (lpp->lp_nextppa == (uint_t)-1) { 689 /* 690 * wrapped around. search from <prefix>1. 691 */ 692 lpp->lp_nextppa = 0; 693 (void) snprintf(linkname, MAXLINKNAMELEN, 694 "%s%d", lpp->lp_prefix, lpp->lp_nextppa); 695 linkp = link_by_name(linkname, lpp->lp_zoneid); 696 if (linkp == NULL) 697 return; 698 } else { 699 if (linkp == NULL) 700 return; 701 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 702 if ((strcmp(prefix, lpp->lp_prefix) != 0) || 703 (ppa != lpp->lp_nextppa)) { 704 return; 705 } 706 } 707 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 708 lpp->lp_nextppa++; 709 } 710 lpp->lp_nextppa = (uint_t)-1; 711 } 712 713 /* 714 * Advance to the next available linkid value. 715 */ 716 static void 717 dlmgmt_advance_linkid(dlmgmt_link_t *linkp) 718 { 719 datalink_id_t start; 720 721 if (linkp->ll_linkid != dlmgmt_nextlinkid) 722 return; 723 724 start = dlmgmt_nextlinkid; 725 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 726 727 do { 728 if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) { 729 /* 730 * wrapped around. search from 1. 731 */ 732 dlmgmt_nextlinkid = 1; 733 if ((linkp = link_by_id(1, GLOBAL_ZONEID)) == NULL) 734 return; 735 } else { 736 dlmgmt_nextlinkid++; 737 if (linkp == NULL) 738 return; 739 if (linkp->ll_linkid != dlmgmt_nextlinkid) 740 return; 741 } 742 743 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 744 } while (dlmgmt_nextlinkid != start); 745 746 dlmgmt_nextlinkid = DATALINK_INVALID_LINKID; 747 } 748 749 /* 750 * Advance various global values, for example, next linkid value, next ppa for 751 * various prefix etc. 752 */ 753 void 754 dlmgmt_advance(dlmgmt_link_t *linkp) 755 { 756 dlmgmt_advance_linkid(linkp); 757 dlmgmt_advance_ppa(linkp); 758 } 759 760 /* 761 * Advance to the next available dlconf id. 762 */ 763 void 764 dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp) 765 { 766 uint_t start; 767 768 start = dlmgmt_nextconfid++; 769 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp); 770 while (dlmgmt_nextconfid != start) { 771 if (dlmgmt_nextconfid == 0) { 772 dlmgmt_dlconf_t dlconf; 773 774 /* 775 * wrapped around. search from 1. 776 */ 777 dlconf.ld_id = dlmgmt_nextconfid = 1; 778 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL); 779 if (dlconfp == NULL) 780 return; 781 } else { 782 if ((dlconfp == NULL) || 783 (dlconfp->ld_id != dlmgmt_nextconfid)) { 784 return; 785 } 786 } 787 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp); 788 dlmgmt_nextconfid++; 789 } 790 dlmgmt_nextconfid = 0; 791 } 792