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