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 /*
2332715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24*85dff7a0SAndy Fiddaman * Copyright 2017 Joyent, Inc.
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>
362b24ab6bSSebastien Roy #include <errno.h>
37d62bc4baSyz #include <strings.h>
382b24ab6bSSebastien Roy #include <string.h>
39d62bc4baSyz #include <syslog.h>
40d62bc4baSyz #include <stdarg.h>
412b24ab6bSSebastien Roy #include <zone.h>
4282a2fc47SJames Carlson #include <errno.h>
43d62bc4baSyz #include <libdlpi.h>
44d62bc4baSyz #include "dlmgmt_impl.h"
45d62bc4baSyz
46d62bc4baSyz /*
472b24ab6bSSebastien Roy * There are three datalink AVL tables. The dlmgmt_name_avl tree contains all
482b24ab6bSSebastien Roy * datalinks and is keyed by zoneid and link name. The dlmgmt_id_avl also
492b24ab6bSSebastien Roy * contains all datalinks, and it is keyed by link ID. The dlmgmt_loan_avl is
502b24ab6bSSebastien Roy * keyed by link name, and contains the set of global-zone links that are
512b24ab6bSSebastien Roy * currently on loan to non-global zones.
52d62bc4baSyz */
53d62bc4baSyz avl_tree_t dlmgmt_name_avl;
54d62bc4baSyz avl_tree_t dlmgmt_id_avl;
552b24ab6bSSebastien 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];
672b24ab6bSSebastien Roy zoneid_t lp_zoneid;
68d62bc4baSyz uint_t lp_nextppa;
69d62bc4baSyz } dlmgmt_prefix_t;
702b24ab6bSSebastien Roy static dlmgmt_prefix_t dlmgmt_prefixlist;
71d62bc4baSyz
722b24ab6bSSebastien 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
dlmgmt_log(int pri,const char * fmt,...)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
cmp_link_by_name(const void * v1,const void * v2)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
1042b24ab6bSSebastien Roy /*
1052b24ab6bSSebastien Roy * Note that the zoneid associated with a link is effectively part of its
1062b24ab6bSSebastien Roy * name. This is essentially what results in having each zone have disjoint
1072b24ab6bSSebastien Roy * datalink namespaces.
1082b24ab6bSSebastien Roy */
1092b24ab6bSSebastien Roy static int
cmp_link_by_zname(const void * v1,const void * v2)1102b24ab6bSSebastien Roy cmp_link_by_zname(const void *v1, const void *v2)
1112b24ab6bSSebastien Roy {
1122b24ab6bSSebastien Roy const dlmgmt_link_t *link1 = v1;
1132b24ab6bSSebastien Roy const dlmgmt_link_t *link2 = v2;
1142b24ab6bSSebastien Roy
1152b24ab6bSSebastien Roy if (link1->ll_zoneid < link2->ll_zoneid)
1162b24ab6bSSebastien Roy return (-1);
1172b24ab6bSSebastien Roy if (link1->ll_zoneid > link2->ll_zoneid)
1182b24ab6bSSebastien Roy return (1);
1192b24ab6bSSebastien Roy return (cmp_link_by_name(link1, link2));
1202b24ab6bSSebastien Roy }
1212b24ab6bSSebastien Roy
122d62bc4baSyz static int
cmp_link_by_id(const void * v1,const void * v2)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
cmp_dlconf_by_id(const void * v1,const void * v2)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
1502b24ab6bSSebastien Roy void
dlmgmt_linktable_init(void)1512b24ab6bSSebastien Roy dlmgmt_linktable_init(void)
152d62bc4baSyz {
153d62bc4baSyz /*
1542b24ab6bSSebastien Roy * Initialize the prefix list. First add the "net" prefix for the
1552b24ab6bSSebastien Roy * global zone to the list.
156d62bc4baSyz */
1572b24ab6bSSebastien Roy dlmgmt_prefixlist.lp_next = NULL;
1582b24ab6bSSebastien Roy dlmgmt_prefixlist.lp_zoneid = GLOBAL_ZONEID;
1592b24ab6bSSebastien Roy dlmgmt_prefixlist.lp_nextppa = 0;
1602b24ab6bSSebastien Roy (void) strlcpy(dlmgmt_prefixlist.lp_prefix, "net", MAXLINKNAMELEN);
161d62bc4baSyz
1622b24ab6bSSebastien Roy avl_create(&dlmgmt_name_avl, cmp_link_by_zname, sizeof (dlmgmt_link_t),
1632b24ab6bSSebastien Roy offsetof(dlmgmt_link_t, ll_name_node));
164d62bc4baSyz avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
1652b24ab6bSSebastien Roy offsetof(dlmgmt_link_t, ll_id_node));
1662b24ab6bSSebastien Roy avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
1672b24ab6bSSebastien 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
dlmgmt_linktable_fini(void)1742b24ab6bSSebastien Roy dlmgmt_linktable_fini(void)
175d62bc4baSyz {
1762b24ab6bSSebastien Roy dlmgmt_prefix_t *lpp, *next;
177d62bc4baSyz
1782b24ab6bSSebastien 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);
1852b24ab6bSSebastien Roy avl_destroy(&dlmgmt_loan_avl);
186d62bc4baSyz avl_destroy(&dlmgmt_id_avl);
187d62bc4baSyz }
188d62bc4baSyz
1892b24ab6bSSebastien Roy static void
linkattr_add(dlmgmt_linkattr_t ** headp,dlmgmt_linkattr_t * attrp)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
2012b24ab6bSSebastien Roy static void
linkattr_rm(dlmgmt_linkattr_t ** headp,dlmgmt_linkattr_t * attrp)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;
2142b24ab6bSSebastien Roy }
215d62bc4baSyz
2162b24ab6bSSebastien Roy dlmgmt_linkattr_t *
linkattr_find(dlmgmt_linkattr_t * headp,const char * attr)2172b24ab6bSSebastien Roy linkattr_find(dlmgmt_linkattr_t *headp, const char *attr)
2182b24ab6bSSebastien Roy {
2192b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp;
2202b24ab6bSSebastien Roy
2212b24ab6bSSebastien Roy for (attrp = headp; attrp != NULL; attrp = attrp->lp_next) {
2222b24ab6bSSebastien Roy if (strcmp(attrp->lp_name, attr) == 0)
2232b24ab6bSSebastien Roy break;
2242b24ab6bSSebastien Roy }
2252b24ab6bSSebastien Roy return (attrp);
226d62bc4baSyz }
227d62bc4baSyz
228d62bc4baSyz int
linkattr_set(dlmgmt_linkattr_t ** headp,const char * attr,void * attrval,size_t attrsz,dladm_datatype_t type)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;
2332b24ab6bSSebastien Roy void *newval;
2342b24ab6bSSebastien Roy boolean_t new;
235d62bc4baSyz
2362b24ab6bSSebastien 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);
2432b24ab6bSSebastien 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);
2532b24ab6bSSebastien Roy new = B_TRUE;
254d62bc4baSyz }
2552b24ab6bSSebastien Roy if ((newval = calloc(1, attrsz)) == NULL) {
2562b24ab6bSSebastien Roy if (new)
2572b24ab6bSSebastien Roy free(attrp);
258d62bc4baSyz return (ENOMEM);
259d62bc4baSyz }
260d62bc4baSyz
2612b24ab6bSSebastien Roy if (!new)
2622b24ab6bSSebastien Roy free(attrp->lp_val);
2632b24ab6bSSebastien 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);
2682b24ab6bSSebastien Roy if (new)
2692b24ab6bSSebastien Roy linkattr_add(headp, attrp);
270d62bc4baSyz return (0);
271d62bc4baSyz }
272d62bc4baSyz
2732b24ab6bSSebastien Roy void
linkattr_unset(dlmgmt_linkattr_t ** headp,const char * attr)274d62bc4baSyz linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr)
275d62bc4baSyz {
2762b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp;
277d62bc4baSyz
27832715170SCathy Zhou if ((attrp = linkattr_find(*headp, attr)) != NULL) {
2792b24ab6bSSebastien Roy linkattr_rm(headp, attrp);
28032715170SCathy Zhou free(attrp->lp_val);
28132715170SCathy Zhou free(attrp);
28232715170SCathy Zhou }
283d62bc4baSyz }
284d62bc4baSyz
285d62bc4baSyz int
linkattr_get(dlmgmt_linkattr_t ** headp,const char * attr,void ** attrvalp,size_t * attrszp,dladm_datatype_t * typep)286d62bc4baSyz linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp,
287d62bc4baSyz size_t *attrszp, dladm_datatype_t *typep)
288d62bc4baSyz {
2892b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp;
290d62bc4baSyz
2912b24ab6bSSebastien Roy if ((attrp = linkattr_find(*headp, attr)) == NULL)
292d62bc4baSyz return (ENOENT);
293d62bc4baSyz
294d62bc4baSyz *attrvalp = attrp->lp_val;
295d62bc4baSyz *attrszp = attrp->lp_sz;
296d62bc4baSyz if (typep != NULL)
297d62bc4baSyz *typep = attrp->lp_type;
298d62bc4baSyz return (0);
299d62bc4baSyz }
300d62bc4baSyz
301d62bc4baSyz boolean_t
linkattr_equal(dlmgmt_linkattr_t ** headp,const char * attr,void * attrval,size_t attrsz)302d62bc4baSyz linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
303d62bc4baSyz size_t attrsz)
304d62bc4baSyz {
305d62bc4baSyz void *saved_attrval;
306d62bc4baSyz size_t saved_attrsz;
307d62bc4baSyz
308d62bc4baSyz if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0)
309d62bc4baSyz return (B_FALSE);
310d62bc4baSyz
311d62bc4baSyz return ((saved_attrsz == attrsz) &&
312d62bc4baSyz (memcmp(saved_attrval, attrval, attrsz) == 0));
313d62bc4baSyz }
314d62bc4baSyz
31532715170SCathy Zhou void
linkattr_destroy(dlmgmt_link_t * linkp)31632715170SCathy Zhou linkattr_destroy(dlmgmt_link_t *linkp)
31732715170SCathy Zhou {
31832715170SCathy Zhou dlmgmt_linkattr_t *next, *attrp;
31932715170SCathy Zhou
32032715170SCathy Zhou for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
32132715170SCathy Zhou next = attrp->lp_next;
32232715170SCathy Zhou free(attrp->lp_val);
32332715170SCathy Zhou free(attrp);
32432715170SCathy Zhou }
32532715170SCathy Zhou }
32632715170SCathy Zhou
327d62bc4baSyz static int
dlmgmt_table_readwritelock(boolean_t write)328d62bc4baSyz dlmgmt_table_readwritelock(boolean_t write)
329d62bc4baSyz {
330d62bc4baSyz if (write)
331d62bc4baSyz return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock));
332d62bc4baSyz else
333d62bc4baSyz return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock));
334d62bc4baSyz }
335d62bc4baSyz
336d62bc4baSyz void
dlmgmt_table_lock(boolean_t write)337d62bc4baSyz dlmgmt_table_lock(boolean_t write)
338d62bc4baSyz {
339d62bc4baSyz (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
340d62bc4baSyz while (dlmgmt_table_readwritelock(write) == EBUSY)
341d62bc4baSyz (void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex);
342d62bc4baSyz
343d62bc4baSyz (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
344d62bc4baSyz }
345d62bc4baSyz
346d62bc4baSyz void
dlmgmt_table_unlock(void)3472b24ab6bSSebastien Roy dlmgmt_table_unlock(void)
348d62bc4baSyz {
349d62bc4baSyz (void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
350d62bc4baSyz (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
351d62bc4baSyz (void) pthread_cond_broadcast(&dlmgmt_avl_cv);
352d62bc4baSyz (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
353d62bc4baSyz }
354d62bc4baSyz
355d62bc4baSyz void
link_destroy(dlmgmt_link_t * linkp)356d62bc4baSyz link_destroy(dlmgmt_link_t *linkp)
357d62bc4baSyz {
35832715170SCathy Zhou linkattr_destroy(linkp);
359d62bc4baSyz free(linkp);
360d62bc4baSyz }
361d62bc4baSyz
3622b24ab6bSSebastien Roy /*
363*85dff7a0SAndy Fiddaman * Set the DLMGMT_ACTIVE flag on the link to note that it is active.
364*85dff7a0SAndy Fiddaman * When a link is active and owned by an NGZ then it is added to
365*85dff7a0SAndy Fiddaman * that zone's datalink list.
3662b24ab6bSSebastien Roy */
3672b24ab6bSSebastien Roy int
link_activate(dlmgmt_link_t * linkp)3682b24ab6bSSebastien Roy link_activate(dlmgmt_link_t *linkp)
3692b24ab6bSSebastien Roy {
3702b24ab6bSSebastien Roy int err = 0;
371f689bed1SRishi Srivatsavai zoneid_t zoneid = ALL_ZONES;
3722b24ab6bSSebastien Roy
373*85dff7a0SAndy Fiddaman /*
374*85dff7a0SAndy Fiddaman * If zone_check_datalink() returns 0 it means we found the
375*85dff7a0SAndy Fiddaman * link in one of the NGZ's datalink lists. Otherwise the link
376*85dff7a0SAndy Fiddaman * is under the GZ.
377*85dff7a0SAndy Fiddaman */
3782b24ab6bSSebastien Roy if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
3792b24ab6bSSebastien Roy /*
380*85dff7a0SAndy Fiddaman * This is a bit subtle. If the following expression
381*85dff7a0SAndy Fiddaman * is true then the link was found in one of the NGZ's
382*85dff7a0SAndy Fiddaman * datalink lists but the link structure has it under
383*85dff7a0SAndy Fiddaman * the GZ. This means that the link is supposed to be
384*85dff7a0SAndy Fiddaman * loaned out to an NGZ but the dlmgmtd state is out
385*85dff7a0SAndy Fiddaman * of sync -- possibly due to the process restarting.
386*85dff7a0SAndy Fiddaman * In this case we need to sync the dlmgmtd state by
387*85dff7a0SAndy Fiddaman * marking it as on-loan to the NGZ it's currently
388*85dff7a0SAndy Fiddaman * under.
3892b24ab6bSSebastien Roy */
3902b24ab6bSSebastien Roy if (zoneid != linkp->ll_zoneid) {
391*85dff7a0SAndy Fiddaman assert(linkp->ll_zoneid == 0);
392*85dff7a0SAndy Fiddaman assert(linkp->ll_onloan == B_FALSE);
393*85dff7a0SAndy Fiddaman assert(linkp->ll_transient == 0);
394*85dff7a0SAndy Fiddaman
395*85dff7a0SAndy Fiddaman /*
396*85dff7a0SAndy Fiddaman * If dlmgmtd already has a link with this
397*85dff7a0SAndy Fiddaman * name under the NGZ then we have a problem.
398*85dff7a0SAndy Fiddaman */
3992b24ab6bSSebastien Roy if (link_by_name(linkp->ll_link, zoneid) != NULL) {
4002b24ab6bSSebastien Roy err = EEXIST;
4012b24ab6bSSebastien Roy goto done;
4022b24ab6bSSebastien Roy }
403f689bed1SRishi Srivatsavai
404*85dff7a0SAndy Fiddaman /*
405*85dff7a0SAndy Fiddaman * Remove the current linkp entry from the
406*85dff7a0SAndy Fiddaman * list because it's under the wrong zoneid.
407*85dff7a0SAndy Fiddaman * We don't have to update the dlmgmt_id_avl
408*85dff7a0SAndy Fiddaman * because it compares entries by ll_linkid
409*85dff7a0SAndy Fiddaman * only.
410*85dff7a0SAndy Fiddaman */
411f689bed1SRishi Srivatsavai if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
412f689bed1SRishi Srivatsavai avl_remove(&dlmgmt_name_avl, linkp);
413f689bed1SRishi Srivatsavai
414*85dff7a0SAndy Fiddaman /*
415*85dff7a0SAndy Fiddaman * Update the link to reflect the fact that
416*85dff7a0SAndy Fiddaman * it's on-loan to an NGZ and re-add it to the
417*85dff7a0SAndy Fiddaman * list.
418*85dff7a0SAndy Fiddaman */
4192b24ab6bSSebastien Roy linkp->ll_zoneid = zoneid;
4202b24ab6bSSebastien Roy avl_add(&dlmgmt_name_avl, linkp);
421*85dff7a0SAndy Fiddaman
422*85dff7a0SAndy Fiddaman /*
423*85dff7a0SAndy Fiddaman * Since the link was found to be in a zone but
424*85dff7a0SAndy Fiddaman * recorded as a GZ link in the link structure, and
425*85dff7a0SAndy Fiddaman * we've now updated that, also mark it as on-loan to
426*85dff7a0SAndy Fiddaman * the NGZ.
427*85dff7a0SAndy Fiddaman */
4282b24ab6bSSebastien Roy avl_add(&dlmgmt_loan_avl, linkp);
4292b24ab6bSSebastien Roy linkp->ll_onloan = B_TRUE;
4302b24ab6bSSebastien Roy }
4312b24ab6bSSebastien Roy } else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
432*85dff7a0SAndy Fiddaman /*
433*85dff7a0SAndy Fiddaman * In this case the link was not found under any NGZ
434*85dff7a0SAndy Fiddaman * but according to its ll_zoneid member it is owned
435*85dff7a0SAndy Fiddaman * by an NGZ. Add the datalink to the appropriate zone
436*85dff7a0SAndy Fiddaman * datalink list.
437*85dff7a0SAndy Fiddaman */
4382b24ab6bSSebastien Roy err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
439*85dff7a0SAndy Fiddaman assert(linkp->ll_onloan == B_FALSE);
4402b24ab6bSSebastien Roy }
4412b24ab6bSSebastien Roy done:
4422b24ab6bSSebastien Roy if (err == 0)
4432b24ab6bSSebastien Roy linkp->ll_flags |= DLMGMT_ACTIVE;
4442b24ab6bSSebastien Roy return (err);
4452b24ab6bSSebastien Roy }
4462b24ab6bSSebastien Roy
4472b24ab6bSSebastien Roy /*
4482b24ab6bSSebastien Roy * Is linkp visible from the caller's zoneid? It is if the link is in the
4492b24ab6bSSebastien Roy * same zone as the caller, or if the caller is in the global zone and the
4502b24ab6bSSebastien Roy * link is on loan to a non-global zone.
4512b24ab6bSSebastien Roy */
4522b24ab6bSSebastien Roy boolean_t
link_is_visible(dlmgmt_link_t * linkp,zoneid_t zoneid)4532b24ab6bSSebastien Roy link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid)
4542b24ab6bSSebastien Roy {
4552b24ab6bSSebastien Roy return (linkp->ll_zoneid == zoneid ||
4562b24ab6bSSebastien Roy (zoneid == GLOBAL_ZONEID && linkp->ll_onloan));
4572b24ab6bSSebastien Roy }
4582b24ab6bSSebastien Roy
459d62bc4baSyz dlmgmt_link_t *
link_by_id(datalink_id_t linkid,zoneid_t zoneid)4602b24ab6bSSebastien Roy link_by_id(datalink_id_t linkid, zoneid_t zoneid)
461d62bc4baSyz {
4622b24ab6bSSebastien Roy dlmgmt_link_t link, *linkp;
463d62bc4baSyz
464d62bc4baSyz link.ll_linkid = linkid;
465c6d054cbSJoshua M. Clulow if ((linkp = avl_find(&dlmgmt_id_avl, &link, NULL)) == NULL)
466c6d054cbSJoshua M. Clulow return (NULL);
4672b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && linkp->ll_zoneid != zoneid)
468c6d054cbSJoshua M. Clulow return (NULL);
4692b24ab6bSSebastien Roy return (linkp);
470d62bc4baSyz }
471d62bc4baSyz
472d62bc4baSyz dlmgmt_link_t *
link_by_name(const char * name,zoneid_t zoneid)4732b24ab6bSSebastien Roy link_by_name(const char *name, zoneid_t zoneid)
474d62bc4baSyz {
4752b24ab6bSSebastien Roy dlmgmt_link_t link, *linkp;
476d62bc4baSyz
477d62bc4baSyz (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
4782b24ab6bSSebastien Roy link.ll_zoneid = zoneid;
4792b24ab6bSSebastien Roy linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
4802b24ab6bSSebastien Roy if (linkp == NULL && zoneid == GLOBAL_ZONEID) {
4812b24ab6bSSebastien Roy /* The link could be on loan to a non-global zone? */
4822b24ab6bSSebastien Roy linkp = avl_find(&dlmgmt_loan_avl, &link, NULL);
4832b24ab6bSSebastien Roy }
4842b24ab6bSSebastien Roy return (linkp);
485d62bc4baSyz }
486d62bc4baSyz
487d62bc4baSyz int
dlmgmt_create_common(const char * name,datalink_class_t class,uint32_t media,zoneid_t zoneid,uint32_t flags,dlmgmt_link_t ** linkpp)488d62bc4baSyz dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
4892b24ab6bSSebastien Roy zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp)
490d62bc4baSyz {
4912b24ab6bSSebastien Roy dlmgmt_link_t *linkp = NULL;
492d62bc4baSyz avl_index_t name_where, id_where;
4932b24ab6bSSebastien Roy int err = 0;
494d62bc4baSyz
495d62bc4baSyz if (!dladm_valid_linkname(name))
496d62bc4baSyz return (EINVAL);
4972b24ab6bSSebastien Roy if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
4982b24ab6bSSebastien Roy return (ENOSPC);
499*85dff7a0SAndy Fiddaman if (flags & ~(DLMGMT_ACTIVE | DLMGMT_PERSIST | DLMGMT_TRANSIENT) ||
500*85dff7a0SAndy Fiddaman ((flags & DLMGMT_PERSIST) && (flags & DLMGMT_TRANSIENT)) ||
501*85dff7a0SAndy Fiddaman flags == 0) {
502*85dff7a0SAndy Fiddaman return (EINVAL);
503*85dff7a0SAndy Fiddaman }
504d62bc4baSyz
5052b24ab6bSSebastien Roy if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
5062b24ab6bSSebastien Roy err = ENOMEM;
5072b24ab6bSSebastien Roy goto done;
5082b24ab6bSSebastien Roy }
509d62bc4baSyz
5102b24ab6bSSebastien Roy (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
5112b24ab6bSSebastien Roy linkp->ll_class = class;
5122b24ab6bSSebastien Roy linkp->ll_media = media;
5132b24ab6bSSebastien Roy linkp->ll_linkid = dlmgmt_nextlinkid;
5142b24ab6bSSebastien Roy linkp->ll_zoneid = zoneid;
5152b24ab6bSSebastien Roy linkp->ll_gen = 0;
5162b24ab6bSSebastien Roy
517*85dff7a0SAndy Fiddaman /*
518*85dff7a0SAndy Fiddaman * While DLMGMT_TRANSIENT starts off as a flag it is converted
519*85dff7a0SAndy Fiddaman * into a link field since it is really a substate of
520*85dff7a0SAndy Fiddaman * DLMGMT_ACTIVE -- it should not survive as a flag beyond
521*85dff7a0SAndy Fiddaman * this point.
522*85dff7a0SAndy Fiddaman */
523*85dff7a0SAndy Fiddaman linkp->ll_transient = (flags & DLMGMT_TRANSIENT) ? B_TRUE : B_FALSE;
524*85dff7a0SAndy Fiddaman flags &= ~DLMGMT_TRANSIENT;
525*85dff7a0SAndy Fiddaman
5262b24ab6bSSebastien Roy if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
5272b24ab6bSSebastien Roy avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
5282b24ab6bSSebastien Roy err = EEXIST;
5292b24ab6bSSebastien Roy goto done;
5302b24ab6bSSebastien Roy }
531d62bc4baSyz
532d62bc4baSyz avl_insert(&dlmgmt_name_avl, linkp, name_where);
533d62bc4baSyz avl_insert(&dlmgmt_id_avl, linkp, id_where);
5342b24ab6bSSebastien Roy
5352b24ab6bSSebastien Roy if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) {
5362b24ab6bSSebastien Roy avl_remove(&dlmgmt_name_avl, linkp);
5372b24ab6bSSebastien Roy avl_remove(&dlmgmt_id_avl, linkp);
5382b24ab6bSSebastien Roy goto done;
5392b24ab6bSSebastien Roy }
5402b24ab6bSSebastien Roy
5412b24ab6bSSebastien Roy linkp->ll_flags = flags;
542d62bc4baSyz dlmgmt_advance(linkp);
543d62bc4baSyz *linkpp = linkp;
5442b24ab6bSSebastien Roy
5452b24ab6bSSebastien Roy done:
5462b24ab6bSSebastien Roy if (err != 0)
5472b24ab6bSSebastien Roy free(linkp);
5482b24ab6bSSebastien Roy return (err);
549d62bc4baSyz }
550d62bc4baSyz
551d62bc4baSyz int
dlmgmt_destroy_common(dlmgmt_link_t * linkp,uint32_t flags)552d62bc4baSyz dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
553d62bc4baSyz {
554*85dff7a0SAndy Fiddaman /*
555*85dff7a0SAndy Fiddaman * After dlmgmt_create_common() the link flags should only
556*85dff7a0SAndy Fiddaman * ever include ACTIVE or PERSIST.
557*85dff7a0SAndy Fiddaman */
558*85dff7a0SAndy Fiddaman assert((linkp->ll_flags & ~(DLMGMT_ACTIVE | DLMGMT_PERSIST)) == 0);
559*85dff7a0SAndy Fiddaman
560d62bc4baSyz if ((linkp->ll_flags & flags) == 0) {
561d62bc4baSyz /*
562d62bc4baSyz * The link does not exist in the specified space.
563d62bc4baSyz */
564d62bc4baSyz return (ENOENT);
565d62bc4baSyz }
5662b24ab6bSSebastien Roy
567d62bc4baSyz linkp->ll_flags &= ~flags;
5682b24ab6bSSebastien Roy if (flags & DLMGMT_PERSIST) {
569d62bc4baSyz dlmgmt_linkattr_t *next, *attrp;
570d62bc4baSyz
571d62bc4baSyz for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
572d62bc4baSyz next = attrp->lp_next;
573d62bc4baSyz free(attrp->lp_val);
574d62bc4baSyz free(attrp);
575d62bc4baSyz }
576d62bc4baSyz linkp->ll_head = NULL;
577d62bc4baSyz }
578d62bc4baSyz
5792b24ab6bSSebastien Roy if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) {
5802b24ab6bSSebastien Roy (void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid);
5812b24ab6bSSebastien Roy if (linkp->ll_onloan)
5822b24ab6bSSebastien Roy avl_remove(&dlmgmt_loan_avl, linkp);
5832b24ab6bSSebastien Roy }
5842b24ab6bSSebastien Roy
585d62bc4baSyz if (linkp->ll_flags == 0) {
586d62bc4baSyz avl_remove(&dlmgmt_id_avl, linkp);
587d62bc4baSyz avl_remove(&dlmgmt_name_avl, linkp);
588d62bc4baSyz link_destroy(linkp);
589d62bc4baSyz }
590d62bc4baSyz
591d62bc4baSyz return (0);
592d62bc4baSyz }
593d62bc4baSyz
5942b24ab6bSSebastien Roy int
dlmgmt_getattr_common(dlmgmt_linkattr_t ** headp,const char * attr,dlmgmt_getattr_retval_t * retvalp)595d62bc4baSyz dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr,
596024b0a25Sseb dlmgmt_getattr_retval_t *retvalp)
597d62bc4baSyz {
598d62bc4baSyz int err;
599d62bc4baSyz void *attrval;
600d62bc4baSyz size_t attrsz;
601d62bc4baSyz dladm_datatype_t attrtype;
602d62bc4baSyz
603d62bc4baSyz err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype);
604d62bc4baSyz if (err != 0)
6052b24ab6bSSebastien Roy return (err);
606d62bc4baSyz
607d62bc4baSyz assert(attrsz > 0);
6082b24ab6bSSebastien Roy if (attrsz > MAXLINKATTRVALLEN)
6092b24ab6bSSebastien Roy return (EINVAL);
610d62bc4baSyz
611d62bc4baSyz retvalp->lr_type = attrtype;
612024b0a25Sseb retvalp->lr_attrsz = attrsz;
613024b0a25Sseb bcopy(attrval, retvalp->lr_attrval, attrsz);
6142b24ab6bSSebastien Roy return (0);
615d62bc4baSyz }
616d62bc4baSyz
617d62bc4baSyz void
dlmgmt_dlconf_table_lock(boolean_t write)618d62bc4baSyz dlmgmt_dlconf_table_lock(boolean_t write)
619d62bc4baSyz {
620d62bc4baSyz if (write)
621d62bc4baSyz (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock);
622d62bc4baSyz else
623d62bc4baSyz (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock);
624d62bc4baSyz }
625d62bc4baSyz
626d62bc4baSyz void
dlmgmt_dlconf_table_unlock(void)6272b24ab6bSSebastien Roy dlmgmt_dlconf_table_unlock(void)
628d62bc4baSyz {
629d62bc4baSyz (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock);
630d62bc4baSyz }
631d62bc4baSyz
632d62bc4baSyz int
dlconf_create(const char * name,datalink_id_t linkid,datalink_class_t class,uint32_t media,zoneid_t zoneid,dlmgmt_dlconf_t ** dlconfpp)633d62bc4baSyz dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class,
6342b24ab6bSSebastien Roy uint32_t media, zoneid_t zoneid, dlmgmt_dlconf_t **dlconfpp)
635d62bc4baSyz {
636d62bc4baSyz dlmgmt_dlconf_t *dlconfp = NULL;
637d62bc4baSyz int err = 0;
638d62bc4baSyz
639d62bc4baSyz if (dlmgmt_nextconfid == 0) {
640d62bc4baSyz err = ENOSPC;
641d62bc4baSyz goto done;
642d62bc4baSyz }
643d62bc4baSyz
644d62bc4baSyz if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) {
645d62bc4baSyz err = ENOMEM;
646d62bc4baSyz goto done;
647d62bc4baSyz }
648d62bc4baSyz
649d62bc4baSyz (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN);
650d62bc4baSyz dlconfp->ld_linkid = linkid;
651d62bc4baSyz dlconfp->ld_class = class;
652d62bc4baSyz dlconfp->ld_media = media;
653d62bc4baSyz dlconfp->ld_id = dlmgmt_nextconfid;
6542b24ab6bSSebastien Roy dlconfp->ld_zoneid = zoneid;
655d62bc4baSyz
656d62bc4baSyz done:
657d62bc4baSyz *dlconfpp = dlconfp;
658d62bc4baSyz return (err);
659d62bc4baSyz }
660d62bc4baSyz
661d62bc4baSyz void
dlconf_destroy(dlmgmt_dlconf_t * dlconfp)662d62bc4baSyz dlconf_destroy(dlmgmt_dlconf_t *dlconfp)
663d62bc4baSyz {
664d62bc4baSyz dlmgmt_linkattr_t *next, *attrp;
665d62bc4baSyz
666d62bc4baSyz for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) {
667d62bc4baSyz next = attrp->lp_next;
668d62bc4baSyz free(attrp->lp_val);
669d62bc4baSyz free(attrp);
670d62bc4baSyz }
671d62bc4baSyz free(dlconfp);
672d62bc4baSyz }
673d62bc4baSyz
674d62bc4baSyz int
dlmgmt_generate_name(const char * prefix,char * name,size_t size,zoneid_t zoneid)6752b24ab6bSSebastien Roy dlmgmt_generate_name(const char *prefix, char *name, size_t size,
6762b24ab6bSSebastien Roy zoneid_t zoneid)
677d62bc4baSyz {
678d62bc4baSyz dlmgmt_prefix_t *lpp, *prev = NULL;
6792b24ab6bSSebastien Roy dlmgmt_link_t link, *linkp;
680d62bc4baSyz
681d62bc4baSyz /*
682d62bc4baSyz * See whether the requested prefix is already in the list.
683d62bc4baSyz */
6842b24ab6bSSebastien Roy for (lpp = &dlmgmt_prefixlist; lpp != NULL;
6852b24ab6bSSebastien Roy prev = lpp, lpp = lpp->lp_next) {
6862b24ab6bSSebastien Roy if (lpp->lp_zoneid == zoneid &&
6872b24ab6bSSebastien Roy strcmp(prefix, lpp->lp_prefix) == 0)
688d62bc4baSyz break;
689d62bc4baSyz }
690d62bc4baSyz
691d62bc4baSyz /*
692d62bc4baSyz * Not found.
693d62bc4baSyz */
694d62bc4baSyz if (lpp == NULL) {
695d62bc4baSyz assert(prev != NULL);
696d62bc4baSyz
697d62bc4baSyz /*
698d62bc4baSyz * First add this new prefix into the prefix list.
699d62bc4baSyz */
700d62bc4baSyz if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL)
701d62bc4baSyz return (ENOMEM);
702d62bc4baSyz
703d62bc4baSyz prev->lp_next = lpp;
704d62bc4baSyz lpp->lp_next = NULL;
7052b24ab6bSSebastien Roy lpp->lp_zoneid = zoneid;
706d62bc4baSyz lpp->lp_nextppa = 0;
707d62bc4baSyz (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN);
708d62bc4baSyz
709d62bc4baSyz /*
710d62bc4baSyz * Now determine this prefix's nextppa.
711d62bc4baSyz */
712d62bc4baSyz (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d",
7132b24ab6bSSebastien Roy prefix, 0);
7142b24ab6bSSebastien Roy link.ll_zoneid = zoneid;
7152b24ab6bSSebastien Roy if ((linkp = avl_find(&dlmgmt_name_avl, &link, NULL)) != NULL)
716d62bc4baSyz dlmgmt_advance_ppa(linkp);
717d62bc4baSyz }
718d62bc4baSyz
719d62bc4baSyz if (lpp->lp_nextppa == (uint_t)-1)
720d62bc4baSyz return (ENOSPC);
721d62bc4baSyz
722d62bc4baSyz (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa);
723d62bc4baSyz return (0);
724d62bc4baSyz }
725d62bc4baSyz
726d62bc4baSyz /*
727d62bc4baSyz * Advance the next available ppa value if the name prefix of the current
728d62bc4baSyz * link is in the prefix list.
729d62bc4baSyz */
730d62bc4baSyz static void
dlmgmt_advance_ppa(dlmgmt_link_t * linkp)731d62bc4baSyz dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
732d62bc4baSyz {
733d62bc4baSyz dlmgmt_prefix_t *lpp;
734d62bc4baSyz char prefix[MAXLINKNAMELEN];
7352b24ab6bSSebastien Roy char linkname[MAXLINKNAMELEN];
736d62bc4baSyz uint_t start, ppa;
737d62bc4baSyz
738d62bc4baSyz (void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
739d62bc4baSyz
740d62bc4baSyz /*
741d62bc4baSyz * See whether the requested prefix is already in the list.
742d62bc4baSyz */
7432b24ab6bSSebastien Roy for (lpp = &dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) {
7442b24ab6bSSebastien Roy if (lpp->lp_zoneid == linkp->ll_zoneid &&
7452b24ab6bSSebastien Roy strcmp(prefix, lpp->lp_prefix) == 0)
746d62bc4baSyz break;
747d62bc4baSyz }
748d62bc4baSyz
749d62bc4baSyz /*
750d62bc4baSyz * If the link name prefix is in the list, advance the
751d62bc4baSyz * next available ppa for the <prefix>N name.
752d62bc4baSyz */
753d62bc4baSyz if (lpp == NULL || lpp->lp_nextppa != ppa)
754d62bc4baSyz return;
755d62bc4baSyz
756d62bc4baSyz start = lpp->lp_nextppa++;
757d62bc4baSyz linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
758d62bc4baSyz while (lpp->lp_nextppa != start) {
759d62bc4baSyz if (lpp->lp_nextppa == (uint_t)-1) {
760d62bc4baSyz /*
761d62bc4baSyz * wrapped around. search from <prefix>1.
762d62bc4baSyz */
763d62bc4baSyz lpp->lp_nextppa = 0;
7642b24ab6bSSebastien Roy (void) snprintf(linkname, MAXLINKNAMELEN,
765d62bc4baSyz "%s%d", lpp->lp_prefix, lpp->lp_nextppa);
7662b24ab6bSSebastien Roy linkp = link_by_name(linkname, lpp->lp_zoneid);
767d62bc4baSyz if (linkp == NULL)
768d62bc4baSyz return;
769d62bc4baSyz } else {
770d62bc4baSyz if (linkp == NULL)
771d62bc4baSyz return;
772d62bc4baSyz (void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
773d62bc4baSyz if ((strcmp(prefix, lpp->lp_prefix) != 0) ||
774d62bc4baSyz (ppa != lpp->lp_nextppa)) {
775d62bc4baSyz return;
776d62bc4baSyz }
777d62bc4baSyz }
778d62bc4baSyz linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
779d62bc4baSyz lpp->lp_nextppa++;
780d62bc4baSyz }
781d62bc4baSyz lpp->lp_nextppa = (uint_t)-1;
782d62bc4baSyz }
783d62bc4baSyz
784d62bc4baSyz /*
785d62bc4baSyz * Advance to the next available linkid value.
786d62bc4baSyz */
787d62bc4baSyz static void
dlmgmt_advance_linkid(dlmgmt_link_t * linkp)788d62bc4baSyz dlmgmt_advance_linkid(dlmgmt_link_t *linkp)
789d62bc4baSyz {
790d62bc4baSyz datalink_id_t start;
791d62bc4baSyz
792d62bc4baSyz if (linkp->ll_linkid != dlmgmt_nextlinkid)
793d62bc4baSyz return;
794d62bc4baSyz
795d62bc4baSyz start = dlmgmt_nextlinkid;
796d62bc4baSyz linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
797d62bc4baSyz
798d62bc4baSyz do {
799d62bc4baSyz if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) {
800d62bc4baSyz /*
801d62bc4baSyz * wrapped around. search from 1.
802d62bc4baSyz */
803d62bc4baSyz dlmgmt_nextlinkid = 1;
8042b24ab6bSSebastien Roy if ((linkp = link_by_id(1, GLOBAL_ZONEID)) == NULL)
805d62bc4baSyz return;
806d62bc4baSyz } else {
807d62bc4baSyz dlmgmt_nextlinkid++;
808d62bc4baSyz if (linkp == NULL)
809d62bc4baSyz return;
810d62bc4baSyz if (linkp->ll_linkid != dlmgmt_nextlinkid)
811d62bc4baSyz return;
812d62bc4baSyz }
813d62bc4baSyz
814d62bc4baSyz linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
815d62bc4baSyz } while (dlmgmt_nextlinkid != start);
816d62bc4baSyz
817d62bc4baSyz dlmgmt_nextlinkid = DATALINK_INVALID_LINKID;
818d62bc4baSyz }
819d62bc4baSyz
820d62bc4baSyz /*
821d62bc4baSyz * Advance various global values, for example, next linkid value, next ppa for
822d62bc4baSyz * various prefix etc.
823d62bc4baSyz */
824d62bc4baSyz void
dlmgmt_advance(dlmgmt_link_t * linkp)825d62bc4baSyz dlmgmt_advance(dlmgmt_link_t *linkp)
826d62bc4baSyz {
827d62bc4baSyz dlmgmt_advance_linkid(linkp);
828d62bc4baSyz dlmgmt_advance_ppa(linkp);
829d62bc4baSyz }
830d62bc4baSyz
831d62bc4baSyz /*
832d62bc4baSyz * Advance to the next available dlconf id.
833d62bc4baSyz */
834d62bc4baSyz void
dlmgmt_advance_dlconfid(dlmgmt_dlconf_t * dlconfp)835d62bc4baSyz dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp)
836d62bc4baSyz {
837d62bc4baSyz uint_t start;
838d62bc4baSyz
839d62bc4baSyz start = dlmgmt_nextconfid++;
840d62bc4baSyz dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
841d62bc4baSyz while (dlmgmt_nextconfid != start) {
842d62bc4baSyz if (dlmgmt_nextconfid == 0) {
843d62bc4baSyz dlmgmt_dlconf_t dlconf;
844d62bc4baSyz
845d62bc4baSyz /*
846d62bc4baSyz * wrapped around. search from 1.
847d62bc4baSyz */
848d62bc4baSyz dlconf.ld_id = dlmgmt_nextconfid = 1;
849a73e6fc1SCathy Zhou dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
850d62bc4baSyz if (dlconfp == NULL)
851d62bc4baSyz return;
852d62bc4baSyz } else {
853d62bc4baSyz if ((dlconfp == NULL) ||
854d62bc4baSyz (dlconfp->ld_id != dlmgmt_nextconfid)) {
855d62bc4baSyz return;
856d62bc4baSyz }
857d62bc4baSyz }
858a73e6fc1SCathy Zhou dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
859d62bc4baSyz dlmgmt_nextconfid++;
860d62bc4baSyz }
861d62bc4baSyz dlmgmt_nextconfid = 0;
862d62bc4baSyz }
863