Print this page
    
NEX-15390 illumos#8149 introduced deadlock between device detach and kstat read
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/dls/dls_mgmt.c
          +++ new/usr/src/uts/common/io/dls/dls_mgmt.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   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  /*
  26   26   * Copyright (c) 2016 by Delphix. All rights reserved.
  27   27   */
  28   28  
  29   29  /*
  30   30   * Datalink management routines.
  31   31   */
  32   32  
  33   33  #include <sys/types.h>
  34   34  #include <sys/door.h>
  35   35  #include <sys/zone.h>
  36   36  #include <sys/modctl.h>
  37   37  #include <sys/file.h>
  38   38  #include <sys/modhash.h>
  39   39  #include <sys/kstat.h>
  40   40  #include <sys/vnode.h>
  41   41  #include <sys/cmn_err.h>
  42   42  #include <sys/softmac.h>
  43   43  #include <sys/dls.h>
  44   44  #include <sys/dls_impl.h>
  45   45  #include <sys/stropts.h>
  46   46  #include <sys/netstack.h>
  47   47  #include <inet/iptun/iptun_impl.h>
  48   48  
  49   49  /*
  50   50   * This vanity name management module is treated as part of the GLD framework
  51   51   * and we don't hold any GLD framework lock across a call to any mac
  52   52   * function that needs to acquire the mac perimeter. The hierarchy is
  53   53   * mac perimeter -> framework locks
  54   54   */
  55   55  
  56   56  typedef struct dls_stack {
  57   57          zoneid_t        dlss_zoneid;
  58   58  } dls_stack_t;
  59   59  
  60   60  static kmem_cache_t     *i_dls_devnet_cachep;
  61   61  static kmutex_t         i_dls_mgmt_lock;
  62   62  static krwlock_t        i_dls_devnet_lock;
  63   63  static mod_hash_t       *i_dls_devnet_id_hash;
  64   64  static mod_hash_t       *i_dls_devnet_hash;
  65   65  
  66   66  boolean_t               devnet_need_rebuild;
  67   67  
  68   68  #define VLAN_HASHSZ     67      /* prime */
  69   69  
  70   70  /*
  71   71   * The following macros take a link name without the trailing PPA as input.
  72   72   * Opening a /dev/net node with one of these names causes a tunnel link to be
  73   73   * implicitly created in dls_devnet_hold_by_name() for backward compatibility
  74   74   * with Solaris 10 and prior.
  75   75   */
  76   76  #define IS_IPV4_TUN(name)       (strcmp((name), "ip.tun") == 0)
  77   77  #define IS_IPV6_TUN(name)       (strcmp((name), "ip6.tun") == 0)
  78   78  #define IS_6TO4_TUN(name)       (strcmp((name), "ip.6to4tun") == 0)
  79   79  #define IS_IPTUN_LINK(name)     (                                       \
  80   80      IS_IPV4_TUN(name) || IS_IPV6_TUN(name) || IS_6TO4_TUN(name))
  81   81  
  82   82  /* Upcall door handle */
  83   83  static door_handle_t    dls_mgmt_dh = NULL;
  84   84  
  85   85  /* dls_devnet_t dd_flags */
  86   86  #define DD_CONDEMNED            0x1
  87   87  #define DD_IMPLICIT_IPTUN       0x2 /* Implicitly-created ip*.*tun* tunnel */
  88   88  
  89   89  /*
  90   90   * This structure is used to keep the <linkid, macname> mapping.
  91   91   * This structure itself is not protected by the mac perimeter, but is
  92   92   * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the
  93   93   * functions manipulating this structure such as dls_devnet_set/unset etc.
  94   94   * may be called while not holding the mac perimeter.
  95   95   */
  96   96  typedef struct dls_devnet_s {
  97   97          datalink_id_t   dd_linkid;
  98   98          char            dd_linkname[MAXLINKNAMELEN];
  99   99          char            dd_mac[MAXNAMELEN];
 100  100          kstat_t         *dd_ksp;        /* kstat in owner_zid */
 101  101          kstat_t         *dd_zone_ksp;   /* in dd_zid if != owner_zid */
 102  102          uint32_t        dd_ref;
 103  103          kmutex_t        dd_mutex;
 104  104          kcondvar_t      dd_cv;
 105  105          uint32_t        dd_tref;
 106  106          uint_t          dd_flags;
 107  107          zoneid_t        dd_owner_zid;   /* zone where node was created */
 108  108          zoneid_t        dd_zid;         /* current zone */
 109  109          boolean_t       dd_prop_loaded;
 110  110          taskqid_t       dd_prop_taskid;
 111  111  } dls_devnet_t;
 112  112  
 113  113  static int i_dls_devnet_create_iptun(const char *, const char *,
 114  114      datalink_id_t *);
 115  115  static int i_dls_devnet_destroy_iptun(datalink_id_t);
 116  116  static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t);
 117  117  static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
 118  118  
 119  119  /*ARGSUSED*/
 120  120  static int
 121  121  i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
 122  122  {
 123  123          dls_devnet_t    *ddp = buf;
 124  124  
 125  125          bzero(buf, sizeof (dls_devnet_t));
 126  126          mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
 127  127          cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
 128  128          return (0);
 129  129  }
 130  130  
 131  131  /*ARGSUSED*/
 132  132  static void
 133  133  i_dls_devnet_destructor(void *buf, void *arg)
 134  134  {
 135  135          dls_devnet_t    *ddp = buf;
 136  136  
 137  137          ASSERT(ddp->dd_ksp == NULL);
 138  138          ASSERT(ddp->dd_ref == 0);
 139  139          ASSERT(ddp->dd_tref == 0);
 140  140          mutex_destroy(&ddp->dd_mutex);
 141  141          cv_destroy(&ddp->dd_cv);
 142  142  }
 143  143  
 144  144  /* ARGSUSED */
 145  145  static int
 146  146  dls_zone_remove(datalink_id_t linkid, void *arg)
 147  147  {
 148  148          dls_devnet_t *ddp;
 149  149  
 150  150          if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
 151  151                  (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID);
 152  152                  dls_devnet_rele_tmp(ddp);
 153  153          }
 154  154          return (0);
 155  155  }
 156  156  
 157  157  /* ARGSUSED */
 158  158  static void *
 159  159  dls_stack_init(netstackid_t stackid, netstack_t *ns)
 160  160  {
 161  161          dls_stack_t *dlss;
 162  162  
 163  163          dlss = kmem_zalloc(sizeof (*dlss), KM_SLEEP);
 164  164          dlss->dlss_zoneid = netstackid_to_zoneid(stackid);
 165  165          return (dlss);
 166  166  }
 167  167  
 168  168  /* ARGSUSED */
 169  169  static void
 170  170  dls_stack_shutdown(netstackid_t stackid, void *arg)
 171  171  {
 172  172          dls_stack_t     *dlss = (dls_stack_t *)arg;
 173  173  
 174  174          /* Move remaining datalinks in this zone back to the global zone. */
 175  175          (void) zone_datalink_walk(dlss->dlss_zoneid, dls_zone_remove, NULL);
 176  176  }
 177  177  
 178  178  /* ARGSUSED */
 179  179  static void
 180  180  dls_stack_fini(netstackid_t stackid, void *arg)
 181  181  {
 182  182          dls_stack_t     *dlss = (dls_stack_t *)arg;
 183  183  
 184  184          kmem_free(dlss, sizeof (*dlss));
 185  185  }
 186  186  
 187  187  /*
 188  188   * Module initialization and finalization functions.
 189  189   */
 190  190  void
 191  191  dls_mgmt_init(void)
 192  192  {
 193  193          mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL);
 194  194          rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL);
 195  195  
 196  196          /*
 197  197           * Create a kmem_cache of dls_devnet_t structures.
 198  198           */
 199  199          i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache",
 200  200              sizeof (dls_devnet_t), 0, i_dls_devnet_constructor,
 201  201              i_dls_devnet_destructor, NULL, NULL, NULL, 0);
 202  202          ASSERT(i_dls_devnet_cachep != NULL);
 203  203  
 204  204          /*
 205  205           * Create a hash table, keyed by dd_linkid, of dls_devnet_t.
 206  206           */
 207  207          i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash",
 208  208              VLAN_HASHSZ, mod_hash_null_valdtor);
 209  209  
 210  210          /*
 211  211           * Create a hash table, keyed by dd_mac
 212  212           */
 213  213          i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash",
 214  214              VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
 215  215              mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
 216  216  
 217  217          devnet_need_rebuild = B_FALSE;
 218  218  
 219  219          netstack_register(NS_DLS, dls_stack_init, dls_stack_shutdown,
 220  220              dls_stack_fini);
 221  221  }
 222  222  
 223  223  void
 224  224  dls_mgmt_fini(void)
 225  225  {
 226  226          netstack_unregister(NS_DLS);
 227  227          mod_hash_destroy_hash(i_dls_devnet_hash);
 228  228          mod_hash_destroy_hash(i_dls_devnet_id_hash);
 229  229          kmem_cache_destroy(i_dls_devnet_cachep);
 230  230          rw_destroy(&i_dls_devnet_lock);
 231  231          mutex_destroy(&i_dls_mgmt_lock);
 232  232  }
 233  233  
 234  234  int
 235  235  dls_mgmt_door_set(boolean_t start)
 236  236  {
 237  237          int     err;
 238  238  
 239  239          /* handle daemon restart */
 240  240          mutex_enter(&i_dls_mgmt_lock);
 241  241          if (dls_mgmt_dh != NULL) {
 242  242                  door_ki_rele(dls_mgmt_dh);
 243  243                  dls_mgmt_dh = NULL;
 244  244          }
 245  245  
 246  246          if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) {
 247  247                  mutex_exit(&i_dls_mgmt_lock);
 248  248                  return (err);
 249  249          }
 250  250  
 251  251          mutex_exit(&i_dls_mgmt_lock);
 252  252  
 253  253          /*
 254  254           * Create and associate <link name, linkid> mapping for network devices
 255  255           * which are already attached before the daemon is started.
 256  256           */
 257  257          if (start)
 258  258                  softmac_recreate();
 259  259          return (0);
 260  260  }
 261  261  
 262  262  static boolean_t
 263  263  i_dls_mgmt_door_revoked(door_handle_t dh)
 264  264  {
 265  265          struct door_info info;
 266  266          extern int sys_shutdown;
 267  267  
 268  268          ASSERT(dh != NULL);
 269  269  
 270  270          if (sys_shutdown) {
 271  271                  cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n");
 272  272                  return (B_TRUE);
 273  273          }
 274  274  
 275  275          if (door_ki_info(dh, &info) != 0)
 276  276                  return (B_TRUE);
 277  277  
 278  278          return ((info.di_attributes & DOOR_REVOKED) != 0);
 279  279  }
 280  280  
 281  281  /*
 282  282   * Upcall to the datalink management daemon (dlmgmtd).
 283  283   */
 284  284  static int
 285  285  i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize)
 286  286  {
 287  287          door_arg_t                      darg, save_arg;
 288  288          door_handle_t                   dh;
 289  289          int                             err;
 290  290          int                             retry = 0;
 291  291  
 292  292  #define MAXRETRYNUM     3
 293  293  
 294  294          ASSERT(arg);
 295  295          darg.data_ptr = arg;
 296  296          darg.data_size = asize;
 297  297          darg.desc_ptr = NULL;
 298  298          darg.desc_num = 0;
 299  299          darg.rbuf = rbuf;
 300  300          darg.rsize = rsize;
 301  301          save_arg = darg;
 302  302  
 303  303  retry:
 304  304          mutex_enter(&i_dls_mgmt_lock);
 305  305          dh = dls_mgmt_dh;
 306  306          if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) {
 307  307                  mutex_exit(&i_dls_mgmt_lock);
 308  308                  return (EBADF);
 309  309          }
 310  310          door_ki_hold(dh);
 311  311          mutex_exit(&i_dls_mgmt_lock);
 312  312  
 313  313          for (;;) {
 314  314                  retry++;
 315  315                  if ((err = door_ki_upcall_limited(dh, &darg, zone_kcred(),
 316  316                      SIZE_MAX, 0)) == 0)
 317  317                          break;
 318  318  
 319  319                  /*
 320  320                   * handle door call errors
 321  321                   */
 322  322                  darg = save_arg;
 323  323                  switch (err) {
 324  324                  case EINTR:
 325  325                          /*
 326  326                           * If the operation which caused this door upcall gets
 327  327                           * interrupted, return directly.
 328  328                           */
 329  329                          goto done;
 330  330                  case EAGAIN:
 331  331                          /*
 332  332                           * Repeat upcall if the maximum attempt limit has not
 333  333                           * been reached.
 334  334                           */
 335  335                          if (retry < MAXRETRYNUM) {
 336  336                                  delay(2 * hz);
 337  337                                  break;
 338  338                          }
 339  339                          cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
 340  340                          goto done;
 341  341                  default:
 342  342                          /* A fatal door error */
 343  343                          if (i_dls_mgmt_door_revoked(dh)) {
 344  344                                  cmn_err(CE_NOTE,
 345  345                                      "dls: dlmgmtd door service revoked\n");
 346  346  
 347  347                                  if (retry < MAXRETRYNUM) {
 348  348                                          door_ki_rele(dh);
 349  349                                          goto retry;
 350  350                                  }
 351  351                          }
 352  352                          cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
 353  353                          goto done;
 354  354                  }
 355  355          }
 356  356  
 357  357          if (darg.rbuf != rbuf) {
 358  358                  /*
 359  359                   * The size of the input rbuf was not big enough, so the
 360  360                   * upcall allocated the rbuf itself.  If this happens, assume
 361  361                   * that this was an invalid door call request.
 362  362                   */
 363  363                  kmem_free(darg.rbuf, darg.rsize);
 364  364                  err = ENOSPC;
 365  365                  goto done;
 366  366          }
 367  367  
 368  368          if (darg.rsize != rsize) {
 369  369                  err = EINVAL;
 370  370                  goto done;
 371  371          }
 372  372  
 373  373          err = ((dlmgmt_retval_t *)rbuf)->lr_err;
 374  374  
 375  375  done:
 376  376          door_ki_rele(dh);
 377  377          return (err);
 378  378  }
 379  379  
 380  380  /*
 381  381   * Request the datalink management daemon to create a link with the attributes
 382  382   * below.  Upon success, zero is returned and linkidp contains the linkid for
 383  383   * the new link; otherwise, an errno is returned.
 384  384   *
 385  385   *     - dev            physical dev_t.  required for all physical links,
 386  386   *                      including GLDv3 links.  It will be used to force the
 387  387   *                      attachment of a physical device, hence the
 388  388   *                      registration of its mac
 389  389   *     - class          datalink class
 390  390   *     - media type     media type; DL_OTHER means unknown
 391  391   *     - persist        whether to persist the datalink
 392  392   */
 393  393  int
 394  394  dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class,
 395  395      uint32_t media, boolean_t persist, datalink_id_t *linkidp)
 396  396  {
 397  397          dlmgmt_upcall_arg_create_t      create;
 398  398          dlmgmt_create_retval_t          retval;
 399  399          int                             err;
 400  400  
 401  401          create.ld_cmd = DLMGMT_CMD_DLS_CREATE;
 402  402          create.ld_class = class;
 403  403          create.ld_media = media;
 404  404          create.ld_phymaj = getmajor(dev);
 405  405          create.ld_phyinst = getminor(dev);
 406  406          create.ld_persist = persist;
 407  407          if (strlcpy(create.ld_devname, devname, sizeof (create.ld_devname)) >=
 408  408              sizeof (create.ld_devname))
 409  409                  return (EINVAL);
 410  410  
 411  411          if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval,
 412  412              sizeof (retval))) == 0) {
 413  413                  *linkidp = retval.lr_linkid;
 414  414          }
 415  415          return (err);
 416  416  }
 417  417  
 418  418  /*
 419  419   * Request the datalink management daemon to destroy the specified link.
 420  420   * Returns zero upon success, or an errno upon failure.
 421  421   */
 422  422  int
 423  423  dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist)
 424  424  {
 425  425          dlmgmt_upcall_arg_destroy_t     destroy;
 426  426          dlmgmt_destroy_retval_t         retval;
 427  427  
 428  428          destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY;
 429  429          destroy.ld_linkid = linkid;
 430  430          destroy.ld_persist = persist;
 431  431  
 432  432          return (i_dls_mgmt_upcall(&destroy, sizeof (destroy),
 433  433              &retval, sizeof (retval)));
 434  434  }
 435  435  
 436  436  /*
 437  437   * Request the datalink management daemon to verify/update the information
 438  438   * for a physical link.  Upon success, get its linkid.
 439  439   *
 440  440   *     - media type     media type
 441  441   *     - novanity       whether this physical datalink supports vanity naming.
 442  442   *                      physical links that do not use the GLDv3 MAC plugin
 443  443   *                      cannot suport vanity naming
 444  444   *
 445  445   * This function could fail with ENOENT or EEXIST.  Two cases return EEXIST:
 446  446   *
 447  447   * 1. A link with devname already exists, but the media type does not match.
 448  448   *    In this case, mediap will bee set to the media type of the existing link.
 449  449   * 2. A link with devname already exists, but its link name does not match
 450  450   *    the device name, although this link does not support vanity naming.
 451  451   */
 452  452  int
 453  453  dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity,
 454  454      uint32_t *mediap, datalink_id_t *linkidp)
 455  455  {
 456  456          dlmgmt_upcall_arg_update_t      update;
 457  457          dlmgmt_update_retval_t          retval;
 458  458          int                             err;
 459  459  
 460  460          update.ld_cmd = DLMGMT_CMD_DLS_UPDATE;
 461  461  
 462  462          if (strlcpy(update.ld_devname, devname, sizeof (update.ld_devname)) >=
 463  463              sizeof (update.ld_devname))
 464  464                  return (EINVAL);
 465  465  
 466  466          update.ld_media = media;
 467  467          update.ld_novanity = novanity;
 468  468  
 469  469          if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval,
 470  470              sizeof (retval))) == EEXIST) {
 471  471                  *linkidp = retval.lr_linkid;
 472  472                  *mediap = retval.lr_media;
 473  473          } else if (err == 0) {
 474  474                  *linkidp = retval.lr_linkid;
 475  475          }
 476  476  
 477  477          return (err);
 478  478  }
 479  479  
 480  480  /*
 481  481   * Request the datalink management daemon to get the information for a link.
 482  482   * Returns zero upon success, or an errno upon failure.
 483  483   *
 484  484   * Only fills in information for argument pointers that are non-NULL.
 485  485   * Note that the link argument is expected to be MAXLINKNAMELEN bytes.
 486  486   */
 487  487  int
 488  488  dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link,
 489  489      datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp)
 490  490  {
 491  491          dlmgmt_door_getname_t   getname;
 492  492          dlmgmt_getname_retval_t retval;
 493  493          int                     err, len;
 494  494  
 495  495          getname.ld_cmd = DLMGMT_CMD_GETNAME;
 496  496          getname.ld_linkid = linkid;
 497  497  
 498  498          if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval,
 499  499              sizeof (retval))) != 0) {
 500  500                  return (err);
 501  501          }
 502  502  
 503  503          len = strlen(retval.lr_link);
 504  504          if (len <= 1 || len >= MAXLINKNAMELEN)
 505  505                  return (EINVAL);
 506  506  
 507  507          if (link != NULL)
 508  508                  (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN);
 509  509          if (classp != NULL)
 510  510                  *classp = retval.lr_class;
 511  511          if (mediap != NULL)
 512  512                  *mediap = retval.lr_media;
 513  513          if (flagsp != NULL)
 514  514                  *flagsp = retval.lr_flags;
 515  515          return (0);
 516  516  }
 517  517  
 518  518  /*
 519  519   * Request the datalink management daemon to get the linkid for a link.
 520  520   * Returns a non-zero error code on failure.  The linkid argument is only
 521  521   * set on success (when zero is returned.)
 522  522   */
 523  523  int
 524  524  dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
 525  525  {
 526  526          dlmgmt_door_getlinkid_t         getlinkid;
 527  527          dlmgmt_getlinkid_retval_t       retval;
 528  528          int                             err;
 529  529  
 530  530          getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
 531  531          (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
 532  532  
 533  533          if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
 534  534              sizeof (retval))) == 0) {
 535  535                  *linkid = retval.lr_linkid;
 536  536          }
 537  537          return (err);
 538  538  }
 539  539  
 540  540  datalink_id_t
 541  541  dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
 542  542      datalink_media_t dmedia, uint32_t flags)
 543  543  {
 544  544          dlmgmt_door_getnext_t   getnext;
 545  545          dlmgmt_getnext_retval_t retval;
 546  546  
 547  547          getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
 548  548          getnext.ld_class = class;
 549  549          getnext.ld_dmedia = dmedia;
 550  550          getnext.ld_flags = flags;
 551  551          getnext.ld_linkid = linkid;
 552  552  
 553  553          if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval,
 554  554              sizeof (retval)) != 0) {
 555  555                  return (DATALINK_INVALID_LINKID);
 556  556          }
 557  557  
 558  558          return (retval.lr_linkid);
 559  559  }
 560  560  
 561  561  static int
 562  562  i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr,
 563  563      void *attrval, size_t *attrszp)
 564  564  {
 565  565          dlmgmt_upcall_arg_getattr_t     getattr;
 566  566          dlmgmt_getattr_retval_t         retval;
 567  567          int                             err;
 568  568  
 569  569          getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR;
 570  570          getattr.ld_linkid = linkid;
 571  571          (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
 572  572  
 573  573          if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval,
 574  574              sizeof (retval))) == 0) {
 575  575                  if (*attrszp < retval.lr_attrsz)
 576  576                          return (EINVAL);
 577  577                  *attrszp = retval.lr_attrsz;
 578  578                  bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
 579  579          }
 580  580  
 581  581          return (err);
 582  582  }
 583  583  
 584  584  /*
 585  585   * Note that this function can only get devp successfully for non-VLAN link.
 586  586   */
 587  587  int
 588  588  dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp)
 589  589  {
 590  590          uint64_t        maj, inst;
 591  591          size_t          attrsz = sizeof (uint64_t);
 592  592  
 593  593          if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 ||
 594  594              attrsz != sizeof (uint64_t) ||
 595  595              i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 ||
 596  596              attrsz != sizeof (uint64_t)) {
 597  597                  return (EINVAL);
 598  598          }
 599  599  
 600  600          *devp = makedevice((major_t)maj, (minor_t)inst);
 601  601          return (0);
 602  602  }
 603  603  
 604  604  /*
 605  605   * Request the datalink management daemon to push in
 606  606   * all properties associated with the link.
 607  607   * Returns a non-zero error code on failure.
 608  608   */
 609  609  int
 610  610  dls_mgmt_linkprop_init(datalink_id_t linkid)
 611  611  {
 612  612          dlmgmt_door_linkprop_init_t     li;
 613  613          dlmgmt_linkprop_init_retval_t   retval;
 614  614          int                             err;
 615  615  
 616  616          li.ld_cmd = DLMGMT_CMD_LINKPROP_INIT;
 617  617          li.ld_linkid = linkid;
 618  618  
 619  619          err = i_dls_mgmt_upcall(&li, sizeof (li), &retval, sizeof (retval));
 620  620          return (err);
 621  621  }
 622  622  
 623  623  static void
 624  624  dls_devnet_prop_task(void *arg)
 625  625  {
 626  626          dls_devnet_t            *ddp = arg;
 627  627  
 628  628          (void) dls_mgmt_linkprop_init(ddp->dd_linkid);
 629  629  
 630  630          mutex_enter(&ddp->dd_mutex);
 631  631          ddp->dd_prop_loaded = B_TRUE;
 632  632          ddp->dd_prop_taskid = NULL;
 633  633          cv_broadcast(&ddp->dd_cv);
 634  634          mutex_exit(&ddp->dd_mutex);
 635  635  }
 636  636  
 637  637  /*
 638  638   * Ensure property loading task is completed.
 639  639   */
 640  640  void
 641  641  dls_devnet_prop_task_wait(dls_dl_handle_t ddp)
 642  642  {
 643  643          mutex_enter(&ddp->dd_mutex);
 644  644          while (ddp->dd_prop_taskid != NULL)
 645  645                  cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
 646  646          mutex_exit(&ddp->dd_mutex);
 647  647  }
 648  648  
 649  649  void
 650  650  dls_devnet_rele_tmp(dls_dl_handle_t dlh)
 651  651  {
 652  652          dls_devnet_t            *ddp = dlh;
 653  653  
 654  654          mutex_enter(&ddp->dd_mutex);
 655  655          ASSERT(ddp->dd_tref != 0);
 656  656          if (--ddp->dd_tref == 0)
 657  657                  cv_signal(&ddp->dd_cv);
 658  658          mutex_exit(&ddp->dd_mutex);
 659  659  }
 660  660  
 661  661  int
 662  662  dls_devnet_hold_link(datalink_id_t linkid, dls_dl_handle_t *ddhp,
 663  663      dls_link_t **dlpp)
 664  664  {
 665  665          dls_dl_handle_t dlh;
 666  666          dls_link_t      *dlp;
 667  667          int             err;
 668  668  
 669  669          if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
 670  670                  return (err);
 671  671  
 672  672          if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) {
 673  673                  dls_devnet_rele_tmp(dlh);
 674  674                  return (err);
 675  675          }
 676  676  
 677  677          ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
 678  678  
 679  679          *ddhp = dlh;
 680  680          *dlpp = dlp;
 681  681          return (0);
 682  682  }
 683  683  
 684  684  void
 685  685  dls_devnet_rele_link(dls_dl_handle_t dlh, dls_link_t *dlp)
 686  686  {
 687  687          ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
 688  688  
 689  689          dls_link_rele(dlp);
 690  690          dls_devnet_rele_tmp(dlh);
 691  691  }
 692  692  
 693  693  /*
 694  694   * "link" kstats related functions.
 695  695   */
 696  696  
 697  697  /*
 698  698   * Query the "link" kstats.
 699  699   *
 700  700   * We may be called from the kstat subsystem in an arbitrary context.
 701  701   * If the caller is the stack, the context could be an upcall data
 702  702   * thread. Hence we can't acquire the mac perimeter in this function
 703  703   * for fear of deadlock.
 704  704   */
 705  705  static int
 706  706  dls_devnet_stat_update(kstat_t *ksp, int rw)
 707  707  {
 708  708          datalink_id_t   linkid = (datalink_id_t)(uintptr_t)ksp->ks_private;
 709  709          dls_devnet_t    *ddp;
 710  710          dls_link_t      *dlp;
 711  711          int             err;
 712  712  
 713  713          if ((err = dls_devnet_hold_tmp(linkid, &ddp)) != 0) {
 714  714                  return (err);
 715  715          }
 716  716  
 717  717          /*
 718  718           * If a device detach happens at this time, it will block in
 719  719           * dls_devnet_unset since the dd_tref has been bumped in
 720  720           * dls_devnet_hold_tmp(). So the access to 'dlp' is safe even though
 721  721           * we don't hold the mac perimeter.
 722  722           */
 723  723          if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac,
 724  724              (mod_hash_val_t *)&dlp) != 0) {
 725  725                  dls_devnet_rele_tmp(ddp);
 726  726                  return (ENOENT);
 727  727          }
 728  728  
 729  729          err = dls_stat_update(ksp, dlp, rw);
 730  730  
 731  731          dls_devnet_rele_tmp(ddp);
 732  732          return (err);
 733  733  }
 734  734  
 735  735  /*
 736  736   * Create the "link" kstats.
 737  737   */
 738  738  static void
 739  739  dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid)
 740  740  {
 741  741          kstat_t *ksp;
 742  742  
 743  743          if (dls_stat_create("link", 0, ddp->dd_linkname, zoneid,
 744  744              dls_devnet_stat_update, (void *)(uintptr_t)ddp->dd_linkid,
 745  745              &ksp) == 0) {
 746  746                  ASSERT(ksp != NULL);
 747  747                  if (zoneid == ddp->dd_owner_zid) {
 748  748                          ASSERT(ddp->dd_ksp == NULL);
 749  749                          ddp->dd_ksp = ksp;
 750  750                  } else {
 751  751                          ASSERT(ddp->dd_zone_ksp == NULL);
 752  752                          ddp->dd_zone_ksp = ksp;
 753  753                  }
 754  754          }
 755  755  }
 756  756  
 757  757  /*
 758  758   * Destroy the "link" kstats.
 759  759   */
 760  760  static void
 761  761  dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
 762  762  {
 763  763          if (zoneid == ddp->dd_owner_zid) {
 764  764                  if (ddp->dd_ksp != NULL) {
 765  765                          kstat_delete(ddp->dd_ksp);
 766  766                          ddp->dd_ksp = NULL;
 767  767                  }
 768  768          } else {
 769  769                  if (ddp->dd_zone_ksp != NULL) {
 770  770                          kstat_delete(ddp->dd_zone_ksp);
 771  771                          ddp->dd_zone_ksp = NULL;
 772  772                  }
 773  773          }
 774  774  }
 775  775  
 776  776  /*
 777  777   * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
 778  778   * and create the new set using the new name.
 779  779   */
 780  780  static void
 781  781  dls_devnet_stat_rename(dls_devnet_t *ddp)
 782  782  {
 783  783          if (ddp->dd_ksp != NULL) {
 784  784                  kstat_delete(ddp->dd_ksp);
 785  785                  ddp->dd_ksp = NULL;
 786  786          }
 787  787          /* We can't rename a link while it's assigned to a non-global zone. */
 788  788          ASSERT(ddp->dd_zone_ksp == NULL);
 789  789          dls_devnet_stat_create(ddp, ddp->dd_owner_zid);
 790  790  }
 791  791  
 792  792  /*
 793  793   * Associate a linkid with a given link (identified by macname)
 794  794   */
 795  795  static int
 796  796  dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
 797  797      dls_devnet_t **ddpp)
 798  798  {
 799  799          dls_devnet_t            *ddp = NULL;
 800  800          datalink_class_t        class;
 801  801          int                     err;
 802  802          boolean_t               stat_create = B_FALSE;
 803  803          char                    linkname[MAXLINKNAMELEN];
 804  804  
 805  805          rw_enter(&i_dls_devnet_lock, RW_WRITER);
 806  806  
 807  807          /*
 808  808           * Don't allow callers to set a link name with a linkid that already
 809  809           * has a name association (that's what rename is for).
 810  810           */
 811  811          if (linkid != DATALINK_INVALID_LINKID) {
 812  812                  if (mod_hash_find(i_dls_devnet_id_hash,
 813  813                      (mod_hash_key_t)(uintptr_t)linkid,
 814  814                      (mod_hash_val_t *)&ddp) == 0) {
 815  815                          err = EEXIST;
 816  816                          goto done;
 817  817                  }
 818  818                  if ((err = dls_mgmt_get_linkinfo(linkid, linkname, &class,
 819  819                      NULL, NULL)) != 0)
 820  820                          goto done;
 821  821          }
 822  822  
 823  823          if ((err = mod_hash_find(i_dls_devnet_hash,
 824  824              (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) == 0) {
 825  825                  if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
 826  826                          err = EEXIST;
 827  827                          goto done;
 828  828                  }
 829  829  
 830  830                  /*
 831  831                   * This might be a physical link that has already
 832  832                   * been created, but which does not have a linkid
 833  833                   * because dlmgmtd was not running when it was created.
 834  834                   */
 835  835                  if (linkid == DATALINK_INVALID_LINKID ||
 836  836                      class != DATALINK_CLASS_PHYS) {
 837  837                          err = EINVAL;
 838  838                          goto done;
 839  839                  }
 840  840          } else {
 841  841                  ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP);
 842  842                  ddp->dd_tref = 0;
 843  843                  ddp->dd_ref++;
 844  844                  ddp->dd_owner_zid = zoneid;
 845  845                  (void) strlcpy(ddp->dd_mac, macname, sizeof (ddp->dd_mac));
 846  846                  VERIFY(mod_hash_insert(i_dls_devnet_hash,
 847  847                      (mod_hash_key_t)ddp->dd_mac, (mod_hash_val_t)ddp) == 0);
 848  848          }
 849  849  
 850  850          if (linkid != DATALINK_INVALID_LINKID) {
 851  851                  ddp->dd_linkid = linkid;
 852  852                  (void) strlcpy(ddp->dd_linkname, linkname,
 853  853                      sizeof (ddp->dd_linkname));
 854  854                  VERIFY(mod_hash_insert(i_dls_devnet_id_hash,
 855  855                      (mod_hash_key_t)(uintptr_t)linkid,
 856  856                      (mod_hash_val_t)ddp) == 0);
 857  857                  devnet_need_rebuild = B_TRUE;
 858  858                  stat_create = B_TRUE;
 859  859                  mutex_enter(&ddp->dd_mutex);
 860  860                  if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) {
 861  861                          ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
 862  862                              dls_devnet_prop_task, ddp, TQ_SLEEP);
 863  863                  }
 864  864                  mutex_exit(&ddp->dd_mutex);
 865  865          }
 866  866          err = 0;
 867  867  done:
 868  868          /*
 869  869           * It is safe to drop the i_dls_devnet_lock at this point. In the case
 870  870           * of physical devices, the softmac framework will fail the device
 871  871           * detach based on the smac_state or smac_hold_cnt. Other cases like
 872  872           * vnic and aggr use their own scheme to serialize creates and deletes
 873  873           * and ensure that *ddp is valid.
 874  874           */
 875  875          rw_exit(&i_dls_devnet_lock);
 876  876          if (err == 0) {
 877  877                  if (zoneid != GLOBAL_ZONEID &&
 878  878                      (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE)) != 0)
 879  879                          (void) dls_devnet_unset(macname, &linkid, B_TRUE);
 880  880                  /*
 881  881                   * The kstat subsystem holds its own locks (rather perimeter)
 882  882                   * before calling the ks_update (dls_devnet_stat_update) entry
 883  883                   * point which in turn grabs the i_dls_devnet_lock. So the
 884  884                   * lock hierarchy is kstat locks -> i_dls_devnet_lock.
 885  885                   */
 886  886                  if (stat_create)
 887  887                          dls_devnet_stat_create(ddp, zoneid);
 888  888                  if (ddpp != NULL)
 889  889                          *ddpp = ddp;
 890  890          }
 891  891          return (err);
 892  892  }
 893  893  
 894  894  /*
 895  895   * Disassociate a linkid with a given link (identified by macname)
 896  896   * This waits until temporary references to the dls_devnet_t are gone.
 897  897   */
 898  898  static int
 899  899  dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait)
 900  900  {
 901  901          dls_devnet_t    *ddp;
 902  902          int             err;
 903  903          mod_hash_val_t  val;
 904  904  
 905  905          rw_enter(&i_dls_devnet_lock, RW_WRITER);
 906  906          if ((err = mod_hash_find(i_dls_devnet_hash,
 907  907              (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) {
 908  908                  ASSERT(err == MH_ERR_NOTFOUND);
 909  909                  rw_exit(&i_dls_devnet_lock);
 910  910                  return (ENOENT);
 911  911          }
 912  912  
 913  913          mutex_enter(&ddp->dd_mutex);
 914  914  
 915  915          /*
 916  916           * Make sure downcalls into softmac_create or softmac_destroy from
 917  917           * devfs don't cv_wait on any devfs related condition for fear of
 918  918           * deadlock. Return EBUSY if the asynchronous thread started for
 919  919           * property loading as part of the post attach hasn't yet completed.
 920  920           */
 921  921          ASSERT(ddp->dd_ref != 0);
 922  922          if ((ddp->dd_ref != 1) || (!wait &&
 923  923              (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {
 924  924                  mutex_exit(&ddp->dd_mutex);
 925  925                  rw_exit(&i_dls_devnet_lock);
 926  926                  return (EBUSY);
 927  927          }
 928  928  
 929  929          ddp->dd_flags |= DD_CONDEMNED;
 930  930          ddp->dd_ref--;
 931  931          *id = ddp->dd_linkid;
 932  932  
 933  933          if (ddp->dd_zid != GLOBAL_ZONEID)
 934  934                  (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
 935  935  
 936  936          /*
 937  937           * Remove this dls_devnet_t from the hash table.
 938  938           */
 939  939          VERIFY(mod_hash_remove(i_dls_devnet_hash,
 940  940              (mod_hash_key_t)ddp->dd_mac, &val) == 0);
 941  941  
 942  942          if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
 943  943                  VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
 944  944                      (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
 945  945  
 946  946                  devnet_need_rebuild = B_TRUE;
 947  947          }
 948  948          rw_exit(&i_dls_devnet_lock);
 949  949  
 950  950          if (wait) {
 951  951                  /*
 952  952                   * Wait until all temporary references are released.
 953  953                   */
 954  954                  while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
 955  955                          cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
 956  956          } else {
 957  957                  ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
 958  958          }
 959  959  
 960  960          if (ddp->dd_linkid != DATALINK_INVALID_LINKID)
 961  961                  dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);
 962  962  
 963  963          ddp->dd_prop_loaded = B_FALSE;
 964  964          ddp->dd_linkid = DATALINK_INVALID_LINKID;
 965  965          ddp->dd_flags = 0;
 966  966          mutex_exit(&ddp->dd_mutex);
  
    | 
      ↓ open down ↓ | 
    966 lines elided | 
    
      ↑ open up ↑ | 
  
 967  967          kmem_cache_free(i_dls_devnet_cachep, ddp);
 968  968  
 969  969          return (0);
 970  970  }
 971  971  
 972  972  static int
 973  973  dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp,
 974  974      boolean_t tmp_hold)
 975  975  {
 976  976          dls_devnet_t            *ddp;
 977      -        dev_t                   phydev = 0;
 978      -        dls_dev_handle_t        ddh = NULL;
 979  977          int                     err;
 980  978  
 981      -        /*
 982      -         * Hold this link to prevent it being detached in case of a
 983      -         * physical link.
 984      -         */
 985      -        if (dls_mgmt_get_phydev(linkid, &phydev) == 0)
 986      -                (void) softmac_hold_device(phydev, &ddh);
 987      -
 988  979          rw_enter(&i_dls_devnet_lock, RW_READER);
 989  980          if ((err = mod_hash_find(i_dls_devnet_id_hash,
 990  981              (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) {
 991  982                  ASSERT(err == MH_ERR_NOTFOUND);
 992  983                  rw_exit(&i_dls_devnet_lock);
 993      -                softmac_rele_device(ddh);
 994  984                  return (ENOENT);
 995  985          }
 996  986  
 997  987          mutex_enter(&ddp->dd_mutex);
 998  988          ASSERT(ddp->dd_ref > 0);
 999  989          if (ddp->dd_flags & DD_CONDEMNED) {
1000  990                  mutex_exit(&ddp->dd_mutex);
1001  991                  rw_exit(&i_dls_devnet_lock);
1002      -                softmac_rele_device(ddh);
1003  992                  return (ENOENT);
1004  993          }
1005  994          if (tmp_hold)
1006  995                  ddp->dd_tref++;
1007  996          else
1008  997                  ddp->dd_ref++;
1009  998          mutex_exit(&ddp->dd_mutex);
1010  999          rw_exit(&i_dls_devnet_lock);
1011 1000  
1012      -        softmac_rele_device(ddh);
1013      -
1014 1001          *ddpp = ddp;
1015 1002          return (0);
1016 1003  }
1017 1004  
1018 1005  int
1019 1006  dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp)
1020 1007  {
1021 1008          return (dls_devnet_hold_common(linkid, ddpp, B_FALSE));
1022 1009  }
1023 1010  
1024 1011  /*
1025 1012   * Hold the vanity naming structure (dls_devnet_t) temporarily.  The request to
  
    | 
      ↓ open down ↓ | 
    2 lines elided | 
    
      ↑ open up ↑ | 
  
1026 1013   * delete the dls_devnet_t will wait until the temporary reference is released.
1027 1014   */
1028 1015  int
1029 1016  dls_devnet_hold_tmp(datalink_id_t linkid, dls_devnet_t **ddpp)
1030 1017  {
1031 1018          return (dls_devnet_hold_common(linkid, ddpp, B_TRUE));
1032 1019  }
1033 1020  
1034 1021  /*
1035 1022   * This funtion is called when a DLS client tries to open a device node.
1036      - * This dev_t could a result of a /dev/net node access (returned by
     1023 + * This dev_t could be a result of a /dev/net node access (returned by
1037 1024   * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access.
1038 1025   * In both cases, this function bumps up the reference count of the
1039 1026   * dls_devnet_t structure. The reference is held as long as the device node
1040 1027   * is open. In the case of /dev/net while it is true that the initial reference
1041 1028   * is held when the devnet_create_rvp->dls_devnet_open call happens, this
1042 1029   * initial reference is released immediately in devnet_inactive_callback ->
1043 1030   * dls_devnet_close(). (Note that devnet_inactive_callback() is called right
1044 1031   * after dld_open completes, not when the /dev/net node is being closed).
1045 1032   * To undo this function, call dls_devnet_rele()
1046 1033   */
1047 1034  int
1048 1035  dls_devnet_hold_by_dev(dev_t dev, dls_dl_handle_t *ddhp)
1049 1036  {
1050 1037          char                    name[MAXNAMELEN];
1051 1038          char                    *drv;
1052      -        dls_dev_handle_t        ddh = NULL;
1053 1039          dls_devnet_t            *ddp;
1054 1040          int                     err;
1055 1041  
1056 1042          if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1057 1043                  return (EINVAL);
1058 1044  
1059 1045          (void) snprintf(name, sizeof (name), "%s%d", drv,
1060 1046              DLS_MINOR2INST(getminor(dev)));
1061 1047  
1062      -        /*
1063      -         * Hold this link to prevent it being detached in case of a
1064      -         * GLDv3 physical link.
1065      -         */
1066      -        if (DLS_MINOR2INST(getminor(dev)) <= DLS_MAX_PPA)
1067      -                (void) softmac_hold_device(dev, &ddh);
1068      -
1069 1048          rw_enter(&i_dls_devnet_lock, RW_READER);
1070 1049          if ((err = mod_hash_find(i_dls_devnet_hash,
1071 1050              (mod_hash_key_t)name, (mod_hash_val_t *)&ddp)) != 0) {
1072 1051                  ASSERT(err == MH_ERR_NOTFOUND);
1073 1052                  rw_exit(&i_dls_devnet_lock);
1074      -                softmac_rele_device(ddh);
1075 1053                  return (ENOENT);
1076 1054          }
1077 1055          mutex_enter(&ddp->dd_mutex);
1078 1056          ASSERT(ddp->dd_ref > 0);
1079 1057          if (ddp->dd_flags & DD_CONDEMNED) {
1080 1058                  mutex_exit(&ddp->dd_mutex);
1081 1059                  rw_exit(&i_dls_devnet_lock);
1082      -                softmac_rele_device(ddh);
1083 1060                  return (ENOENT);
1084 1061          }
1085 1062          ddp->dd_ref++;
1086 1063          mutex_exit(&ddp->dd_mutex);
1087 1064          rw_exit(&i_dls_devnet_lock);
1088 1065  
1089      -        softmac_rele_device(ddh);
1090      -
1091 1066          *ddhp = ddp;
1092 1067          return (0);
1093 1068  }
1094 1069  
1095 1070  void
1096 1071  dls_devnet_rele(dls_devnet_t *ddp)
1097 1072  {
1098 1073          mutex_enter(&ddp->dd_mutex);
1099 1074          ASSERT(ddp->dd_ref > 1);
1100 1075          ddp->dd_ref--;
1101 1076          if ((ddp->dd_flags & DD_IMPLICIT_IPTUN) && ddp->dd_ref == 1) {
1102 1077                  mutex_exit(&ddp->dd_mutex);
1103 1078                  if (i_dls_devnet_destroy_iptun(ddp->dd_linkid) != 0)
1104 1079                          ddp->dd_flags |= DD_IMPLICIT_IPTUN;
1105 1080                  return;
1106 1081          }
1107 1082          mutex_exit(&ddp->dd_mutex);
1108 1083  }
1109 1084  
1110 1085  static int
1111 1086  dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp)
1112 1087  {
1113 1088          char                    drv[MAXLINKNAMELEN];
1114 1089          uint_t                  ppa;
1115 1090          major_t                 major;
1116 1091          dev_t                   phy_dev, tmp_dev;
1117 1092          datalink_id_t           linkid;
1118 1093          dls_dev_handle_t        ddh;
1119 1094          int                     err;
1120 1095  
1121 1096          if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0)
1122 1097                  return (dls_devnet_hold(linkid, ddpp));
1123 1098  
1124 1099          /*
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
1125 1100           * If we failed to get the link's linkid because the dlmgmtd daemon
1126 1101           * has not been started, return ENOENT so that the application can
1127 1102           * fallback to open the /dev node.
1128 1103           */
1129 1104          if (err == EBADF)
1130 1105                  return (ENOENT);
1131 1106  
1132 1107          if (err != ENOENT)
1133 1108                  return (err);
1134 1109  
     1110 +        /*
     1111 +         * If we reach this point it means dlmgmtd is up but has no
     1112 +         * mapping for the link name.
     1113 +         */
1135 1114          if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS)
1136 1115                  return (ENOENT);
1137 1116  
1138 1117          if (IS_IPTUN_LINK(drv)) {
1139 1118                  if ((err = i_dls_devnet_create_iptun(link, drv, &linkid)) != 0)
1140 1119                          return (err);
1141 1120                  /*
1142 1121                   * At this point, an IP tunnel MAC has registered, which
1143 1122                   * resulted in a link being created.
1144 1123                   */
1145 1124                  err = dls_devnet_hold(linkid, ddpp);
1146      -                ASSERT(err == 0);
1147 1125                  if (err != 0) {
1148 1126                          VERIFY(i_dls_devnet_destroy_iptun(linkid) == 0);
1149 1127                          return (err);
1150 1128                  }
1151 1129                  /*
1152 1130                   * dls_devnet_rele() will know to destroy the implicit IP
1153 1131                   * tunnel on last reference release if DD_IMPLICIT_IPTUN is
1154 1132                   * set.
1155 1133                   */
1156 1134                  (*ddpp)->dd_flags |= DD_IMPLICIT_IPTUN;
1157 1135                  return (0);
1158 1136          }
1159 1137  
1160 1138          /*
1161 1139           * If this link:
1162 1140           * (a) is a physical device, (b) this is the first boot, (c) the MAC
1163 1141           * is not registered yet, and (d) we cannot find its linkid, then the
1164 1142           * linkname is the same as the devname.
1165 1143           *
1166 1144           * First filter out invalid names.
1167 1145           */
1168 1146          if ((major = ddi_name_to_major(drv)) == (major_t)-1)
1169 1147                  return (ENOENT);
1170 1148  
1171 1149          phy_dev = makedevice(major, DLS_PPA2MINOR(ppa));
1172 1150          if (softmac_hold_device(phy_dev, &ddh) != 0)
1173 1151                  return (ENOENT);
1174 1152  
1175 1153          /*
1176 1154           * At this time, the MAC should be registered, check its phy_dev using
1177 1155           * the given name.
1178 1156           */
1179 1157          if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0 ||
1180 1158              (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) {
1181 1159                  softmac_rele_device(ddh);
1182 1160                  return (err);
1183 1161          }
1184 1162          if (tmp_dev != phy_dev) {
1185 1163                  softmac_rele_device(ddh);
1186 1164                  return (ENOENT);
1187 1165          }
1188 1166  
1189 1167          err = dls_devnet_hold(linkid, ddpp);
1190 1168          softmac_rele_device(ddh);
1191 1169          return (err);
1192 1170  }
1193 1171  
1194 1172  int
1195 1173  dls_devnet_macname2linkid(const char *macname, datalink_id_t *linkidp)
1196 1174  {
1197 1175          dls_devnet_t    *ddp;
1198 1176  
1199 1177          rw_enter(&i_dls_devnet_lock, RW_READER);
1200 1178          if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)macname,
1201 1179              (mod_hash_val_t *)&ddp) != 0) {
1202 1180                  rw_exit(&i_dls_devnet_lock);
1203 1181                  return (ENOENT);
1204 1182          }
1205 1183  
1206 1184          *linkidp = ddp->dd_linkid;
1207 1185          rw_exit(&i_dls_devnet_lock);
1208 1186          return (0);
1209 1187  }
1210 1188  
1211 1189  /*
1212 1190   * Get linkid for the given dev.
1213 1191   */
1214 1192  int
1215 1193  dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp)
1216 1194  {
1217 1195          char    macname[MAXNAMELEN];
1218 1196          char    *drv;
1219 1197  
1220 1198          if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1221 1199                  return (EINVAL);
1222 1200  
1223 1201          (void) snprintf(macname, sizeof (macname), "%s%d", drv,
1224 1202              DLS_MINOR2INST(getminor(dev)));
1225 1203          return (dls_devnet_macname2linkid(macname, linkidp));
1226 1204  }
1227 1205  
1228 1206  /*
1229 1207   * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the
1230 1208   * link this VLAN is created on.
1231 1209   */
1232 1210  int
1233 1211  dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp)
1234 1212  {
1235 1213          dls_devnet_t    *ddp;
1236 1214          int             err;
1237 1215  
1238 1216          if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0)
1239 1217                  return (err);
1240 1218  
1241 1219          err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1242 1220          dls_devnet_rele_tmp(ddp);
1243 1221          return (err);
1244 1222  }
1245 1223  
1246 1224  /*
1247 1225   * Handle the renaming requests.  There are two rename cases:
1248 1226   *
1249 1227   * 1. Request to rename a valid link (id1) to an non-existent link name
1250 1228   *    (id2). In this case id2 is DATALINK_INVALID_LINKID.  Just check whether
1251 1229   *    id1 is held by any applications.
1252 1230   *
1253 1231   *    In this case, the link's kstats need to be updated using the given name.
1254 1232   *
1255 1233   * 2. Request to rename a valid link (id1) to the name of a REMOVED
1256 1234   *    physical link (id2). In this case, check that id1 and its associated
1257 1235   *    mac is not held by any application, and update the link's linkid to id2.
1258 1236   *
1259 1237   *    This case does not change the <link name, linkid> mapping, so the link's
1260 1238   *    kstats need to be updated with using name associated the given id2.
1261 1239   */
1262 1240  int
1263 1241  dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)
1264 1242  {
1265 1243          dls_dev_handle_t        ddh = NULL;
1266 1244          int                     err = 0;
1267 1245          dev_t                   phydev = 0;
1268 1246          dls_devnet_t            *ddp;
1269 1247          mac_perim_handle_t      mph = NULL;
1270 1248          mac_handle_t            mh;
1271 1249          mod_hash_val_t          val;
1272 1250  
1273 1251          /*
1274 1252           * In the second case, id2 must be a REMOVED physical link.
1275 1253           */
1276 1254          if ((id2 != DATALINK_INVALID_LINKID) &&
1277 1255              (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1278 1256              softmac_hold_device(phydev, &ddh) == 0) {
1279 1257                  softmac_rele_device(ddh);
1280 1258                  return (EEXIST);
1281 1259          }
1282 1260  
1283 1261          /*
1284 1262           * Hold id1 to prevent it from being detached (if a physical link).
1285 1263           */
1286 1264          if (dls_mgmt_get_phydev(id1, &phydev) == 0)
1287 1265                  (void) softmac_hold_device(phydev, &ddh);
1288 1266  
1289 1267          /*
1290 1268           * The framework does not hold hold locks across calls to the
1291 1269           * mac perimeter, hence enter the perimeter first. This also waits
1292 1270           * for the property loading to finish.
1293 1271           */
1294 1272          if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) {
1295 1273                  softmac_rele_device(ddh);
1296 1274                  return (err);
1297 1275          }
1298 1276  
1299 1277          rw_enter(&i_dls_devnet_lock, RW_WRITER);
1300 1278          if ((err = mod_hash_find(i_dls_devnet_id_hash,
1301 1279              (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
1302 1280                  ASSERT(err == MH_ERR_NOTFOUND);
1303 1281                  err = ENOENT;
1304 1282                  goto done;
1305 1283          }
1306 1284  
1307 1285          mutex_enter(&ddp->dd_mutex);
1308 1286          if (ddp->dd_ref > 1) {
1309 1287                  mutex_exit(&ddp->dd_mutex);
1310 1288                  err = EBUSY;
1311 1289                  goto done;
1312 1290          }
1313 1291          mutex_exit(&ddp->dd_mutex);
1314 1292  
1315 1293          if (id2 == DATALINK_INVALID_LINKID) {
1316 1294                  (void) strlcpy(ddp->dd_linkname, link,
1317 1295                      sizeof (ddp->dd_linkname));
1318 1296  
1319 1297                  /* rename mac client name and its flow if exists */
1320 1298                  if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1321 1299                          goto done;
1322 1300                  (void) mac_rename_primary(mh, link);
1323 1301                  mac_close(mh);
1324 1302                  goto done;
1325 1303          }
1326 1304  
1327 1305          /*
1328 1306           * The second case, check whether the MAC is used by any MAC
1329 1307           * user.  This must be a physical link so ddh must not be NULL.
1330 1308           */
1331 1309          if (ddh == NULL) {
1332 1310                  err = EINVAL;
1333 1311                  goto done;
1334 1312          }
1335 1313  
1336 1314          if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1337 1315                  goto done;
1338 1316  
1339 1317          /*
1340 1318           * We release the reference of the MAC which mac_open() is
1341 1319           * holding. Note that this mac will not be unregistered
1342 1320           * because the physical device is held.
1343 1321           */
1344 1322          mac_close(mh);
1345 1323  
1346 1324          /*
1347 1325           * Check if there is any other MAC clients, if not, hold this mac
1348 1326           * exclusively until we are done.
1349 1327           */
1350 1328          if ((err = mac_mark_exclusive(mh)) != 0)
1351 1329                  goto done;
1352 1330  
1353 1331          /*
1354 1332           * Update the link's linkid.
1355 1333           */
1356 1334          if ((err = mod_hash_find(i_dls_devnet_id_hash,
1357 1335              (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) {
1358 1336                  mac_unmark_exclusive(mh);
1359 1337                  err = EEXIST;
1360 1338                  goto done;
1361 1339          }
1362 1340  
1363 1341          err = dls_mgmt_get_linkinfo(id2, ddp->dd_linkname, NULL, NULL, NULL);
1364 1342          if (err != 0) {
1365 1343                  mac_unmark_exclusive(mh);
1366 1344                  goto done;
1367 1345          }
1368 1346  
1369 1347          (void) mod_hash_remove(i_dls_devnet_id_hash,
1370 1348              (mod_hash_key_t)(uintptr_t)id1, &val);
1371 1349  
1372 1350          ddp->dd_linkid = id2;
1373 1351          (void) mod_hash_insert(i_dls_devnet_id_hash,
1374 1352              (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, (mod_hash_val_t)ddp);
1375 1353  
1376 1354          mac_unmark_exclusive(mh);
1377 1355  
1378 1356          /* load properties for new id */
1379 1357          mutex_enter(&ddp->dd_mutex);
1380 1358          ddp->dd_prop_loaded = B_FALSE;
1381 1359          ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
1382 1360              dls_devnet_prop_task, ddp, TQ_SLEEP);
1383 1361          mutex_exit(&ddp->dd_mutex);
1384 1362  
1385 1363  done:
1386 1364          rw_exit(&i_dls_devnet_lock);
1387 1365  
1388 1366          if (err == 0)
1389 1367                  dls_devnet_stat_rename(ddp);
1390 1368  
1391 1369          if (mph != NULL)
1392 1370                  mac_perim_exit(mph);
1393 1371          softmac_rele_device(ddh);
1394 1372          return (err);
1395 1373  }
1396 1374  
1397 1375  static int
1398 1376  i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop)
1399 1377  {
1400 1378          int                     err;
1401 1379          mac_perim_handle_t      mph;
1402 1380          boolean_t               upcall_done = B_FALSE;
1403 1381          datalink_id_t           linkid = ddp->dd_linkid;
1404 1382          zoneid_t                old_zoneid = ddp->dd_zid;
1405 1383          dlmgmt_door_setzoneid_t setzid;
1406 1384          dlmgmt_setzoneid_retval_t retval;
1407 1385  
1408 1386          if (old_zoneid == new_zoneid)
1409 1387                  return (0);
1410 1388  
1411 1389          if ((err = mac_perim_enter_by_macname(ddp->dd_mac, &mph)) != 0)
1412 1390                  return (err);
1413 1391  
1414 1392          /*
1415 1393           * When changing the zoneid of an existing link, we need to tell
1416 1394           * dlmgmtd about it.  dlmgmtd already knows the zoneid associated with
1417 1395           * newly created links.
1418 1396           */
1419 1397          if (setprop) {
1420 1398                  setzid.ld_cmd = DLMGMT_CMD_SETZONEID;
1421 1399                  setzid.ld_linkid = linkid;
1422 1400                  setzid.ld_zoneid = new_zoneid;
1423 1401                  err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1424 1402                      sizeof (retval));
1425 1403                  if (err != 0)
1426 1404                          goto done;
1427 1405                  upcall_done = B_TRUE;
1428 1406          }
1429 1407          if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
1430 1408                  ddp->dd_zid = new_zoneid;
1431 1409                  devnet_need_rebuild = B_TRUE;
1432 1410          }
1433 1411  
1434 1412  done:
1435 1413          if (err != 0 && upcall_done) {
1436 1414                  setzid.ld_zoneid = old_zoneid;
1437 1415                  (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1438 1416                      sizeof (retval));
1439 1417          }
1440 1418          mac_perim_exit(mph);
1441 1419          return (err);
1442 1420  }
1443 1421  
1444 1422  int
1445 1423  dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid)
1446 1424  {
1447 1425          dls_devnet_t    *ddp;
1448 1426          int             err;
1449 1427          zoneid_t        old_zid;
1450 1428          boolean_t       refheld = B_FALSE;
1451 1429  
1452 1430          old_zid = ddh->dd_zid;
1453 1431  
1454 1432          if (old_zid == new_zid)
1455 1433                  return (0);
1456 1434  
1457 1435          /*
1458 1436           * Acquire an additional reference to the link if it is being assigned
1459 1437           * to a non-global zone from the global zone.
1460 1438           */
1461 1439          if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
1462 1440                  if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
1463 1441                          return (err);
1464 1442                  refheld = B_TRUE;
1465 1443          }
1466 1444  
1467 1445          if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE)) != 0) {
1468 1446                  if (refheld)
1469 1447                          dls_devnet_rele(ddp);
1470 1448                  return (err);
1471 1449          }
1472 1450  
1473 1451          /*
1474 1452           * Release the additional reference if the link is returning to the
1475 1453           * global zone from a non-global zone.
1476 1454           */
1477 1455          if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
1478 1456                  dls_devnet_rele(ddh);
1479 1457  
1480 1458          /* Re-create kstats in the appropriate zones. */
1481 1459          if (old_zid != GLOBAL_ZONEID)
1482 1460                  dls_devnet_stat_destroy(ddh, old_zid);
1483 1461          if (new_zid != GLOBAL_ZONEID)
1484 1462                  dls_devnet_stat_create(ddh, new_zid);
1485 1463  
1486 1464          return (0);
1487 1465  }
1488 1466  
1489 1467  zoneid_t
1490 1468  dls_devnet_getzid(dls_dl_handle_t ddh)
1491 1469  {
1492 1470          return (((dls_devnet_t *)ddh)->dd_zid);
1493 1471  }
1494 1472  
1495 1473  zoneid_t
1496 1474  dls_devnet_getownerzid(dls_dl_handle_t ddh)
1497 1475  {
1498 1476          return (((dls_devnet_t *)ddh)->dd_owner_zid);
1499 1477  }
1500 1478  
1501 1479  /*
1502 1480   * Is linkid visible from zoneid?  A link is visible if it was created in the
1503 1481   * zone, or if it is currently assigned to the zone.
1504 1482   */
1505 1483  boolean_t
1506 1484  dls_devnet_islinkvisible(datalink_id_t linkid, zoneid_t zoneid)
1507 1485  {
1508 1486          dls_devnet_t    *ddp;
1509 1487          boolean_t       result;
1510 1488  
1511 1489          if (dls_devnet_hold_tmp(linkid, &ddp) != 0)
1512 1490                  return (B_FALSE);
1513 1491          result = (ddp->dd_owner_zid == zoneid || ddp->dd_zid == zoneid);
1514 1492          dls_devnet_rele_tmp(ddp);
1515 1493          return (result);
1516 1494  }
1517 1495  
1518 1496  /*
1519 1497   * Access a vanity naming node.
1520 1498   */
1521 1499  int
1522 1500  dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp)
1523 1501  {
1524 1502          dls_devnet_t    *ddp;
1525 1503          dls_link_t      *dlp;
1526 1504          zoneid_t        zid = getzoneid();
1527 1505          int             err;
1528 1506          mac_perim_handle_t      mph;
1529 1507  
1530 1508          if ((err = dls_devnet_hold_by_name(link, &ddp)) != 0)
1531 1509                  return (err);
1532 1510  
1533 1511          dls_devnet_prop_task_wait(ddp);
1534 1512  
1535 1513          /*
1536 1514           * Opening a link that does not belong to the current non-global zone
1537 1515           * is not allowed.
1538 1516           */
1539 1517          if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) {
1540 1518                  dls_devnet_rele(ddp);
1541 1519                  return (ENOENT);
1542 1520          }
1543 1521  
1544 1522          err = mac_perim_enter_by_macname(ddp->dd_mac, &mph);
1545 1523          if (err != 0) {
1546 1524                  dls_devnet_rele(ddp);
1547 1525                  return (err);
1548 1526          }
1549 1527  
1550 1528          err = dls_link_hold_create(ddp->dd_mac, &dlp);
1551 1529          mac_perim_exit(mph);
1552 1530  
1553 1531          if (err != 0) {
1554 1532                  dls_devnet_rele(ddp);
1555 1533                  return (err);
1556 1534          }
1557 1535  
1558 1536          *dhp = ddp;
1559 1537          *devp = dls_link_dev(dlp);
1560 1538          return (0);
1561 1539  }
1562 1540  
1563 1541  /*
1564 1542   * Close access to a vanity naming node.
1565 1543   */
1566 1544  void
1567 1545  dls_devnet_close(dls_dl_handle_t dlh)
1568 1546  {
1569 1547          dls_devnet_t    *ddp = dlh;
1570 1548          dls_link_t      *dlp;
1571 1549          mac_perim_handle_t      mph;
1572 1550  
1573 1551          VERIFY(mac_perim_enter_by_macname(ddp->dd_mac, &mph) == 0);
1574 1552          VERIFY(dls_link_hold(ddp->dd_mac, &dlp) == 0);
1575 1553  
1576 1554          /*
1577 1555           * One rele for the hold placed in dls_devnet_open, another for
1578 1556           * the hold done just above
1579 1557           */
1580 1558          dls_link_rele(dlp);
1581 1559          dls_link_rele(dlp);
1582 1560          mac_perim_exit(mph);
1583 1561  
1584 1562          dls_devnet_rele(ddp);
1585 1563  }
1586 1564  
1587 1565  /*
1588 1566   * This is used by /dev/net to rebuild the nodes for readdir().  It is not
1589 1567   * critical and no protection is needed.
1590 1568   */
1591 1569  boolean_t
1592 1570  dls_devnet_rebuild()
1593 1571  {
1594 1572          boolean_t updated = devnet_need_rebuild;
1595 1573  
1596 1574          devnet_need_rebuild = B_FALSE;
1597 1575          return (updated);
1598 1576  }
1599 1577  
1600 1578  int
1601 1579  dls_devnet_create(mac_handle_t mh, datalink_id_t linkid, zoneid_t zoneid)
1602 1580  {
1603 1581          dls_link_t      *dlp;
1604 1582          dls_devnet_t    *ddp;
1605 1583          int             err;
1606 1584          mac_perim_handle_t mph;
1607 1585  
1608 1586          /*
1609 1587           * Holding the mac perimeter ensures that the downcall from the
1610 1588           * dlmgmt daemon which does the property loading does not proceed
1611 1589           * until we relinquish the perimeter.
1612 1590           */
1613 1591          mac_perim_enter_by_mh(mh, &mph);
1614 1592          /*
1615 1593           * Make this association before we call dls_link_hold_create as
1616 1594           * we need to use the linkid to get the user name for the link
1617 1595           * when we create the MAC client.
1618 1596           */
1619 1597          if ((err = dls_devnet_set(mac_name(mh), linkid, zoneid, &ddp)) == 0) {
1620 1598                  if ((err = dls_link_hold_create(mac_name(mh), &dlp)) != 0) {
1621 1599                          mac_perim_exit(mph);
1622 1600                          (void) dls_devnet_unset(mac_name(mh), &linkid, B_TRUE);
1623 1601                          return (err);
1624 1602                  }
1625 1603          }
1626 1604          mac_perim_exit(mph);
1627 1605          return (err);
1628 1606  }
1629 1607  
1630 1608  /*
1631 1609   * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash.
1632 1610   * This is called in the case that the dlmgmtd daemon is started later than
1633 1611   * the physical devices get attached, and the linkid is only known after the
1634 1612   * daemon starts.
1635 1613   */
1636 1614  int
1637 1615  dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid)
1638 1616  {
1639 1617          ASSERT(linkid != DATALINK_INVALID_LINKID);
1640 1618          return (dls_devnet_set(mac_name(mh), linkid, GLOBAL_ZONEID, NULL));
1641 1619  }
1642 1620  
1643 1621  int
1644 1622  dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp, boolean_t wait)
1645 1623  {
1646 1624          int                     err;
1647 1625          mac_perim_handle_t      mph;
1648 1626  
1649 1627          *idp = DATALINK_INVALID_LINKID;
1650 1628          err = dls_devnet_unset(mac_name(mh), idp, wait);
1651 1629          if (err != 0 && err != ENOENT)
1652 1630                  return (err);
1653 1631  
1654 1632          mac_perim_enter_by_mh(mh, &mph);
1655 1633          err = dls_link_rele_by_name(mac_name(mh));
1656 1634          mac_perim_exit(mph);
1657 1635  
1658 1636          if (err != 0) {
1659 1637                  /*
1660 1638                   * XXX It is a general GLDv3 bug that dls_devnet_set() has to
1661 1639                   * be called to re-set the link when destroy fails.  The
1662 1640                   * zoneid below will be incorrect if this function is ever
1663 1641                   * called from kernel context or from a zone other than that
1664 1642                   * which initially created the link.
1665 1643                   */
1666 1644                  (void) dls_devnet_set(mac_name(mh), *idp, crgetzoneid(CRED()),
1667 1645                      NULL);
1668 1646          }
1669 1647          return (err);
1670 1648  }
1671 1649  
1672 1650  /*
1673 1651   * Implicitly create an IP tunnel link.
1674 1652   */
1675 1653  static int
1676 1654  i_dls_devnet_create_iptun(const char *linkname, const char *drvname,
1677 1655      datalink_id_t *linkid)
1678 1656  {
1679 1657          int             err;
1680 1658          iptun_kparams_t ik;
1681 1659          uint32_t        media;
1682 1660          netstack_t      *ns;
1683 1661          major_t         iptun_major;
1684 1662          dev_info_t      *iptun_dip;
1685 1663  
1686 1664          /* First ensure that the iptun device is attached. */
1687 1665          if ((iptun_major = ddi_name_to_major(IPTUN_DRIVER_NAME)) == (major_t)-1)
1688 1666                  return (EINVAL);
1689 1667          if ((iptun_dip = ddi_hold_devi_by_instance(iptun_major, 0, 0)) == NULL)
1690 1668                  return (EINVAL);
1691 1669  
1692 1670          if (IS_IPV4_TUN(drvname)) {
1693 1671                  ik.iptun_kparam_type = IPTUN_TYPE_IPV4;
1694 1672                  media = DL_IPV4;
1695 1673          } else if (IS_6TO4_TUN(drvname)) {
1696 1674                  ik.iptun_kparam_type = IPTUN_TYPE_6TO4;
1697 1675                  media = DL_6TO4;
1698 1676          } else if (IS_IPV6_TUN(drvname)) {
1699 1677                  ik.iptun_kparam_type = IPTUN_TYPE_IPV6;
1700 1678                  media = DL_IPV6;
1701 1679          }
1702 1680          ik.iptun_kparam_flags = (IPTUN_KPARAM_TYPE | IPTUN_KPARAM_IMPLICIT);
1703 1681  
1704 1682          /* Obtain a datalink id for this tunnel. */
1705 1683          err = dls_mgmt_create((char *)linkname, 0, DATALINK_CLASS_IPTUN, media,
1706 1684              B_FALSE, &ik.iptun_kparam_linkid);
1707 1685          if (err != 0) {
1708 1686                  ddi_release_devi(iptun_dip);
1709 1687                  return (err);
1710 1688          }
1711 1689  
1712 1690          ns = netstack_get_current();
1713 1691          err = iptun_create(&ik, CRED());
1714 1692          netstack_rele(ns);
1715 1693  
1716 1694          if (err != 0)
1717 1695                  VERIFY(dls_mgmt_destroy(ik.iptun_kparam_linkid, B_FALSE) == 0);
1718 1696          else
1719 1697                  *linkid = ik.iptun_kparam_linkid;
1720 1698  
1721 1699          ddi_release_devi(iptun_dip);
1722 1700          return (err);
1723 1701  }
1724 1702  
1725 1703  static int
1726 1704  i_dls_devnet_destroy_iptun(datalink_id_t linkid)
1727 1705  {
1728 1706          int err;
1729 1707  
1730 1708          /*
1731 1709           * Note the use of zone_kcred() here as opposed to CRED().  This is
1732 1710           * because the process that does the last close of this /dev/net node
1733 1711           * may not have necessary privileges to delete this IP tunnel, but the
1734 1712           * tunnel must always be implicitly deleted on last close.
1735 1713           */
1736 1714          if ((err = iptun_delete(linkid, zone_kcred())) == 0)
1737 1715                  (void) dls_mgmt_destroy(linkid, B_FALSE);
1738 1716          return (err);
1739 1717  }
1740 1718  
1741 1719  const char *
1742 1720  dls_devnet_mac(dls_dl_handle_t ddh)
1743 1721  {
1744 1722          return (ddh->dd_mac);
1745 1723  }
1746 1724  
1747 1725  datalink_id_t
1748 1726  dls_devnet_linkid(dls_dl_handle_t ddh)
1749 1727  {
1750 1728          return (ddh->dd_linkid);
1751 1729  }
  
    | 
      ↓ open down ↓ | 
    595 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX