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