xref: /titanic_51/usr/src/cmd/dlmgmtd/dlmgmt_util.c (revision c6d054cbc999e5c8b9ad1aa01dbb4800b84f06bd)
1d62bc4baSyz147064 /*
2d62bc4baSyz147064  * CDDL HEADER START
3d62bc4baSyz147064  *
4d62bc4baSyz147064  * The contents of this file are subject to the terms of the
5d62bc4baSyz147064  * Common Development and Distribution License (the "License").
6d62bc4baSyz147064  * You may not use this file except in compliance with the License.
7d62bc4baSyz147064  *
8d62bc4baSyz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz147064  * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz147064  * See the License for the specific language governing permissions
11d62bc4baSyz147064  * and limitations under the License.
12d62bc4baSyz147064  *
13d62bc4baSyz147064  * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz147064  * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz147064  * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz147064  *
19d62bc4baSyz147064  * CDDL HEADER END
20d62bc4baSyz147064  */
21d62bc4baSyz147064 
22d62bc4baSyz147064 /*
2332715170SCathy Zhou  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24d62bc4baSyz147064  */
25d62bc4baSyz147064 
26d62bc4baSyz147064 /*
27d62bc4baSyz147064  * Utility functions used by the dlmgmtd daemon.
28d62bc4baSyz147064  */
29d62bc4baSyz147064 
30d62bc4baSyz147064 #include <assert.h>
31d62bc4baSyz147064 #include <pthread.h>
32d62bc4baSyz147064 #include <stddef.h>
33d62bc4baSyz147064 #include <stdlib.h>
34d62bc4baSyz147064 #include <stdio.h>
352b24ab6bSSebastien Roy #include <errno.h>
36d62bc4baSyz147064 #include <strings.h>
372b24ab6bSSebastien Roy #include <string.h>
38d62bc4baSyz147064 #include <syslog.h>
39d62bc4baSyz147064 #include <stdarg.h>
402b24ab6bSSebastien Roy #include <zone.h>
4182a2fc47SJames Carlson #include <errno.h>
42d62bc4baSyz147064 #include <libdlpi.h>
43d62bc4baSyz147064 #include "dlmgmt_impl.h"
44d62bc4baSyz147064 
45d62bc4baSyz147064 /*
462b24ab6bSSebastien Roy  * There are three datalink AVL tables.  The dlmgmt_name_avl tree contains all
472b24ab6bSSebastien Roy  * datalinks and is keyed by zoneid and link name.  The dlmgmt_id_avl also
482b24ab6bSSebastien Roy  * contains all datalinks, and it is keyed by link ID.  The dlmgmt_loan_avl is
492b24ab6bSSebastien Roy  * keyed by link name, and contains the set of global-zone links that are
502b24ab6bSSebastien Roy  * currently on loan to non-global zones.
51d62bc4baSyz147064  */
52d62bc4baSyz147064 avl_tree_t	dlmgmt_name_avl;
53d62bc4baSyz147064 avl_tree_t	dlmgmt_id_avl;
542b24ab6bSSebastien Roy avl_tree_t	dlmgmt_loan_avl;
55d62bc4baSyz147064 
56d62bc4baSyz147064 avl_tree_t	dlmgmt_dlconf_avl;
57d62bc4baSyz147064 
58d62bc4baSyz147064 static pthread_rwlock_t	dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER;
59d62bc4baSyz147064 static pthread_mutex_t  dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER;
60d62bc4baSyz147064 static pthread_cond_t	dlmgmt_avl_cv = PTHREAD_COND_INITIALIZER;
61d62bc4baSyz147064 static pthread_rwlock_t	dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER;
62d62bc4baSyz147064 
63d62bc4baSyz147064 typedef struct dlmgmt_prefix {
64d62bc4baSyz147064 	struct dlmgmt_prefix	*lp_next;
65d62bc4baSyz147064 	char			lp_prefix[MAXLINKNAMELEN];
662b24ab6bSSebastien Roy 	zoneid_t		lp_zoneid;
67d62bc4baSyz147064 	uint_t			lp_nextppa;
68d62bc4baSyz147064 } dlmgmt_prefix_t;
692b24ab6bSSebastien Roy static dlmgmt_prefix_t	dlmgmt_prefixlist;
70d62bc4baSyz147064 
712b24ab6bSSebastien Roy datalink_id_t		dlmgmt_nextlinkid;
72d62bc4baSyz147064 static datalink_id_t	dlmgmt_nextconfid = 1;
73d62bc4baSyz147064 
74d62bc4baSyz147064 static void		dlmgmt_advance_linkid(dlmgmt_link_t *);
75d62bc4baSyz147064 static void		dlmgmt_advance_ppa(dlmgmt_link_t *);
76d62bc4baSyz147064 
77d62bc4baSyz147064 void
78d62bc4baSyz147064 dlmgmt_log(int pri, const char *fmt, ...)
79d62bc4baSyz147064 {
80d62bc4baSyz147064 	va_list alist;
81d62bc4baSyz147064 
82d62bc4baSyz147064 	va_start(alist, fmt);
83d62bc4baSyz147064 	if (debug) {
84d62bc4baSyz147064 		(void) vfprintf(stderr, fmt, alist);
85d62bc4baSyz147064 		(void) fputc('\n', stderr);
86d62bc4baSyz147064 	} else {
87d62bc4baSyz147064 		vsyslog(pri, fmt, alist);
88d62bc4baSyz147064 	}
89d62bc4baSyz147064 	va_end(alist);
90d62bc4baSyz147064 }
91d62bc4baSyz147064 
92d62bc4baSyz147064 static int
93d62bc4baSyz147064 cmp_link_by_name(const void *v1, const void *v2)
94d62bc4baSyz147064 {
95d62bc4baSyz147064 	const dlmgmt_link_t *link1 = v1;
96d62bc4baSyz147064 	const dlmgmt_link_t *link2 = v2;
97d62bc4baSyz147064 	int cmp;
98d62bc4baSyz147064 
99d62bc4baSyz147064 	cmp = strcmp(link1->ll_link, link2->ll_link);
100d62bc4baSyz147064 	return ((cmp == 0) ? 0 : ((cmp < 0) ? -1 : 1));
101d62bc4baSyz147064 }
102d62bc4baSyz147064 
1032b24ab6bSSebastien Roy /*
1042b24ab6bSSebastien Roy  * Note that the zoneid associated with a link is effectively part of its
1052b24ab6bSSebastien Roy  * name.  This is essentially what results in having each zone have disjoint
1062b24ab6bSSebastien Roy  * datalink namespaces.
1072b24ab6bSSebastien Roy  */
1082b24ab6bSSebastien Roy static int
1092b24ab6bSSebastien Roy cmp_link_by_zname(const void *v1, const void *v2)
1102b24ab6bSSebastien Roy {
1112b24ab6bSSebastien Roy 	const dlmgmt_link_t *link1 = v1;
1122b24ab6bSSebastien Roy 	const dlmgmt_link_t *link2 = v2;
1132b24ab6bSSebastien Roy 
1142b24ab6bSSebastien Roy 	if (link1->ll_zoneid < link2->ll_zoneid)
1152b24ab6bSSebastien Roy 		return (-1);
1162b24ab6bSSebastien Roy 	if (link1->ll_zoneid > link2->ll_zoneid)
1172b24ab6bSSebastien Roy 		return (1);
1182b24ab6bSSebastien Roy 	return (cmp_link_by_name(link1, link2));
1192b24ab6bSSebastien Roy }
1202b24ab6bSSebastien Roy 
121d62bc4baSyz147064 static int
122d62bc4baSyz147064 cmp_link_by_id(const void *v1, const void *v2)
123d62bc4baSyz147064 {
124d62bc4baSyz147064 	const dlmgmt_link_t *link1 = v1;
125d62bc4baSyz147064 	const dlmgmt_link_t *link2 = v2;
126d62bc4baSyz147064 
127d62bc4baSyz147064 	if ((uint64_t)(link1->ll_linkid) == (uint64_t)(link2->ll_linkid))
128d62bc4baSyz147064 		return (0);
129d62bc4baSyz147064 	else if ((uint64_t)(link1->ll_linkid) < (uint64_t)(link2->ll_linkid))
130d62bc4baSyz147064 		return (-1);
131d62bc4baSyz147064 	else
132d62bc4baSyz147064 		return (1);
133d62bc4baSyz147064 }
134d62bc4baSyz147064 
135d62bc4baSyz147064 static int
136d62bc4baSyz147064 cmp_dlconf_by_id(const void *v1, const void *v2)
137d62bc4baSyz147064 {
138d62bc4baSyz147064 	const dlmgmt_dlconf_t *dlconfp1 = v1;
139d62bc4baSyz147064 	const dlmgmt_dlconf_t *dlconfp2 = v2;
140d62bc4baSyz147064 
141d62bc4baSyz147064 	if (dlconfp1->ld_id == dlconfp2->ld_id)
142d62bc4baSyz147064 		return (0);
143d62bc4baSyz147064 	else if (dlconfp1->ld_id < dlconfp2->ld_id)
144d62bc4baSyz147064 		return (-1);
145d62bc4baSyz147064 	else
146d62bc4baSyz147064 		return (1);
147d62bc4baSyz147064 }
148d62bc4baSyz147064 
1492b24ab6bSSebastien Roy void
1502b24ab6bSSebastien Roy dlmgmt_linktable_init(void)
151d62bc4baSyz147064 {
152d62bc4baSyz147064 	/*
1532b24ab6bSSebastien Roy 	 * Initialize the prefix list. First add the "net" prefix for the
1542b24ab6bSSebastien Roy 	 * global zone to the list.
155d62bc4baSyz147064 	 */
1562b24ab6bSSebastien Roy 	dlmgmt_prefixlist.lp_next = NULL;
1572b24ab6bSSebastien Roy 	dlmgmt_prefixlist.lp_zoneid = GLOBAL_ZONEID;
1582b24ab6bSSebastien Roy 	dlmgmt_prefixlist.lp_nextppa = 0;
1592b24ab6bSSebastien Roy 	(void) strlcpy(dlmgmt_prefixlist.lp_prefix, "net", MAXLINKNAMELEN);
160d62bc4baSyz147064 
1612b24ab6bSSebastien Roy 	avl_create(&dlmgmt_name_avl, cmp_link_by_zname, sizeof (dlmgmt_link_t),
1622b24ab6bSSebastien Roy 	    offsetof(dlmgmt_link_t, ll_name_node));
163d62bc4baSyz147064 	avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
1642b24ab6bSSebastien Roy 	    offsetof(dlmgmt_link_t, ll_id_node));
1652b24ab6bSSebastien Roy 	avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
1662b24ab6bSSebastien Roy 	    offsetof(dlmgmt_link_t, ll_loan_node));
167d62bc4baSyz147064 	avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id,
168d62bc4baSyz147064 	    sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node));
169d62bc4baSyz147064 	dlmgmt_nextlinkid = 1;
170d62bc4baSyz147064 }
171d62bc4baSyz147064 
172d62bc4baSyz147064 void
1732b24ab6bSSebastien Roy dlmgmt_linktable_fini(void)
174d62bc4baSyz147064 {
175d62bc4baSyz147064 	dlmgmt_prefix_t *lpp, *next;
176d62bc4baSyz147064 
1772b24ab6bSSebastien Roy 	for (lpp = dlmgmt_prefixlist.lp_next; lpp != NULL; lpp = next) {
178d62bc4baSyz147064 		next = lpp->lp_next;
179d62bc4baSyz147064 		free(lpp);
180d62bc4baSyz147064 	}
181d62bc4baSyz147064 
182d62bc4baSyz147064 	avl_destroy(&dlmgmt_dlconf_avl);
183d62bc4baSyz147064 	avl_destroy(&dlmgmt_name_avl);
1842b24ab6bSSebastien Roy 	avl_destroy(&dlmgmt_loan_avl);
185d62bc4baSyz147064 	avl_destroy(&dlmgmt_id_avl);
186d62bc4baSyz147064 }
187d62bc4baSyz147064 
1882b24ab6bSSebastien Roy static void
189d62bc4baSyz147064 linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
190d62bc4baSyz147064 {
191d62bc4baSyz147064 	if (*headp == NULL) {
192d62bc4baSyz147064 		*headp = attrp;
193d62bc4baSyz147064 	} else {
194d62bc4baSyz147064 		(*headp)->lp_prev = attrp;
195d62bc4baSyz147064 		attrp->lp_next = *headp;
196d62bc4baSyz147064 		*headp = attrp;
197d62bc4baSyz147064 	}
198d62bc4baSyz147064 }
199d62bc4baSyz147064 
2002b24ab6bSSebastien Roy static void
201d62bc4baSyz147064 linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
202d62bc4baSyz147064 {
203d62bc4baSyz147064 	dlmgmt_linkattr_t *next, *prev;
204d62bc4baSyz147064 
205d62bc4baSyz147064 	next = attrp->lp_next;
206d62bc4baSyz147064 	prev = attrp->lp_prev;
207d62bc4baSyz147064 	if (next != NULL)
208d62bc4baSyz147064 		next->lp_prev = prev;
209d62bc4baSyz147064 	if (prev != NULL)
210d62bc4baSyz147064 		prev->lp_next = next;
211d62bc4baSyz147064 	else
212d62bc4baSyz147064 		*headp = next;
2132b24ab6bSSebastien Roy }
214d62bc4baSyz147064 
2152b24ab6bSSebastien Roy dlmgmt_linkattr_t *
2162b24ab6bSSebastien Roy linkattr_find(dlmgmt_linkattr_t *headp, const char *attr)
2172b24ab6bSSebastien Roy {
2182b24ab6bSSebastien Roy 	dlmgmt_linkattr_t *attrp;
2192b24ab6bSSebastien Roy 
2202b24ab6bSSebastien Roy 	for (attrp = headp; attrp != NULL; attrp = attrp->lp_next) {
2212b24ab6bSSebastien Roy 		if (strcmp(attrp->lp_name, attr) == 0)
2222b24ab6bSSebastien Roy 			break;
2232b24ab6bSSebastien Roy 	}
2242b24ab6bSSebastien Roy 	return (attrp);
225d62bc4baSyz147064 }
226d62bc4baSyz147064 
227d62bc4baSyz147064 int
228d62bc4baSyz147064 linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
229d62bc4baSyz147064     size_t attrsz, dladm_datatype_t type)
230d62bc4baSyz147064 {
231d62bc4baSyz147064 	dlmgmt_linkattr_t	*attrp;
2322b24ab6bSSebastien Roy 	void			*newval;
2332b24ab6bSSebastien Roy 	boolean_t		new;
234d62bc4baSyz147064 
2352b24ab6bSSebastien Roy 	attrp = linkattr_find(*headp, attr);
236d62bc4baSyz147064 	if (attrp != NULL) {
237d62bc4baSyz147064 		/*
238d62bc4baSyz147064 		 * It is already set.  If the value changed, update it.
239d62bc4baSyz147064 		 */
240d62bc4baSyz147064 		if (linkattr_equal(headp, attr, attrval, attrsz))
241d62bc4baSyz147064 			return (0);
2422b24ab6bSSebastien Roy 		new = B_FALSE;
243d62bc4baSyz147064 	} else {
244d62bc4baSyz147064 		/*
245d62bc4baSyz147064 		 * It is not set yet, allocate the linkattr and prepend to the
246d62bc4baSyz147064 		 * list.
247d62bc4baSyz147064 		 */
248d62bc4baSyz147064 		if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL)
249d62bc4baSyz147064 			return (ENOMEM);
250d62bc4baSyz147064 
251d62bc4baSyz147064 		(void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN);
2522b24ab6bSSebastien Roy 		new = B_TRUE;
253d62bc4baSyz147064 	}
2542b24ab6bSSebastien Roy 	if ((newval = calloc(1, attrsz)) == NULL) {
2552b24ab6bSSebastien Roy 		if (new)
256d62bc4baSyz147064 			free(attrp);
257d62bc4baSyz147064 		return (ENOMEM);
258d62bc4baSyz147064 	}
259d62bc4baSyz147064 
2602b24ab6bSSebastien Roy 	if (!new)
2612b24ab6bSSebastien Roy 		free(attrp->lp_val);
2622b24ab6bSSebastien Roy 	attrp->lp_val = newval;
263d62bc4baSyz147064 	bcopy(attrval, attrp->lp_val, attrsz);
264d62bc4baSyz147064 	attrp->lp_sz = attrsz;
265d62bc4baSyz147064 	attrp->lp_type = type;
26662ee1d25SArtem Kachitchkine 	attrp->lp_linkprop = dladm_attr_is_linkprop(attr);
2672b24ab6bSSebastien Roy 	if (new)
2682b24ab6bSSebastien Roy 		linkattr_add(headp, attrp);
269d62bc4baSyz147064 	return (0);
270d62bc4baSyz147064 }
271d62bc4baSyz147064 
2722b24ab6bSSebastien Roy void
273d62bc4baSyz147064 linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr)
274d62bc4baSyz147064 {
2752b24ab6bSSebastien Roy 	dlmgmt_linkattr_t *attrp;
276d62bc4baSyz147064 
27732715170SCathy Zhou 	if ((attrp = linkattr_find(*headp, attr)) != NULL) {
2782b24ab6bSSebastien Roy 		linkattr_rm(headp, attrp);
27932715170SCathy Zhou 		free(attrp->lp_val);
28032715170SCathy Zhou 		free(attrp);
28132715170SCathy Zhou 	}
282d62bc4baSyz147064 }
283d62bc4baSyz147064 
284d62bc4baSyz147064 int
285d62bc4baSyz147064 linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp,
286d62bc4baSyz147064     size_t *attrszp, dladm_datatype_t *typep)
287d62bc4baSyz147064 {
2882b24ab6bSSebastien Roy 	dlmgmt_linkattr_t *attrp;
289d62bc4baSyz147064 
2902b24ab6bSSebastien Roy 	if ((attrp = linkattr_find(*headp, attr)) == NULL)
291d62bc4baSyz147064 		return (ENOENT);
292d62bc4baSyz147064 
293d62bc4baSyz147064 	*attrvalp = attrp->lp_val;
294d62bc4baSyz147064 	*attrszp = attrp->lp_sz;
295d62bc4baSyz147064 	if (typep != NULL)
296d62bc4baSyz147064 		*typep = attrp->lp_type;
297d62bc4baSyz147064 	return (0);
298d62bc4baSyz147064 }
299d62bc4baSyz147064 
300d62bc4baSyz147064 boolean_t
301d62bc4baSyz147064 linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
302d62bc4baSyz147064     size_t attrsz)
303d62bc4baSyz147064 {
304d62bc4baSyz147064 	void	*saved_attrval;
305d62bc4baSyz147064 	size_t	saved_attrsz;
306d62bc4baSyz147064 
307d62bc4baSyz147064 	if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0)
308d62bc4baSyz147064 		return (B_FALSE);
309d62bc4baSyz147064 
310d62bc4baSyz147064 	return ((saved_attrsz == attrsz) &&
311d62bc4baSyz147064 	    (memcmp(saved_attrval, attrval, attrsz) == 0));
312d62bc4baSyz147064 }
313d62bc4baSyz147064 
31432715170SCathy Zhou void
31532715170SCathy Zhou linkattr_destroy(dlmgmt_link_t *linkp)
31632715170SCathy Zhou {
31732715170SCathy Zhou 	dlmgmt_linkattr_t *next, *attrp;
31832715170SCathy Zhou 
31932715170SCathy Zhou 	for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
32032715170SCathy Zhou 		next = attrp->lp_next;
32132715170SCathy Zhou 		free(attrp->lp_val);
32232715170SCathy Zhou 		free(attrp);
32332715170SCathy Zhou 	}
32432715170SCathy Zhou }
32532715170SCathy Zhou 
326d62bc4baSyz147064 static int
327d62bc4baSyz147064 dlmgmt_table_readwritelock(boolean_t write)
328d62bc4baSyz147064 {
329d62bc4baSyz147064 	if (write)
330d62bc4baSyz147064 		return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock));
331d62bc4baSyz147064 	else
332d62bc4baSyz147064 		return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock));
333d62bc4baSyz147064 }
334d62bc4baSyz147064 
335d62bc4baSyz147064 void
336d62bc4baSyz147064 dlmgmt_table_lock(boolean_t write)
337d62bc4baSyz147064 {
338d62bc4baSyz147064 	(void) pthread_mutex_lock(&dlmgmt_avl_mutex);
339d62bc4baSyz147064 	while (dlmgmt_table_readwritelock(write) == EBUSY)
340d62bc4baSyz147064 		(void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex);
341d62bc4baSyz147064 
342d62bc4baSyz147064 	(void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
343d62bc4baSyz147064 }
344d62bc4baSyz147064 
345d62bc4baSyz147064 void
3462b24ab6bSSebastien Roy dlmgmt_table_unlock(void)
347d62bc4baSyz147064 {
348d62bc4baSyz147064 	(void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
349d62bc4baSyz147064 	(void) pthread_mutex_lock(&dlmgmt_avl_mutex);
350d62bc4baSyz147064 	(void) pthread_cond_broadcast(&dlmgmt_avl_cv);
351d62bc4baSyz147064 	(void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
352d62bc4baSyz147064 }
353d62bc4baSyz147064 
354d62bc4baSyz147064 void
355d62bc4baSyz147064 link_destroy(dlmgmt_link_t *linkp)
356d62bc4baSyz147064 {
35732715170SCathy Zhou 	linkattr_destroy(linkp);
358d62bc4baSyz147064 	free(linkp);
359d62bc4baSyz147064 }
360d62bc4baSyz147064 
3612b24ab6bSSebastien Roy /*
3622b24ab6bSSebastien Roy  * Set the DLMGMT_ACTIVE flag on the link to note that it is active.  When a
3632b24ab6bSSebastien Roy  * link becomes active and it belongs to a non-global zone, it is also added
3642b24ab6bSSebastien Roy  * to that zone.
3652b24ab6bSSebastien Roy  */
3662b24ab6bSSebastien Roy int
3672b24ab6bSSebastien Roy link_activate(dlmgmt_link_t *linkp)
368d62bc4baSyz147064 {
3692b24ab6bSSebastien Roy 	int		err = 0;
370f689bed1SRishi Srivatsavai 	zoneid_t	zoneid = ALL_ZONES;
371d62bc4baSyz147064 
3722b24ab6bSSebastien Roy 	if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
3732b24ab6bSSebastien Roy 		/*
3742b24ab6bSSebastien Roy 		 * This link was already added to a non-global zone.  This can
3752b24ab6bSSebastien Roy 		 * happen if dlmgmtd is restarted.
3762b24ab6bSSebastien Roy 		 */
3772b24ab6bSSebastien Roy 		if (zoneid != linkp->ll_zoneid) {
3782b24ab6bSSebastien Roy 			if (link_by_name(linkp->ll_link, zoneid) != NULL) {
3792b24ab6bSSebastien Roy 				err = EEXIST;
3802b24ab6bSSebastien Roy 				goto done;
3812b24ab6bSSebastien Roy 			}
382f689bed1SRishi Srivatsavai 
383f689bed1SRishi Srivatsavai 			if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
3842b24ab6bSSebastien Roy 				avl_remove(&dlmgmt_name_avl, linkp);
385f689bed1SRishi Srivatsavai 
3862b24ab6bSSebastien Roy 			linkp->ll_zoneid = zoneid;
3872b24ab6bSSebastien Roy 			avl_add(&dlmgmt_name_avl, linkp);
3882b24ab6bSSebastien Roy 			avl_add(&dlmgmt_loan_avl, linkp);
3892b24ab6bSSebastien Roy 			linkp->ll_onloan = B_TRUE;
3902b24ab6bSSebastien Roy 		}
3912b24ab6bSSebastien Roy 	} else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
3922b24ab6bSSebastien Roy 		err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
3932b24ab6bSSebastien Roy 	}
3942b24ab6bSSebastien Roy done:
3952b24ab6bSSebastien Roy 	if (err == 0)
3962b24ab6bSSebastien Roy 		linkp->ll_flags |= DLMGMT_ACTIVE;
3972b24ab6bSSebastien Roy 	return (err);
3982b24ab6bSSebastien Roy }
3992b24ab6bSSebastien Roy 
4002b24ab6bSSebastien Roy /*
4012b24ab6bSSebastien Roy  * Is linkp visible from the caller's zoneid?  It is if the link is in the
4022b24ab6bSSebastien Roy  * same zone as the caller, or if the caller is in the global zone and the
4032b24ab6bSSebastien Roy  * link is on loan to a non-global zone.
4042b24ab6bSSebastien Roy  */
4052b24ab6bSSebastien Roy boolean_t
4062b24ab6bSSebastien Roy link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid)
4072b24ab6bSSebastien Roy {
4082b24ab6bSSebastien Roy 	return (linkp->ll_zoneid == zoneid ||
4092b24ab6bSSebastien Roy 	    (zoneid == GLOBAL_ZONEID && linkp->ll_onloan));
410d62bc4baSyz147064 }
411d62bc4baSyz147064 
412d62bc4baSyz147064 dlmgmt_link_t *
4132b24ab6bSSebastien Roy link_by_id(datalink_id_t linkid, zoneid_t zoneid)
414d62bc4baSyz147064 {
4152b24ab6bSSebastien Roy 	dlmgmt_link_t link, *linkp;
4162b24ab6bSSebastien Roy 
4172b24ab6bSSebastien Roy 	link.ll_linkid = linkid;
418*c6d054cbSJoshua M. Clulow 	if ((linkp = avl_find(&dlmgmt_id_avl, &link, NULL)) == NULL)
419*c6d054cbSJoshua M. Clulow 		return (NULL);
4202b24ab6bSSebastien Roy 	if (zoneid != GLOBAL_ZONEID && linkp->ll_zoneid != zoneid)
421*c6d054cbSJoshua M. Clulow 		return (NULL);
4222b24ab6bSSebastien Roy 	return (linkp);
4232b24ab6bSSebastien Roy }
4242b24ab6bSSebastien Roy 
4252b24ab6bSSebastien Roy dlmgmt_link_t *
4262b24ab6bSSebastien Roy link_by_name(const char *name, zoneid_t zoneid)
4272b24ab6bSSebastien Roy {
4282b24ab6bSSebastien Roy 	dlmgmt_link_t	link, *linkp;
429d62bc4baSyz147064 
430d62bc4baSyz147064 	(void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
4312b24ab6bSSebastien Roy 	link.ll_zoneid = zoneid;
4322b24ab6bSSebastien Roy 	linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
4332b24ab6bSSebastien Roy 	if (linkp == NULL && zoneid == GLOBAL_ZONEID) {
4342b24ab6bSSebastien Roy 		/* The link could be on loan to a non-global zone? */
4352b24ab6bSSebastien Roy 		linkp = avl_find(&dlmgmt_loan_avl, &link, NULL);
4362b24ab6bSSebastien Roy 	}
4372b24ab6bSSebastien Roy 	return (linkp);
438d62bc4baSyz147064 }
439d62bc4baSyz147064 
440d62bc4baSyz147064 int
441d62bc4baSyz147064 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
4422b24ab6bSSebastien Roy     zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp)
443d62bc4baSyz147064 {
4442b24ab6bSSebastien Roy 	dlmgmt_link_t	*linkp = NULL;
445d62bc4baSyz147064 	avl_index_t	name_where, id_where;
4462b24ab6bSSebastien Roy 	int		err = 0;
447d62bc4baSyz147064 
448d62bc4baSyz147064 	if (!dladm_valid_linkname(name))
449d62bc4baSyz147064 		return (EINVAL);
4502b24ab6bSSebastien Roy 	if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
4512b24ab6bSSebastien Roy 		return (ENOSPC);
452d62bc4baSyz147064 
4532b24ab6bSSebastien Roy 	if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
4542b24ab6bSSebastien Roy 		err = ENOMEM;
4552b24ab6bSSebastien Roy 		goto done;
4562b24ab6bSSebastien Roy 	}
457d62bc4baSyz147064 
4582b24ab6bSSebastien Roy 	(void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
4592b24ab6bSSebastien Roy 	linkp->ll_class = class;
4602b24ab6bSSebastien Roy 	linkp->ll_media = media;
4612b24ab6bSSebastien Roy 	linkp->ll_linkid = dlmgmt_nextlinkid;
4622b24ab6bSSebastien Roy 	linkp->ll_zoneid = zoneid;
4632b24ab6bSSebastien Roy 	linkp->ll_gen = 0;
464d62bc4baSyz147064 
4652b24ab6bSSebastien Roy 	if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
4662b24ab6bSSebastien Roy 	    avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
4672b24ab6bSSebastien Roy 		err = EEXIST;
4682b24ab6bSSebastien Roy 		goto done;
4692b24ab6bSSebastien Roy 	}
4702b24ab6bSSebastien Roy 
471d62bc4baSyz147064 	avl_insert(&dlmgmt_name_avl, linkp, name_where);
472d62bc4baSyz147064 	avl_insert(&dlmgmt_id_avl, linkp, id_where);
4732b24ab6bSSebastien Roy 
4742b24ab6bSSebastien Roy 	if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) {
4752b24ab6bSSebastien Roy 		avl_remove(&dlmgmt_name_avl, linkp);
4762b24ab6bSSebastien Roy 		avl_remove(&dlmgmt_id_avl, linkp);
4772b24ab6bSSebastien Roy 		goto done;
4782b24ab6bSSebastien Roy 	}
4792b24ab6bSSebastien Roy 
4802b24ab6bSSebastien Roy 	linkp->ll_flags = flags;
481d62bc4baSyz147064 	dlmgmt_advance(linkp);
482d62bc4baSyz147064 	*linkpp = linkp;
4832b24ab6bSSebastien Roy 
4842b24ab6bSSebastien Roy done:
4852b24ab6bSSebastien Roy 	if (err != 0)
4862b24ab6bSSebastien Roy 		free(linkp);
4872b24ab6bSSebastien Roy 	return (err);
488d62bc4baSyz147064 }
489d62bc4baSyz147064 
490d62bc4baSyz147064 int
491d62bc4baSyz147064 dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
492d62bc4baSyz147064 {
493d62bc4baSyz147064 	if ((linkp->ll_flags & flags) == 0) {
494d62bc4baSyz147064 		/*
495d62bc4baSyz147064 		 * The link does not exist in the specified space.
496d62bc4baSyz147064 		 */
497d62bc4baSyz147064 		return (ENOENT);
498d62bc4baSyz147064 	}
4992b24ab6bSSebastien Roy 
500d62bc4baSyz147064 	linkp->ll_flags &= ~flags;
5012b24ab6bSSebastien Roy 	if (flags & DLMGMT_PERSIST) {
502d62bc4baSyz147064 		dlmgmt_linkattr_t *next, *attrp;
503d62bc4baSyz147064 
504d62bc4baSyz147064 		for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
505d62bc4baSyz147064 			next = attrp->lp_next;
506d62bc4baSyz147064 			free(attrp->lp_val);
507d62bc4baSyz147064 			free(attrp);
508d62bc4baSyz147064 		}
509d62bc4baSyz147064 		linkp->ll_head = NULL;
510d62bc4baSyz147064 	}
511d62bc4baSyz147064 
5122b24ab6bSSebastien Roy 	if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) {
5132b24ab6bSSebastien Roy 		(void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid);
5142b24ab6bSSebastien Roy 		if (linkp->ll_onloan)
5152b24ab6bSSebastien Roy 			avl_remove(&dlmgmt_loan_avl, linkp);
5162b24ab6bSSebastien Roy 	}
5172b24ab6bSSebastien Roy 
518d62bc4baSyz147064 	if (linkp->ll_flags == 0) {
519d62bc4baSyz147064 		avl_remove(&dlmgmt_id_avl, linkp);
520d62bc4baSyz147064 		avl_remove(&dlmgmt_name_avl, linkp);
521d62bc4baSyz147064 		link_destroy(linkp);
522d62bc4baSyz147064 	}
523d62bc4baSyz147064 
524d62bc4baSyz147064 	return (0);
525d62bc4baSyz147064 }
526d62bc4baSyz147064 
5272b24ab6bSSebastien Roy int
528d62bc4baSyz147064 dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr,
529024b0a25Sseb     dlmgmt_getattr_retval_t *retvalp)
530d62bc4baSyz147064 {
531d62bc4baSyz147064 	int			err;
532d62bc4baSyz147064 	void			*attrval;
533d62bc4baSyz147064 	size_t			attrsz;
534d62bc4baSyz147064 	dladm_datatype_t	attrtype;
535d62bc4baSyz147064 
536d62bc4baSyz147064 	err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype);
537d62bc4baSyz147064 	if (err != 0)
5382b24ab6bSSebastien Roy 		return (err);
539d62bc4baSyz147064 
540d62bc4baSyz147064 	assert(attrsz > 0);
5412b24ab6bSSebastien Roy 	if (attrsz > MAXLINKATTRVALLEN)
5422b24ab6bSSebastien Roy 		return (EINVAL);
543d62bc4baSyz147064 
544d62bc4baSyz147064 	retvalp->lr_type = attrtype;
545024b0a25Sseb 	retvalp->lr_attrsz = attrsz;
546024b0a25Sseb 	bcopy(attrval, retvalp->lr_attrval, attrsz);
5472b24ab6bSSebastien Roy 	return (0);
548d62bc4baSyz147064 }
549d62bc4baSyz147064 
550d62bc4baSyz147064 void
551d62bc4baSyz147064 dlmgmt_dlconf_table_lock(boolean_t write)
552d62bc4baSyz147064 {
553d62bc4baSyz147064 	if (write)
554d62bc4baSyz147064 		(void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock);
555d62bc4baSyz147064 	else
556d62bc4baSyz147064 		(void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock);
557d62bc4baSyz147064 }
558d62bc4baSyz147064 
559d62bc4baSyz147064 void
5602b24ab6bSSebastien Roy dlmgmt_dlconf_table_unlock(void)
561d62bc4baSyz147064 {
562d62bc4baSyz147064 	(void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock);
563d62bc4baSyz147064 }
564d62bc4baSyz147064 
565d62bc4baSyz147064 int
566d62bc4baSyz147064 dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class,
5672b24ab6bSSebastien Roy     uint32_t media, zoneid_t zoneid, dlmgmt_dlconf_t **dlconfpp)
568d62bc4baSyz147064 {
569d62bc4baSyz147064 	dlmgmt_dlconf_t	*dlconfp = NULL;
570d62bc4baSyz147064 	int		err = 0;
571d62bc4baSyz147064 
572d62bc4baSyz147064 	if (dlmgmt_nextconfid == 0) {
573d62bc4baSyz147064 		err = ENOSPC;
574d62bc4baSyz147064 		goto done;
575d62bc4baSyz147064 	}
576d62bc4baSyz147064 
577d62bc4baSyz147064 	if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) {
578d62bc4baSyz147064 		err = ENOMEM;
579d62bc4baSyz147064 		goto done;
580d62bc4baSyz147064 	}
581d62bc4baSyz147064 
582d62bc4baSyz147064 	(void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN);
583d62bc4baSyz147064 	dlconfp->ld_linkid = linkid;
584d62bc4baSyz147064 	dlconfp->ld_class = class;
585d62bc4baSyz147064 	dlconfp->ld_media = media;
586d62bc4baSyz147064 	dlconfp->ld_id = dlmgmt_nextconfid;
5872b24ab6bSSebastien Roy 	dlconfp->ld_zoneid = zoneid;
588d62bc4baSyz147064 
589d62bc4baSyz147064 done:
590d62bc4baSyz147064 	*dlconfpp = dlconfp;
591d62bc4baSyz147064 	return (err);
592d62bc4baSyz147064 }
593d62bc4baSyz147064 
594d62bc4baSyz147064 void
595d62bc4baSyz147064 dlconf_destroy(dlmgmt_dlconf_t *dlconfp)
596d62bc4baSyz147064 {
597d62bc4baSyz147064 	dlmgmt_linkattr_t *next, *attrp;
598d62bc4baSyz147064 
599d62bc4baSyz147064 	for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) {
600d62bc4baSyz147064 		next = attrp->lp_next;
601d62bc4baSyz147064 		free(attrp->lp_val);
602d62bc4baSyz147064 		free(attrp);
603d62bc4baSyz147064 	}
604d62bc4baSyz147064 	free(dlconfp);
605d62bc4baSyz147064 }
606d62bc4baSyz147064 
607d62bc4baSyz147064 int
6082b24ab6bSSebastien Roy dlmgmt_generate_name(const char *prefix, char *name, size_t size,
6092b24ab6bSSebastien Roy     zoneid_t zoneid)
610d62bc4baSyz147064 {
611d62bc4baSyz147064 	dlmgmt_prefix_t	*lpp, *prev = NULL;
6122b24ab6bSSebastien Roy 	dlmgmt_link_t	link, *linkp;
613d62bc4baSyz147064 
614d62bc4baSyz147064 	/*
615d62bc4baSyz147064 	 * See whether the requested prefix is already in the list.
616d62bc4baSyz147064 	 */
6172b24ab6bSSebastien Roy 	for (lpp = &dlmgmt_prefixlist; lpp != NULL;
6182b24ab6bSSebastien Roy 	    prev = lpp, lpp = lpp->lp_next) {
6192b24ab6bSSebastien Roy 		if (lpp->lp_zoneid == zoneid &&
6202b24ab6bSSebastien Roy 		    strcmp(prefix, lpp->lp_prefix) == 0)
621d62bc4baSyz147064 			break;
622d62bc4baSyz147064 	}
623d62bc4baSyz147064 
624d62bc4baSyz147064 	/*
625d62bc4baSyz147064 	 * Not found.
626d62bc4baSyz147064 	 */
627d62bc4baSyz147064 	if (lpp == NULL) {
628d62bc4baSyz147064 		assert(prev != NULL);
629d62bc4baSyz147064 
630d62bc4baSyz147064 		/*
631d62bc4baSyz147064 		 * First add this new prefix into the prefix list.
632d62bc4baSyz147064 		 */
633d62bc4baSyz147064 		if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL)
634d62bc4baSyz147064 			return (ENOMEM);
635d62bc4baSyz147064 
636d62bc4baSyz147064 		prev->lp_next = lpp;
637d62bc4baSyz147064 		lpp->lp_next = NULL;
6382b24ab6bSSebastien Roy 		lpp->lp_zoneid = zoneid;
639d62bc4baSyz147064 		lpp->lp_nextppa = 0;
640d62bc4baSyz147064 		(void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN);
641d62bc4baSyz147064 
642d62bc4baSyz147064 		/*
643d62bc4baSyz147064 		 * Now determine this prefix's nextppa.
644d62bc4baSyz147064 		 */
645d62bc4baSyz147064 		(void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d",
6462b24ab6bSSebastien Roy 		    prefix, 0);
6472b24ab6bSSebastien Roy 		link.ll_zoneid = zoneid;
6482b24ab6bSSebastien Roy 		if ((linkp = avl_find(&dlmgmt_name_avl, &link, NULL)) != NULL)
649d62bc4baSyz147064 			dlmgmt_advance_ppa(linkp);
650d62bc4baSyz147064 	}
651d62bc4baSyz147064 
652d62bc4baSyz147064 	if (lpp->lp_nextppa == (uint_t)-1)
653d62bc4baSyz147064 		return (ENOSPC);
654d62bc4baSyz147064 
655d62bc4baSyz147064 	(void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa);
656d62bc4baSyz147064 	return (0);
657d62bc4baSyz147064 }
658d62bc4baSyz147064 
659d62bc4baSyz147064 /*
660d62bc4baSyz147064  * Advance the next available ppa value if the name prefix of the current
661d62bc4baSyz147064  * link is in the prefix list.
662d62bc4baSyz147064  */
663d62bc4baSyz147064 static void
664d62bc4baSyz147064 dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
665d62bc4baSyz147064 {
666d62bc4baSyz147064 	dlmgmt_prefix_t	*lpp;
667d62bc4baSyz147064 	char		prefix[MAXLINKNAMELEN];
6682b24ab6bSSebastien Roy 	char		linkname[MAXLINKNAMELEN];
669d62bc4baSyz147064 	uint_t		start, ppa;
670d62bc4baSyz147064 
671d62bc4baSyz147064 	(void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
672d62bc4baSyz147064 
673d62bc4baSyz147064 	/*
674d62bc4baSyz147064 	 * See whether the requested prefix is already in the list.
675d62bc4baSyz147064 	 */
6762b24ab6bSSebastien Roy 	for (lpp = &dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) {
6772b24ab6bSSebastien Roy 		if (lpp->lp_zoneid == linkp->ll_zoneid &&
6782b24ab6bSSebastien Roy 		    strcmp(prefix, lpp->lp_prefix) == 0)
679d62bc4baSyz147064 			break;
680d62bc4baSyz147064 	}
681d62bc4baSyz147064 
682d62bc4baSyz147064 	/*
683d62bc4baSyz147064 	 * If the link name prefix is in the list, advance the
684d62bc4baSyz147064 	 * next available ppa for the <prefix>N name.
685d62bc4baSyz147064 	 */
686d62bc4baSyz147064 	if (lpp == NULL || lpp->lp_nextppa != ppa)
687d62bc4baSyz147064 		return;
688d62bc4baSyz147064 
689d62bc4baSyz147064 	start = lpp->lp_nextppa++;
690d62bc4baSyz147064 	linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
691d62bc4baSyz147064 	while (lpp->lp_nextppa != start) {
692d62bc4baSyz147064 		if (lpp->lp_nextppa == (uint_t)-1) {
693d62bc4baSyz147064 			/*
694d62bc4baSyz147064 			 * wrapped around. search from <prefix>1.
695d62bc4baSyz147064 			 */
696d62bc4baSyz147064 			lpp->lp_nextppa = 0;
6972b24ab6bSSebastien Roy 			(void) snprintf(linkname, MAXLINKNAMELEN,
698d62bc4baSyz147064 			    "%s%d", lpp->lp_prefix, lpp->lp_nextppa);
6992b24ab6bSSebastien Roy 			linkp = link_by_name(linkname, lpp->lp_zoneid);
700d62bc4baSyz147064 			if (linkp == NULL)
701d62bc4baSyz147064 				return;
702d62bc4baSyz147064 		} else {
703d62bc4baSyz147064 			if (linkp == NULL)
704d62bc4baSyz147064 				return;
705d62bc4baSyz147064 			(void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
706d62bc4baSyz147064 			if ((strcmp(prefix, lpp->lp_prefix) != 0) ||
707d62bc4baSyz147064 			    (ppa != lpp->lp_nextppa)) {
708d62bc4baSyz147064 				return;
709d62bc4baSyz147064 			}
710d62bc4baSyz147064 		}
711d62bc4baSyz147064 		linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
712d62bc4baSyz147064 		lpp->lp_nextppa++;
713d62bc4baSyz147064 	}
714d62bc4baSyz147064 	lpp->lp_nextppa = (uint_t)-1;
715d62bc4baSyz147064 }
716d62bc4baSyz147064 
717d62bc4baSyz147064 /*
718d62bc4baSyz147064  * Advance to the next available linkid value.
719d62bc4baSyz147064  */
720d62bc4baSyz147064 static void
721d62bc4baSyz147064 dlmgmt_advance_linkid(dlmgmt_link_t *linkp)
722d62bc4baSyz147064 {
723d62bc4baSyz147064 	datalink_id_t	start;
724d62bc4baSyz147064 
725d62bc4baSyz147064 	if (linkp->ll_linkid != dlmgmt_nextlinkid)
726d62bc4baSyz147064 		return;
727d62bc4baSyz147064 
728d62bc4baSyz147064 	start = dlmgmt_nextlinkid;
729d62bc4baSyz147064 	linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
730d62bc4baSyz147064 
731d62bc4baSyz147064 	do {
732d62bc4baSyz147064 		if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) {
733d62bc4baSyz147064 			/*
734d62bc4baSyz147064 			 * wrapped around. search from 1.
735d62bc4baSyz147064 			 */
736d62bc4baSyz147064 			dlmgmt_nextlinkid = 1;
7372b24ab6bSSebastien Roy 			if ((linkp = link_by_id(1, GLOBAL_ZONEID)) == NULL)
738d62bc4baSyz147064 				return;
739d62bc4baSyz147064 		} else {
740d62bc4baSyz147064 			dlmgmt_nextlinkid++;
741d62bc4baSyz147064 			if (linkp == NULL)
742d62bc4baSyz147064 				return;
743d62bc4baSyz147064 			if (linkp->ll_linkid != dlmgmt_nextlinkid)
744d62bc4baSyz147064 				return;
745d62bc4baSyz147064 		}
746d62bc4baSyz147064 
747d62bc4baSyz147064 		linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
748d62bc4baSyz147064 	} while (dlmgmt_nextlinkid != start);
749d62bc4baSyz147064 
750d62bc4baSyz147064 	dlmgmt_nextlinkid = DATALINK_INVALID_LINKID;
751d62bc4baSyz147064 }
752d62bc4baSyz147064 
753d62bc4baSyz147064 /*
754d62bc4baSyz147064  * Advance various global values, for example, next linkid value, next ppa for
755d62bc4baSyz147064  * various prefix etc.
756d62bc4baSyz147064  */
757d62bc4baSyz147064 void
758d62bc4baSyz147064 dlmgmt_advance(dlmgmt_link_t *linkp)
759d62bc4baSyz147064 {
760d62bc4baSyz147064 	dlmgmt_advance_linkid(linkp);
761d62bc4baSyz147064 	dlmgmt_advance_ppa(linkp);
762d62bc4baSyz147064 }
763d62bc4baSyz147064 
764d62bc4baSyz147064 /*
765d62bc4baSyz147064  * Advance to the next available dlconf id.
766d62bc4baSyz147064  */
767d62bc4baSyz147064 void
768d62bc4baSyz147064 dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp)
769d62bc4baSyz147064 {
770d62bc4baSyz147064 	uint_t	start;
771d62bc4baSyz147064 
772d62bc4baSyz147064 	start = dlmgmt_nextconfid++;
773d62bc4baSyz147064 	dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
774d62bc4baSyz147064 	while (dlmgmt_nextconfid != start) {
775d62bc4baSyz147064 		if (dlmgmt_nextconfid == 0) {
776d62bc4baSyz147064 			dlmgmt_dlconf_t	dlconf;
777d62bc4baSyz147064 
778d62bc4baSyz147064 			/*
779d62bc4baSyz147064 			 * wrapped around. search from 1.
780d62bc4baSyz147064 			 */
781d62bc4baSyz147064 			dlconf.ld_id = dlmgmt_nextconfid = 1;
782a73e6fc1SCathy Zhou 			dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
783d62bc4baSyz147064 			if (dlconfp == NULL)
784d62bc4baSyz147064 				return;
785d62bc4baSyz147064 		} else {
786d62bc4baSyz147064 			if ((dlconfp == NULL) ||
787d62bc4baSyz147064 			    (dlconfp->ld_id != dlmgmt_nextconfid)) {
788d62bc4baSyz147064 				return;
789d62bc4baSyz147064 			}
790d62bc4baSyz147064 		}
791a73e6fc1SCathy Zhou 		dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
792d62bc4baSyz147064 		dlmgmt_nextconfid++;
793d62bc4baSyz147064 	}
794d62bc4baSyz147064 	dlmgmt_nextconfid = 0;
795d62bc4baSyz147064 }
796