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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Utility functions used by the dlmgmtd daemon. 29 */ 30 31 #include <assert.h> 32 #include <pthread.h> 33 #include <stddef.h> 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <strings.h> 37 #include <syslog.h> 38 #include <stdarg.h> 39 #include <libdlpi.h> 40 #include "dlmgmt_impl.h" 41 42 /* 43 * There are two datalink AVL tables. One table (dlmgmt_name_avl) is keyed by 44 * the link name, and the other (dlmgmt_id_avl) is keyed by the link id. 45 * Each link will be present in both tables. 46 */ 47 avl_tree_t dlmgmt_name_avl; 48 avl_tree_t dlmgmt_id_avl; 49 50 avl_tree_t dlmgmt_dlconf_avl; 51 52 static pthread_rwlock_t dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER; 53 static pthread_mutex_t dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER; 54 static pthread_cond_t dlmgmt_avl_cv = PTHREAD_COND_INITIALIZER; 55 static pthread_rwlock_t dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER; 56 57 typedef struct dlmgmt_prefix { 58 struct dlmgmt_prefix *lp_next; 59 char lp_prefix[MAXLINKNAMELEN]; 60 uint_t lp_nextppa; 61 } dlmgmt_prefix_t; 62 static dlmgmt_prefix_t *dlmgmt_prefixlist; 63 64 static datalink_id_t dlmgmt_nextlinkid; 65 static datalink_id_t dlmgmt_nextconfid = 1; 66 67 static int linkattr_add(dlmgmt_linkattr_t **, 68 dlmgmt_linkattr_t *); 69 static int linkattr_rm(dlmgmt_linkattr_t **, 70 dlmgmt_linkattr_t *); 71 static int link_create(const char *, datalink_class_t, uint32_t, 72 uint32_t, dlmgmt_link_t **); 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 static int 104 cmp_link_by_id(const void *v1, const void *v2) 105 { 106 const dlmgmt_link_t *link1 = v1; 107 const dlmgmt_link_t *link2 = v2; 108 109 if ((uint64_t)(link1->ll_linkid) == (uint64_t)(link2->ll_linkid)) 110 return (0); 111 else if ((uint64_t)(link1->ll_linkid) < (uint64_t)(link2->ll_linkid)) 112 return (-1); 113 else 114 return (1); 115 } 116 117 static int 118 cmp_dlconf_by_id(const void *v1, const void *v2) 119 { 120 const dlmgmt_dlconf_t *dlconfp1 = v1; 121 const dlmgmt_dlconf_t *dlconfp2 = v2; 122 123 if (dlconfp1->ld_id == dlconfp2->ld_id) 124 return (0); 125 else if (dlconfp1->ld_id < dlconfp2->ld_id) 126 return (-1); 127 else 128 return (1); 129 } 130 131 int 132 dlmgmt_linktable_init() 133 { 134 /* 135 * Initialize the prefix list. First add the "net" prefix to the list. 136 */ 137 dlmgmt_prefixlist = malloc(sizeof (dlmgmt_prefix_t)); 138 if (dlmgmt_prefixlist == NULL) { 139 dlmgmt_log(LOG_WARNING, "dlmgmt_linktable_init() failed: %s", 140 strerror(ENOMEM)); 141 return (ENOMEM); 142 } 143 144 dlmgmt_prefixlist->lp_next = NULL; 145 dlmgmt_prefixlist->lp_nextppa = 0; 146 (void) strlcpy(dlmgmt_prefixlist->lp_prefix, "net", MAXLINKNAMELEN); 147 148 avl_create(&dlmgmt_name_avl, cmp_link_by_name, sizeof (dlmgmt_link_t), 149 offsetof(dlmgmt_link_t, ll_node_by_name)); 150 avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t), 151 offsetof(dlmgmt_link_t, ll_node_by_id)); 152 avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id, 153 sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node)); 154 dlmgmt_nextlinkid = 1; 155 return (0); 156 } 157 158 void 159 dlmgmt_linktable_fini() 160 { 161 dlmgmt_prefix_t *lpp, *next; 162 163 for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = next) { 164 next = lpp->lp_next; 165 free(lpp); 166 } 167 168 avl_destroy(&dlmgmt_dlconf_avl); 169 avl_destroy(&dlmgmt_name_avl); 170 avl_destroy(&dlmgmt_id_avl); 171 } 172 173 static int 174 linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp) 175 { 176 if (*headp == NULL) { 177 *headp = attrp; 178 } else { 179 (*headp)->lp_prev = attrp; 180 attrp->lp_next = *headp; 181 *headp = attrp; 182 } 183 return (0); 184 } 185 186 static int 187 linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp) 188 { 189 dlmgmt_linkattr_t *next, *prev; 190 191 next = attrp->lp_next; 192 prev = attrp->lp_prev; 193 if (next != NULL) 194 next->lp_prev = prev; 195 if (prev != NULL) 196 prev->lp_next = next; 197 else 198 *headp = next; 199 200 return (0); 201 } 202 203 int 204 linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval, 205 size_t attrsz, dladm_datatype_t type) 206 { 207 dlmgmt_linkattr_t *attrp; 208 int err; 209 210 /* 211 * See whether the attr is already set. 212 */ 213 for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) { 214 if (strcmp(attrp->lp_name, attr) == 0) 215 break; 216 } 217 218 if (attrp != NULL) { 219 /* 220 * It is already set. If the value changed, update it. 221 */ 222 if (linkattr_equal(headp, attr, attrval, attrsz)) 223 return (0); 224 225 free(attrp->lp_val); 226 } else { 227 /* 228 * It is not set yet, allocate the linkattr and prepend to the 229 * list. 230 */ 231 if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL) 232 return (ENOMEM); 233 234 if ((err = linkattr_add(headp, attrp)) != 0) { 235 free(attrp); 236 return (err); 237 } 238 (void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN); 239 } 240 if ((attrp->lp_val = calloc(1, attrsz)) == NULL) { 241 (void) linkattr_rm(headp, attrp); 242 free(attrp); 243 return (ENOMEM); 244 } 245 246 bcopy(attrval, attrp->lp_val, attrsz); 247 attrp->lp_sz = attrsz; 248 attrp->lp_type = type; 249 attrp->lp_linkprop = dladm_attr_is_linkprop(attr); 250 return (0); 251 } 252 253 int 254 linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr) 255 { 256 dlmgmt_linkattr_t *attrp, *prev; 257 258 /* 259 * See whether the attr exists. 260 */ 261 for (prev = NULL, attrp = *headp; attrp != NULL; 262 prev = attrp, attrp = attrp->lp_next) { 263 if (strcmp(attrp->lp_name, attr) == 0) 264 break; 265 } 266 267 /* 268 * This attribute is not set in the first place. Return success. 269 */ 270 if (attrp == NULL) 271 return (0); 272 273 /* 274 * Remove this attr from the list. 275 */ 276 if (prev == NULL) 277 *headp = attrp->lp_next; 278 else 279 prev->lp_next = attrp->lp_next; 280 281 free(attrp->lp_val); 282 free(attrp); 283 return (0); 284 } 285 286 int 287 linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp, 288 size_t *attrszp, dladm_datatype_t *typep) 289 { 290 dlmgmt_linkattr_t *attrp = *headp; 291 292 /* 293 * find the specific attr. 294 */ 295 for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) { 296 if (strcmp(attrp->lp_name, attr) == 0) 297 break; 298 } 299 300 if (attrp == NULL) 301 return (ENOENT); 302 303 *attrvalp = attrp->lp_val; 304 *attrszp = attrp->lp_sz; 305 if (typep != NULL) 306 *typep = attrp->lp_type; 307 return (0); 308 } 309 310 int 311 linkprop_getnext(dlmgmt_linkattr_t **headp, const char *lastattr, 312 char **attrnamep, void **attrvalp, size_t *attrszp, dladm_datatype_t *typep) 313 { 314 dlmgmt_linkattr_t *attrp; 315 316 /* skip to entry following lastattr or pick first if none specified */ 317 for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) { 318 if (!attrp->lp_linkprop) 319 continue; 320 if (lastattr[0] == '\0') 321 break; 322 if (strcmp(attrp->lp_name, lastattr) == 0) { 323 attrp = attrp->lp_next; 324 break; 325 } 326 } 327 if (attrp == NULL) 328 return (ENOENT); 329 330 *attrnamep = attrp->lp_name; 331 *attrvalp = attrp->lp_val; 332 *attrszp = attrp->lp_sz; 333 *typep = attrp->lp_type; 334 return (0); 335 } 336 337 boolean_t 338 linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval, 339 size_t attrsz) 340 { 341 void *saved_attrval; 342 size_t saved_attrsz; 343 344 if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0) 345 return (B_FALSE); 346 347 return ((saved_attrsz == attrsz) && 348 (memcmp(saved_attrval, attrval, attrsz) == 0)); 349 } 350 351 static int 352 dlmgmt_table_readwritelock(boolean_t write) 353 { 354 if (write) 355 return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock)); 356 else 357 return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock)); 358 } 359 360 void 361 dlmgmt_table_lock(boolean_t write) 362 { 363 (void) pthread_mutex_lock(&dlmgmt_avl_mutex); 364 while (dlmgmt_table_readwritelock(write) == EBUSY) 365 (void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex); 366 367 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex); 368 } 369 370 void 371 dlmgmt_table_unlock() 372 { 373 (void) pthread_rwlock_unlock(&dlmgmt_avl_lock); 374 (void) pthread_mutex_lock(&dlmgmt_avl_mutex); 375 (void) pthread_cond_broadcast(&dlmgmt_avl_cv); 376 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex); 377 } 378 379 static int 380 link_create(const char *name, datalink_class_t class, uint32_t media, 381 uint32_t flags, dlmgmt_link_t **linkpp) 382 { 383 dlmgmt_link_t *linkp = NULL; 384 int err = 0; 385 386 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID) { 387 err = ENOSPC; 388 goto done; 389 } 390 391 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) { 392 err = ENOMEM; 393 goto done; 394 } 395 396 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN); 397 linkp->ll_class = class; 398 linkp->ll_media = media; 399 linkp->ll_linkid = dlmgmt_nextlinkid; 400 linkp->ll_flags = flags; 401 linkp->ll_gen = 0; 402 done: 403 *linkpp = linkp; 404 return (err); 405 } 406 407 void 408 link_destroy(dlmgmt_link_t *linkp) 409 { 410 dlmgmt_linkattr_t *next, *attrp; 411 412 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 413 next = attrp->lp_next; 414 free(attrp->lp_val); 415 free(attrp); 416 } 417 free(linkp); 418 } 419 420 dlmgmt_link_t * 421 link_by_id(datalink_id_t linkid) 422 { 423 dlmgmt_link_t link; 424 425 link.ll_linkid = linkid; 426 return (avl_find(&dlmgmt_id_avl, &link, NULL)); 427 } 428 429 dlmgmt_link_t * 430 link_by_name(const char *name) 431 { 432 dlmgmt_link_t link; 433 434 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN); 435 return (avl_find(&dlmgmt_name_avl, &link, NULL)); 436 } 437 438 int 439 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media, 440 uint32_t flags, dlmgmt_link_t **linkpp) 441 { 442 dlmgmt_link_t link, *linkp, *tmp; 443 avl_index_t name_where, id_where; 444 int err; 445 446 /* 447 * Validate the link. 448 */ 449 if (!dladm_valid_linkname(name)) 450 return (EINVAL); 451 452 /* 453 * Check to see whether this is an existing link name. 454 */ 455 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN); 456 if ((linkp = avl_find(&dlmgmt_name_avl, &link, &name_where)) != NULL) 457 return (EEXIST); 458 459 if ((err = link_create(name, class, media, flags, &linkp)) != 0) 460 return (err); 461 462 link.ll_linkid = linkp->ll_linkid; 463 tmp = avl_find(&dlmgmt_id_avl, &link, &id_where); 464 assert(tmp == NULL); 465 avl_insert(&dlmgmt_name_avl, linkp, name_where); 466 avl_insert(&dlmgmt_id_avl, linkp, id_where); 467 dlmgmt_advance(linkp); 468 *linkpp = linkp; 469 return (0); 470 } 471 472 int 473 dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags) 474 { 475 if ((linkp->ll_flags & flags) == 0) { 476 /* 477 * The link does not exist in the specified space. 478 */ 479 return (ENOENT); 480 } 481 linkp->ll_flags &= ~flags; 482 if (!(linkp->ll_flags & DLMGMT_PERSIST)) { 483 dlmgmt_linkattr_t *next, *attrp; 484 485 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 486 next = attrp->lp_next; 487 free(attrp->lp_val); 488 free(attrp); 489 } 490 linkp->ll_head = NULL; 491 } 492 493 if (linkp->ll_flags == 0) { 494 avl_remove(&dlmgmt_id_avl, linkp); 495 avl_remove(&dlmgmt_name_avl, linkp); 496 link_destroy(linkp); 497 } 498 499 return (0); 500 } 501 502 void 503 dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr, 504 dlmgmt_getattr_retval_t *retvalp) 505 { 506 int err; 507 void *attrval; 508 size_t attrsz; 509 dladm_datatype_t attrtype; 510 511 err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype); 512 if (err != 0) 513 goto done; 514 515 assert(attrsz > 0); 516 if (attrsz > MAXLINKATTRVALLEN) { 517 err = EINVAL; 518 goto done; 519 } 520 521 retvalp->lr_type = attrtype; 522 retvalp->lr_attrsz = attrsz; 523 bcopy(attrval, retvalp->lr_attrval, attrsz); 524 done: 525 retvalp->lr_err = err; 526 } 527 528 void 529 dlmgmt_dlconf_table_lock(boolean_t write) 530 { 531 if (write) 532 (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock); 533 else 534 (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock); 535 } 536 537 void 538 dlmgmt_dlconf_table_unlock() 539 { 540 (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock); 541 } 542 543 int 544 dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class, 545 uint32_t media, dlmgmt_dlconf_t **dlconfpp) 546 { 547 dlmgmt_dlconf_t *dlconfp = NULL; 548 int err = 0; 549 550 if (dlmgmt_nextconfid == 0) { 551 err = ENOSPC; 552 goto done; 553 } 554 555 if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) { 556 err = ENOMEM; 557 goto done; 558 } 559 560 (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN); 561 dlconfp->ld_linkid = linkid; 562 dlconfp->ld_class = class; 563 dlconfp->ld_media = media; 564 dlconfp->ld_id = dlmgmt_nextconfid; 565 566 done: 567 *dlconfpp = dlconfp; 568 return (err); 569 } 570 571 void 572 dlconf_destroy(dlmgmt_dlconf_t *dlconfp) 573 { 574 dlmgmt_linkattr_t *next, *attrp; 575 576 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) { 577 next = attrp->lp_next; 578 free(attrp->lp_val); 579 free(attrp); 580 } 581 free(dlconfp); 582 } 583 584 int 585 dlmgmt_generate_name(const char *prefix, char *name, size_t size) 586 { 587 dlmgmt_prefix_t *lpp, *prev = NULL; 588 589 /* 590 * See whether the requested prefix is already in the list. 591 */ 592 for (lpp = dlmgmt_prefixlist; lpp != NULL; prev = lpp, 593 lpp = lpp->lp_next) { 594 if (strcmp(prefix, lpp->lp_prefix) == 0) 595 break; 596 } 597 598 /* 599 * Not found. 600 */ 601 if (lpp == NULL) { 602 dlmgmt_link_t *linkp, link; 603 604 assert(prev != NULL); 605 606 /* 607 * First add this new prefix into the prefix list. 608 */ 609 if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL) 610 return (ENOMEM); 611 612 prev->lp_next = lpp; 613 lpp->lp_next = NULL; 614 lpp->lp_nextppa = 0; 615 (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN); 616 617 /* 618 * Now determine this prefix's nextppa. 619 */ 620 (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d", 621 prefix, lpp->lp_nextppa); 622 linkp = avl_find(&dlmgmt_name_avl, &link, NULL); 623 if (linkp != NULL) 624 dlmgmt_advance_ppa(linkp); 625 } 626 627 if (lpp->lp_nextppa == (uint_t)-1) 628 return (ENOSPC); 629 630 (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa); 631 return (0); 632 } 633 634 /* 635 * Advance the next available ppa value if the name prefix of the current 636 * link is in the prefix list. 637 */ 638 static void 639 dlmgmt_advance_ppa(dlmgmt_link_t *linkp) 640 { 641 dlmgmt_prefix_t *lpp; 642 char prefix[MAXLINKNAMELEN]; 643 uint_t start, ppa; 644 645 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 646 647 /* 648 * See whether the requested prefix is already in the list. 649 */ 650 for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) { 651 if (strcmp(prefix, lpp->lp_prefix) == 0) 652 break; 653 } 654 655 /* 656 * If the link name prefix is in the list, advance the 657 * next available ppa for the <prefix>N name. 658 */ 659 if (lpp == NULL || lpp->lp_nextppa != ppa) 660 return; 661 662 start = lpp->lp_nextppa++; 663 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 664 while (lpp->lp_nextppa != start) { 665 if (lpp->lp_nextppa == (uint_t)-1) { 666 dlmgmt_link_t link; 667 668 /* 669 * wrapped around. search from <prefix>1. 670 */ 671 lpp->lp_nextppa = 0; 672 (void) snprintf(link.ll_link, MAXLINKNAMELEN, 673 "%s%d", lpp->lp_prefix, lpp->lp_nextppa); 674 linkp = avl_find(&dlmgmt_name_avl, &link, NULL); 675 if (linkp == NULL) 676 return; 677 } else { 678 if (linkp == NULL) 679 return; 680 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 681 if ((strcmp(prefix, lpp->lp_prefix) != 0) || 682 (ppa != lpp->lp_nextppa)) { 683 return; 684 } 685 } 686 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 687 lpp->lp_nextppa++; 688 } 689 lpp->lp_nextppa = (uint_t)-1; 690 } 691 692 /* 693 * Advance to the next available linkid value. 694 */ 695 static void 696 dlmgmt_advance_linkid(dlmgmt_link_t *linkp) 697 { 698 datalink_id_t start; 699 700 if (linkp->ll_linkid != dlmgmt_nextlinkid) 701 return; 702 703 start = dlmgmt_nextlinkid; 704 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 705 706 do { 707 if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) { 708 dlmgmt_link_t link; 709 710 /* 711 * wrapped around. search from 1. 712 */ 713 dlmgmt_nextlinkid = 1; 714 link.ll_linkid = 1; 715 linkp = avl_find(&dlmgmt_id_avl, &link, NULL); 716 if (linkp == NULL) 717 return; 718 } else { 719 dlmgmt_nextlinkid++; 720 if (linkp == NULL) 721 return; 722 if (linkp->ll_linkid != dlmgmt_nextlinkid) 723 return; 724 } 725 726 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 727 } while (dlmgmt_nextlinkid != start); 728 729 dlmgmt_nextlinkid = DATALINK_INVALID_LINKID; 730 } 731 732 /* 733 * Advance various global values, for example, next linkid value, next ppa for 734 * various prefix etc. 735 */ 736 void 737 dlmgmt_advance(dlmgmt_link_t *linkp) 738 { 739 dlmgmt_advance_linkid(linkp); 740 dlmgmt_advance_ppa(linkp); 741 } 742 743 /* 744 * Advance to the next available dlconf id. 745 */ 746 void 747 dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp) 748 { 749 uint_t start; 750 751 start = dlmgmt_nextconfid++; 752 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp); 753 while (dlmgmt_nextconfid != start) { 754 if (dlmgmt_nextconfid == 0) { 755 dlmgmt_dlconf_t dlconf; 756 757 /* 758 * wrapped around. search from 1. 759 */ 760 dlconf.ld_id = dlmgmt_nextconfid = 1; 761 dlconfp = avl_find(&dlmgmt_name_avl, &dlconf, NULL); 762 if (dlconfp == NULL) 763 return; 764 } else { 765 if ((dlconfp == NULL) || 766 (dlconfp->ld_id != dlmgmt_nextconfid)) { 767 return; 768 } 769 } 770 dlconfp = AVL_NEXT(&dlmgmt_name_avl, dlconfp); 771 dlmgmt_nextconfid++; 772 } 773 dlmgmt_nextconfid = 0; 774 } 775