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