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