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