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