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