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