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