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