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