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