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