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