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