Print this page
OS-1885 deadlock between vnic destroy and kstat read
OS-676 debug kernel blew assertion in dls_devnet_stat_create()
OS-428 add link zonename kstat
OS-406
OS-327
OS-276 global zone duplicate kstat when two zones have same vnic name
OS-249


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.

  24  */
  25 
  26 /*
  27  * Datalink management routines.
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/door.h>
  32 #include <sys/zone.h>
  33 #include <sys/modctl.h>
  34 #include <sys/file.h>
  35 #include <sys/modhash.h>
  36 #include <sys/kstat.h>
  37 #include <sys/vnode.h>
  38 #include <sys/cmn_err.h>
  39 #include <sys/softmac.h>
  40 #include <sys/dls.h>
  41 #include <sys/dls_impl.h>
  42 #include <sys/stropts.h>
  43 #include <sys/netstack.h>


  88  * This structure itself is not protected by the mac perimeter, but is
  89  * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the
  90  * functions manipulating this structure such as dls_devnet_set/unset etc.
  91  * may be called while not holding the mac perimeter.
  92  */
  93 typedef struct dls_devnet_s {
  94         datalink_id_t   dd_linkid;
  95         char            dd_linkname[MAXLINKNAMELEN];
  96         char            dd_mac[MAXNAMELEN];
  97         kstat_t         *dd_ksp;        /* kstat in owner_zid */
  98         kstat_t         *dd_zone_ksp;   /* in dd_zid if != owner_zid */
  99         uint32_t        dd_ref;
 100         kmutex_t        dd_mutex;
 101         kcondvar_t      dd_cv;
 102         uint32_t        dd_tref;
 103         uint_t          dd_flags;
 104         zoneid_t        dd_owner_zid;   /* zone where node was created */
 105         zoneid_t        dd_zid;         /* current zone */
 106         boolean_t       dd_prop_loaded;
 107         taskqid_t       dd_prop_taskid;

 108 } dls_devnet_t;
 109 
 110 static int i_dls_devnet_create_iptun(const char *, const char *,
 111     datalink_id_t *);
 112 static int i_dls_devnet_destroy_iptun(datalink_id_t);
 113 static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t);
 114 static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
 115 
 116 /*ARGSUSED*/
 117 static int
 118 i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
 119 {
 120         dls_devnet_t    *ddp = buf;
 121 
 122         bzero(buf, sizeof (dls_devnet_t));
 123         mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
 124         cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
 125         return (0);
 126 }
 127 
 128 /*ARGSUSED*/
 129 static void
 130 i_dls_devnet_destructor(void *buf, void *arg)
 131 {
 132         dls_devnet_t    *ddp = buf;
 133 
 134         ASSERT(ddp->dd_ksp == NULL);
 135         ASSERT(ddp->dd_ref == 0);
 136         ASSERT(ddp->dd_tref == 0);
 137         mutex_destroy(&ddp->dd_mutex);
 138         cv_destroy(&ddp->dd_cv);
 139 }
 140 
 141 /* ARGSUSED */
 142 static int
 143 dls_zone_remove(datalink_id_t linkid, void *arg)
 144 {
 145         dls_devnet_t *ddp;
 146 
 147         if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
 148                 (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID);





 149                 dls_devnet_rele_tmp(ddp);
 150         }
 151         return (0);
 152 }
 153 
 154 /* ARGSUSED */
 155 static void *
 156 dls_stack_init(netstackid_t stackid, netstack_t *ns)
 157 {
 158         dls_stack_t *dlss;
 159 
 160         dlss = kmem_zalloc(sizeof (*dlss), KM_SLEEP);
 161         dlss->dlss_zoneid = netstackid_to_zoneid(stackid);
 162         return (dlss);
 163 }
 164 
 165 /* ARGSUSED */
 166 static void
 167 dls_stack_shutdown(netstackid_t stackid, void *arg)
 168 {


 509                 *mediap = retval.lr_media;
 510         if (flagsp != NULL)
 511                 *flagsp = retval.lr_flags;
 512         return (0);
 513 }
 514 
 515 /*
 516  * Request the datalink management daemon to get the linkid for a link.
 517  * Returns a non-zero error code on failure.  The linkid argument is only
 518  * set on success (when zero is returned.)
 519  */
 520 int
 521 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
 522 {
 523         dlmgmt_door_getlinkid_t         getlinkid;
 524         dlmgmt_getlinkid_retval_t       retval;
 525         int                             err;
 526 
 527         getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
 528         (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);

 529 
 530         if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
 531             sizeof (retval))) == 0) {
 532                 *linkid = retval.lr_linkid;
 533         }
 534         return (err);
 535 }
 536 
 537 datalink_id_t
 538 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
 539     datalink_media_t dmedia, uint32_t flags)
 540 {
 541         dlmgmt_door_getnext_t   getnext;
 542         dlmgmt_getnext_retval_t retval;
 543 
 544         getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
 545         getnext.ld_class = class;
 546         getnext.ld_dmedia = dmedia;
 547         getnext.ld_flags = flags;
 548         getnext.ld_linkid = linkid;


 723          * If a device detach happens at this time, it will block in
 724          * dls_devnet_unset since the dd_tref has been bumped up above. So the
 725          * access to 'dlp' is safe even though we don't hold the mac perimeter.
 726          */
 727         if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac,
 728             (mod_hash_val_t *)&dlp) != 0) {
 729                 dls_devnet_rele_tmp(ddp);
 730                 return (ENOENT);
 731         }
 732 
 733         err = dls_stat_update(ksp, dlp, rw);
 734 
 735         dls_devnet_rele_tmp(ddp);
 736         return (err);
 737 }
 738 
 739 /*
 740  * Create the "link" kstats.
 741  */
 742 static void
 743 dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid)
 744 {
 745         kstat_t *ksp;


 746 
 747         if (dls_stat_create("link", 0, ddp->dd_linkname, zoneid,
 748             dls_devnet_stat_update, ddp, &ksp) == 0) {









 749                 ASSERT(ksp != NULL);
 750                 if (zoneid == ddp->dd_owner_zid) {
 751                         ASSERT(ddp->dd_ksp == NULL);
 752                         ddp->dd_ksp = ksp;
 753                 } else {
 754                         ASSERT(ddp->dd_zone_ksp == NULL);
 755                         ddp->dd_zone_ksp = ksp;
 756                 }
 757         }
 758 }
 759 
 760 /*
 761  * Destroy the "link" kstats.
 762  */
 763 static void
 764 dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
 765 {
 766         if (zoneid == ddp->dd_owner_zid) {
 767                 if (ddp->dd_ksp != NULL) {
 768                         kstat_delete(ddp->dd_ksp);
 769                         ddp->dd_ksp = NULL;
 770                 }
 771         } else {
 772                 if (ddp->dd_zone_ksp != NULL) {
 773                         kstat_delete(ddp->dd_zone_ksp);
 774                         ddp->dd_zone_ksp = NULL;
 775                 }
 776         }
 777 }
 778 
 779 /*
 780  * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
 781  * and create the new set using the new name.
 782  */
 783 static void
 784 dls_devnet_stat_rename(dls_devnet_t *ddp)
 785 {
 786         if (ddp->dd_ksp != NULL) {
 787                 kstat_delete(ddp->dd_ksp);
 788                 ddp->dd_ksp = NULL;
 789         }
 790         /* We can't rename a link while it's assigned to a non-global zone. */







 791         ASSERT(ddp->dd_zone_ksp == NULL);
 792         dls_devnet_stat_create(ddp, ddp->dd_owner_zid);



 793 }
 794 
 795 /*
 796  * Associate a linkid with a given link (identified by macname)
 797  */
 798 static int
 799 dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
 800     dls_devnet_t **ddpp)
 801 {
 802         dls_devnet_t            *ddp = NULL;
 803         datalink_class_t        class;
 804         int                     err;
 805         boolean_t               stat_create = B_FALSE;
 806         char                    linkname[MAXLINKNAMELEN];
 807 
 808         rw_enter(&i_dls_devnet_lock, RW_WRITER);
 809 
 810         /*
 811          * Don't allow callers to set a link name with a linkid that already
 812          * has a name association (that's what rename is for).


 861                 stat_create = B_TRUE;
 862                 mutex_enter(&ddp->dd_mutex);
 863                 if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) {
 864                         ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
 865                             dls_devnet_prop_task, ddp, TQ_SLEEP);
 866                 }
 867                 mutex_exit(&ddp->dd_mutex);
 868         }
 869         err = 0;
 870 done:
 871         /*
 872          * It is safe to drop the i_dls_devnet_lock at this point. In the case
 873          * of physical devices, the softmac framework will fail the device
 874          * detach based on the smac_state or smac_hold_cnt. Other cases like
 875          * vnic and aggr use their own scheme to serialize creates and deletes
 876          * and ensure that *ddp is valid.
 877          */
 878         rw_exit(&i_dls_devnet_lock);
 879         if (err == 0) {
 880                 if (zoneid != GLOBAL_ZONEID &&
 881                     (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE)) != 0)

 882                         (void) dls_devnet_unset(macname, &linkid, B_TRUE);
 883                 /*
 884                  * The kstat subsystem holds its own locks (rather perimeter)
 885                  * before calling the ks_update (dls_devnet_stat_update) entry
 886                  * point which in turn grabs the i_dls_devnet_lock. So the
 887                  * lock hierarchy is kstat locks -> i_dls_devnet_lock.
 888                  */
 889                 if (stat_create)
 890                         dls_devnet_stat_create(ddp, zoneid);
 891                 if (ddpp != NULL)
 892                         *ddpp = ddp;
 893         }
 894         return (err);
 895 }
 896 
 897 /*
 898  * Disassociate a linkid with a given link (identified by macname)
 899  * This waits until temporary references to the dls_devnet_t are gone.
 900  */
 901 static int
 902 dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait)
 903 {
 904         dls_devnet_t    *ddp;
 905         int             err;
 906         mod_hash_val_t  val;
 907 
 908         rw_enter(&i_dls_devnet_lock, RW_WRITER);
 909         if ((err = mod_hash_find(i_dls_devnet_hash,
 910             (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) {
 911                 ASSERT(err == MH_ERR_NOTFOUND);
 912                 rw_exit(&i_dls_devnet_lock);
 913                 return (ENOENT);
 914         }
 915 
 916         mutex_enter(&ddp->dd_mutex);
 917 
 918         /*
 919          * Make sure downcalls into softmac_create or softmac_destroy from
 920          * devfs don't cv_wait on any devfs related condition for fear of
 921          * deadlock. Return EBUSY if the asynchronous thread started for
 922          * property loading as part of the post attach hasn't yet completed.
 923          */
 924         ASSERT(ddp->dd_ref != 0);
 925         if ((ddp->dd_ref != 1) || (!wait &&
 926             (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {


































 927                 mutex_exit(&ddp->dd_mutex);
 928                 rw_exit(&i_dls_devnet_lock);
 929                 return (EBUSY);
 930         }
 931 










 932         ddp->dd_flags |= DD_CONDEMNED;
 933         ddp->dd_ref--;
 934         *id = ddp->dd_linkid;
 935 
 936         if (ddp->dd_zid != GLOBAL_ZONEID)
 937                 (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);

















 938 
 939         /*
 940          * Remove this dls_devnet_t from the hash table.
 941          */
 942         VERIFY(mod_hash_remove(i_dls_devnet_hash,
 943             (mod_hash_key_t)ddp->dd_mac, &val) == 0);
 944 
 945         if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
 946                 VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
 947                     (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
 948 
 949                 devnet_need_rebuild = B_TRUE;
 950         }
 951         rw_exit(&i_dls_devnet_lock);
 952 
 953         if (wait) {
 954                 /*
 955                  * Wait until all temporary references are released.
 956                  */
 957                 while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
 958                         cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
 959         } else {
 960                 ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
 961         }
 962 
 963         if (ddp->dd_linkid != DATALINK_INVALID_LINKID)




 964                 dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);


 965 

 966         ddp->dd_prop_loaded = B_FALSE;
 967         ddp->dd_linkid = DATALINK_INVALID_LINKID;
 968         ddp->dd_flags = 0;
 969         mutex_exit(&ddp->dd_mutex);
 970         kmem_cache_free(i_dls_devnet_cachep, ddp);
 971 
 972         return (0);
 973 }
 974 
 975 static int
 976 dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp,
 977     boolean_t tmp_hold)
 978 {
 979         dls_devnet_t            *ddp;
 980         dev_t                   phydev = 0;
 981         dls_dev_handle_t        ddh = NULL;
 982         int                     err;
 983 
 984         /*
 985          * Hold this link to prevent it being detached in case of a


1244         err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1245         dls_devnet_rele_tmp(ddp);
1246         return (err);
1247 }
1248 
1249 /*
1250  * Handle the renaming requests.  There are two rename cases:
1251  *
1252  * 1. Request to rename a valid link (id1) to an non-existent link name
1253  *    (id2). In this case id2 is DATALINK_INVALID_LINKID.  Just check whether
1254  *    id1 is held by any applications.
1255  *
1256  *    In this case, the link's kstats need to be updated using the given name.
1257  *
1258  * 2. Request to rename a valid link (id1) to the name of a REMOVED
1259  *    physical link (id2). In this case, check that id1 and its associated
1260  *    mac is not held by any application, and update the link's linkid to id2.
1261  *
1262  *    This case does not change the <link name, linkid> mapping, so the link's
1263  *    kstats need to be updated with using name associated the given id2.





1264  */
1265 int
1266 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)

1267 {
1268         dls_dev_handle_t        ddh = NULL;
1269         int                     err = 0;
1270         dev_t                   phydev = 0;
1271         dls_devnet_t            *ddp;
1272         mac_perim_handle_t      mph = NULL;
1273         mac_handle_t            mh;
1274         mod_hash_val_t          val;
1275         boolean_t               clear_dd_flag = B_FALSE;
1276 
1277         /*
1278          * In the second case, id2 must be a REMOVED physical link.
1279          */
1280         if ((id2 != DATALINK_INVALID_LINKID) &&
1281             (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1282             softmac_hold_device(phydev, &ddh) == 0) {
1283                 softmac_rele_device(ddh);
1284                 return (EEXIST);
1285         }
1286 


1296          * for the property loading to finish.
1297          */
1298         if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) {
1299                 softmac_rele_device(ddh);
1300                 return (err);
1301         }
1302 
1303         rw_enter(&i_dls_devnet_lock, RW_WRITER);
1304         if ((err = mod_hash_find(i_dls_devnet_id_hash,
1305             (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
1306                 ASSERT(err == MH_ERR_NOTFOUND);
1307                 err = ENOENT;
1308                 goto done;
1309         }
1310 
1311         /*
1312          * Return EBUSY if any applications have this link open, if any thread
1313          * is currently accessing the link kstats, or if the link is on-loan
1314          * to a non-global zone. Then set the DD_KSTAT_CHANGING flag to
1315          * prevent any access to the kstats while we delete and recreate
1316          * kstats below.

1317          */
1318         mutex_enter(&ddp->dd_mutex);

1319         if (ddp->dd_ref > 1) {
1320                 mutex_exit(&ddp->dd_mutex);
1321                 err = EBUSY;
1322                 goto done;
1323         }

1324 
1325         ddp->dd_flags |= DD_KSTAT_CHANGING;
1326         clear_dd_flag = B_TRUE;
1327         mutex_exit(&ddp->dd_mutex);
1328 
1329         if (id2 == DATALINK_INVALID_LINKID) {
1330                 (void) strlcpy(ddp->dd_linkname, link,
1331                     sizeof (ddp->dd_linkname));
1332 
1333                 /* rename mac client name and its flow if exists */
1334                 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1335                         goto done;







1336                 (void) mac_rename_primary(mh, link);

1337                 mac_close(mh);
1338                 goto done;
1339         }
1340 
1341         /*
1342          * The second case, check whether the MAC is used by any MAC
1343          * user.  This must be a physical link so ddh must not be NULL.
1344          */
1345         if (ddh == NULL) {
1346                 err = EINVAL;
1347                 goto done;
1348         }
1349 
1350         if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1351                 goto done;
1352 
1353         /*
1354          * We release the reference of the MAC which mac_open() is
1355          * holding. Note that this mac will not be unregistered
1356          * because the physical device is held.


1389 
1390         mac_unmark_exclusive(mh);
1391 
1392         /* load properties for new id */
1393         mutex_enter(&ddp->dd_mutex);
1394         ddp->dd_prop_loaded = B_FALSE;
1395         ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
1396             dls_devnet_prop_task, ddp, TQ_SLEEP);
1397         mutex_exit(&ddp->dd_mutex);
1398 
1399 done:
1400         /*
1401          * Change the name of the kstat based on the new link name.
1402          * We can't hold the i_dls_devnet_lock across calls to the kstat
1403          * subsystem. Instead the DD_KSTAT_CHANGING flag set above in this
1404          * function prevents any access to the dd_ksp while we delete and
1405          * recreate it below.
1406          */
1407         rw_exit(&i_dls_devnet_lock);
1408         if (err == 0)
1409                 dls_devnet_stat_rename(ddp);
1410 
1411         if (clear_dd_flag) {
1412                 mutex_enter(&ddp->dd_mutex);
1413                 ddp->dd_flags &= ~DD_KSTAT_CHANGING;
1414                 mutex_exit(&ddp->dd_mutex);
1415         }
1416 
1417         if (mph != NULL)
1418                 mac_perim_exit(mph);
1419         softmac_rele_device(ddh);
1420         return (err);
1421 }
1422 
1423 static int
1424 i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop)

1425 {
1426         int                     err;
1427         mac_perim_handle_t      mph;
1428         boolean_t               upcall_done = B_FALSE;
1429         datalink_id_t           linkid = ddp->dd_linkid;
1430         zoneid_t                old_zoneid = ddp->dd_zid;
1431         dlmgmt_door_setzoneid_t setzid;
1432         dlmgmt_setzoneid_retval_t retval;
1433 
1434         if (old_zoneid == new_zoneid)
1435                 return (0);
1436 
1437         if ((err = mac_perim_enter_by_macname(ddp->dd_mac, &mph)) != 0)
1438                 return (err);
1439 
1440         /*
1441          * When changing the zoneid of an existing link, we need to tell
1442          * dlmgmtd about it.  dlmgmtd already knows the zoneid associated with
1443          * newly created links.
1444          */
1445         if (setprop) {
1446                 setzid.ld_cmd = DLMGMT_CMD_SETZONEID;
1447                 setzid.ld_linkid = linkid;
1448                 setzid.ld_zoneid = new_zoneid;
1449                 err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1450                     sizeof (retval));
1451                 if (err != 0)
1452                         goto done;
1453                 upcall_done = B_TRUE;
1454         }
1455         if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
1456                 ddp->dd_zid = new_zoneid;

1457                 devnet_need_rebuild = B_TRUE;
1458         }
1459 
1460 done:
1461         if (err != 0 && upcall_done) {
1462                 setzid.ld_zoneid = old_zoneid;
1463                 (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1464                     sizeof (retval));
1465         }
1466         mac_perim_exit(mph);
1467         return (err);
1468 }
1469 
1470 int
1471 dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid)
1472 {
1473         dls_devnet_t    *ddp;
1474         int             err;
1475         zoneid_t        old_zid;
1476         boolean_t       refheld = B_FALSE;
1477 
1478         old_zid = ddh->dd_zid;
1479 
1480         if (old_zid == new_zid)
1481                 return (0);
1482 
1483         /*
1484          * Acquire an additional reference to the link if it is being assigned
1485          * to a non-global zone from the global zone.
1486          */
1487         if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
1488                 if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
1489                         return (err);
1490                 refheld = B_TRUE;
1491         }
1492 
1493         if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE)) != 0) {
1494                 if (refheld)
1495                         dls_devnet_rele(ddp);
1496                 return (err);
1497         }
1498 
1499         /*
1500          * Release the additional reference if the link is returning to the
1501          * global zone from a non-global zone.
1502          */
1503         if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
1504                 dls_devnet_rele(ddh);
1505 
1506         /* Re-create kstats in the appropriate zones. */
1507         if (old_zid != GLOBAL_ZONEID)
1508                 dls_devnet_stat_destroy(ddh, old_zid);
1509         if (new_zid != GLOBAL_ZONEID)
1510                 dls_devnet_stat_create(ddh, new_zid);
1511 
1512         return (0);
1513 }
1514 
1515 zoneid_t
1516 dls_devnet_getzid(dls_dl_handle_t ddh)
1517 {
1518         return (((dls_devnet_t *)ddh)->dd_zid);
1519 }
1520 
1521 zoneid_t
1522 dls_devnet_getownerzid(dls_dl_handle_t ddh)
1523 {
1524         return (((dls_devnet_t *)ddh)->dd_owner_zid);
1525 }
1526 
1527 /*
1528  * Is linkid visible from zoneid?  A link is visible if it was created in the
1529  * zone, or if it is currently assigned to the zone.
1530  */




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright (c) 2013 Joyent, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Datalink management routines.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/door.h>
  33 #include <sys/zone.h>
  34 #include <sys/modctl.h>
  35 #include <sys/file.h>
  36 #include <sys/modhash.h>
  37 #include <sys/kstat.h>
  38 #include <sys/vnode.h>
  39 #include <sys/cmn_err.h>
  40 #include <sys/softmac.h>
  41 #include <sys/dls.h>
  42 #include <sys/dls_impl.h>
  43 #include <sys/stropts.h>
  44 #include <sys/netstack.h>


  89  * This structure itself is not protected by the mac perimeter, but is
  90  * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the
  91  * functions manipulating this structure such as dls_devnet_set/unset etc.
  92  * may be called while not holding the mac perimeter.
  93  */
  94 typedef struct dls_devnet_s {
  95         datalink_id_t   dd_linkid;
  96         char            dd_linkname[MAXLINKNAMELEN];
  97         char            dd_mac[MAXNAMELEN];
  98         kstat_t         *dd_ksp;        /* kstat in owner_zid */
  99         kstat_t         *dd_zone_ksp;   /* in dd_zid if != owner_zid */
 100         uint32_t        dd_ref;
 101         kmutex_t        dd_mutex;
 102         kcondvar_t      dd_cv;
 103         uint32_t        dd_tref;
 104         uint_t          dd_flags;
 105         zoneid_t        dd_owner_zid;   /* zone where node was created */
 106         zoneid_t        dd_zid;         /* current zone */
 107         boolean_t       dd_prop_loaded;
 108         taskqid_t       dd_prop_taskid;
 109         boolean_t       dd_transient;   /* link goes away when zone does */
 110 } dls_devnet_t;
 111 
 112 static int i_dls_devnet_create_iptun(const char *, const char *,
 113     datalink_id_t *);
 114 static int i_dls_devnet_destroy_iptun(datalink_id_t);
 115 static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t, boolean_t);
 116 static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
 117 
 118 /*ARGSUSED*/
 119 static int
 120 i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
 121 {
 122         dls_devnet_t    *ddp = buf;
 123 
 124         bzero(buf, sizeof (dls_devnet_t));
 125         mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
 126         cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
 127         return (0);
 128 }
 129 
 130 /*ARGSUSED*/
 131 static void
 132 i_dls_devnet_destructor(void *buf, void *arg)
 133 {
 134         dls_devnet_t    *ddp = buf;
 135 
 136         ASSERT(ddp->dd_ksp == NULL);
 137         ASSERT(ddp->dd_ref == 0);
 138         ASSERT(ddp->dd_tref == 0);
 139         mutex_destroy(&ddp->dd_mutex);
 140         cv_destroy(&ddp->dd_cv);
 141 }
 142 
 143 /* ARGSUSED */
 144 static int
 145 dls_zone_remove(datalink_id_t linkid, void *arg)
 146 {
 147         dls_devnet_t *ddp;
 148 
 149         if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
 150                 /*
 151                  * Don't bother moving transient links back to the global zone
 152                  * since we will simply delete them in dls_devnet_unset.
 153                  */
 154                 if (!ddp->dd_transient)
 155                         (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
 156                 dls_devnet_rele_tmp(ddp);
 157         }
 158         return (0);
 159 }
 160 
 161 /* ARGSUSED */
 162 static void *
 163 dls_stack_init(netstackid_t stackid, netstack_t *ns)
 164 {
 165         dls_stack_t *dlss;
 166 
 167         dlss = kmem_zalloc(sizeof (*dlss), KM_SLEEP);
 168         dlss->dlss_zoneid = netstackid_to_zoneid(stackid);
 169         return (dlss);
 170 }
 171 
 172 /* ARGSUSED */
 173 static void
 174 dls_stack_shutdown(netstackid_t stackid, void *arg)
 175 {


 516                 *mediap = retval.lr_media;
 517         if (flagsp != NULL)
 518                 *flagsp = retval.lr_flags;
 519         return (0);
 520 }
 521 
 522 /*
 523  * Request the datalink management daemon to get the linkid for a link.
 524  * Returns a non-zero error code on failure.  The linkid argument is only
 525  * set on success (when zero is returned.)
 526  */
 527 int
 528 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
 529 {
 530         dlmgmt_door_getlinkid_t         getlinkid;
 531         dlmgmt_getlinkid_retval_t       retval;
 532         int                             err;
 533 
 534         getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
 535         (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
 536         getlinkid.ld_zoneid = getzoneid();
 537 
 538         if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
 539             sizeof (retval))) == 0) {
 540                 *linkid = retval.lr_linkid;
 541         }
 542         return (err);
 543 }
 544 
 545 datalink_id_t
 546 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
 547     datalink_media_t dmedia, uint32_t flags)
 548 {
 549         dlmgmt_door_getnext_t   getnext;
 550         dlmgmt_getnext_retval_t retval;
 551 
 552         getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
 553         getnext.ld_class = class;
 554         getnext.ld_dmedia = dmedia;
 555         getnext.ld_flags = flags;
 556         getnext.ld_linkid = linkid;


 731          * If a device detach happens at this time, it will block in
 732          * dls_devnet_unset since the dd_tref has been bumped up above. So the
 733          * access to 'dlp' is safe even though we don't hold the mac perimeter.
 734          */
 735         if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac,
 736             (mod_hash_val_t *)&dlp) != 0) {
 737                 dls_devnet_rele_tmp(ddp);
 738                 return (ENOENT);
 739         }
 740 
 741         err = dls_stat_update(ksp, dlp, rw);
 742 
 743         dls_devnet_rele_tmp(ddp);
 744         return (err);
 745 }
 746 
 747 /*
 748  * Create the "link" kstats.
 749  */
 750 static void
 751 dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid, zoneid_t newzoneid)
 752 {
 753         kstat_t *ksp;
 754         char    *nm;
 755         char    kname[MAXLINKNAMELEN];
 756 
 757         if (zoneid != newzoneid) {
 758                 ASSERT(zoneid == GLOBAL_ZONEID);
 759                 (void) snprintf(kname, sizeof (kname), "z%d_%s", newzoneid,
 760                     ddp->dd_linkname);
 761                 nm = kname;
 762         } else {
 763                 nm = ddp->dd_linkname;
 764         }
 765 
 766         if (dls_stat_create("link", 0, nm, zoneid,
 767             dls_devnet_stat_update, ddp, &ksp, newzoneid) == 0) {
 768                 ASSERT(ksp != NULL);
 769                 if (zoneid == ddp->dd_owner_zid) {
 770                         ASSERT(ddp->dd_ksp == NULL);
 771                         ddp->dd_ksp = ksp;
 772                 } else {
 773                         ASSERT(ddp->dd_zone_ksp == NULL);
 774                         ddp->dd_zone_ksp = ksp;
 775                 }
 776         }
 777 }
 778 
 779 /*
 780  * Destroy the "link" kstats.
 781  */
 782 static void
 783 dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
 784 {
 785         if (zoneid == ddp->dd_owner_zid) {
 786                 if (ddp->dd_ksp != NULL) {
 787                         dls_stat_delete(ddp->dd_ksp);
 788                         ddp->dd_ksp = NULL;
 789                 }
 790         } else {
 791                 if (ddp->dd_zone_ksp != NULL) {
 792                         dls_stat_delete(ddp->dd_zone_ksp);
 793                         ddp->dd_zone_ksp = NULL;
 794                 }
 795         }
 796 }
 797 
 798 /*
 799  * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
 800  * and create the new set using the new name.
 801  */
 802 static void
 803 dls_devnet_stat_rename(dls_devnet_t *ddp, boolean_t zoneinit)
 804 {
 805         if (ddp->dd_ksp != NULL) {
 806                 dls_stat_delete(ddp->dd_ksp);
 807                 ddp->dd_ksp = NULL;
 808         }
 809         if (zoneinit && ddp->dd_zone_ksp != NULL) {
 810                 dls_stat_delete(ddp->dd_zone_ksp);
 811                 ddp->dd_zone_ksp = NULL;
 812         }
 813         /*
 814          * We can't rename a link while it's assigned to a non-global zone
 815          * unless we're first initializing the zone while readying it.
 816          */
 817         ASSERT(ddp->dd_zone_ksp == NULL);
 818         dls_devnet_stat_create(ddp, ddp->dd_owner_zid,
 819             (zoneinit ? ddp->dd_zid : ddp->dd_owner_zid));
 820         if (zoneinit)
 821                 dls_devnet_stat_create(ddp, ddp->dd_zid, ddp->dd_zid);
 822 }
 823 
 824 /*
 825  * Associate a linkid with a given link (identified by macname)
 826  */
 827 static int
 828 dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
 829     dls_devnet_t **ddpp)
 830 {
 831         dls_devnet_t            *ddp = NULL;
 832         datalink_class_t        class;
 833         int                     err;
 834         boolean_t               stat_create = B_FALSE;
 835         char                    linkname[MAXLINKNAMELEN];
 836 
 837         rw_enter(&i_dls_devnet_lock, RW_WRITER);
 838 
 839         /*
 840          * Don't allow callers to set a link name with a linkid that already
 841          * has a name association (that's what rename is for).


 890                 stat_create = B_TRUE;
 891                 mutex_enter(&ddp->dd_mutex);
 892                 if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) {
 893                         ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
 894                             dls_devnet_prop_task, ddp, TQ_SLEEP);
 895                 }
 896                 mutex_exit(&ddp->dd_mutex);
 897         }
 898         err = 0;
 899 done:
 900         /*
 901          * It is safe to drop the i_dls_devnet_lock at this point. In the case
 902          * of physical devices, the softmac framework will fail the device
 903          * detach based on the smac_state or smac_hold_cnt. Other cases like
 904          * vnic and aggr use their own scheme to serialize creates and deletes
 905          * and ensure that *ddp is valid.
 906          */
 907         rw_exit(&i_dls_devnet_lock);
 908         if (err == 0) {
 909                 if (zoneid != GLOBAL_ZONEID &&
 910                     (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE,
 911                     B_FALSE)) != 0)
 912                         (void) dls_devnet_unset(macname, &linkid, B_TRUE);
 913                 /*
 914                  * The kstat subsystem holds its own locks (rather perimeter)
 915                  * before calling the ks_update (dls_devnet_stat_update) entry
 916                  * point which in turn grabs the i_dls_devnet_lock. So the
 917                  * lock hierarchy is kstat locks -> i_dls_devnet_lock.
 918                  */
 919                 if (stat_create)
 920                         dls_devnet_stat_create(ddp, zoneid, zoneid);
 921                 if (ddpp != NULL)
 922                         *ddpp = ddp;
 923         }
 924         return (err);
 925 }
 926 
 927 /*
 928  * Disassociate a linkid with a given link (identified by macname)
 929  * This waits until temporary references to the dls_devnet_t are gone.
 930  */
 931 static int
 932 dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait)
 933 {
 934         dls_devnet_t    *ddp;
 935         int             err;
 936         mod_hash_val_t  val;
 937 
 938         rw_enter(&i_dls_devnet_lock, RW_WRITER);
 939         if ((err = mod_hash_find(i_dls_devnet_hash,
 940             (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) {
 941                 ASSERT(err == MH_ERR_NOTFOUND);
 942                 rw_exit(&i_dls_devnet_lock);
 943                 return (ENOENT);
 944         }
 945 
 946         mutex_enter(&ddp->dd_mutex);
 947 
 948         /*
 949          * Make sure downcalls into softmac_create or softmac_destroy from
 950          * devfs don't cv_wait on any devfs related condition for fear of
 951          * deadlock. Return EBUSY if the asynchronous thread started for
 952          * property loading as part of the post attach hasn't yet completed.
 953          */
 954         ASSERT(ddp->dd_ref != 0);
 955         if ((ddp->dd_ref != 1) || (!wait &&
 956             (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {
 957                 int zstatus = 0;
 958 
 959                 /*
 960                  * There are a couple of alternatives that might be going on
 961                  * here; a) the zone is shutting down and it has a transient
 962                  * link assigned, in which case we want to clean it up instead
 963                  * of moving it back to the global zone, or b) its possible
 964                  * that we're trying to clean up an orphaned vnic that was
 965                  * delegated to a zone and which wasn't cleaned up properly
 966                  * when the zone went away.  Check for either of these cases
 967                  * before we simply return EBUSY.
 968                  *
 969                  * zstatus indicates which situation we are dealing with:
 970                  *       0 - means return EBUSY
 971                  *       1 - means case (a), cleanup transient link
 972                  *      -1 - means case (b), orphained VNIC
 973                  */
 974                 if (ddp->dd_ref > 1 && ddp->dd_zid != GLOBAL_ZONEID) {
 975                         zone_t  *zp;
 976 
 977                         if ((zp = zone_find_by_id(ddp->dd_zid)) == NULL) {
 978                                 zstatus = -1;
 979                         } else {
 980                                 if (ddp->dd_transient) {
 981                                         zone_status_t s = zone_status_get(zp);
 982 
 983                                         if (s >= ZONE_IS_SHUTTING_DOWN)
 984                                                 zstatus = 1;
 985                                 }
 986                                 zone_rele(zp);
 987                         }
 988                 }
 989 
 990                 if (zstatus == 0) {
 991                         mutex_exit(&ddp->dd_mutex);
 992                         rw_exit(&i_dls_devnet_lock);
 993                         return (EBUSY);
 994                 }
 995 
 996                 /*
 997                  * We want to delete the link, reset ref to 1;
 998                  */
 999                 if (zstatus == -1)
1000                         /* Log a warning, but continue in this case */
1001                         cmn_err(CE_WARN, "clear orphaned datalink: %s\n",
1002                             ddp->dd_linkname);
1003                 ddp->dd_ref = 1;
1004         }
1005 
1006         ddp->dd_flags |= DD_CONDEMNED;
1007         ddp->dd_ref--;
1008         *id = ddp->dd_linkid;
1009 
1010         if (ddp->dd_zid != GLOBAL_ZONEID) {
1011                 /*
1012                  * We need to release the dd_mutex before we try and destroy the
1013                  * stat. When we destroy it, we'll need to grab the lock for the
1014                  * kstat but if there's a concurrent reader of the kstat, we'll
1015                  * be blocked on it. This will lead to deadlock because these
1016                  * kstats employ a ks_update function (dls_devnet_stat_update)
1017                  * which needs the dd_mutex that we currently hold.
1018                  *
1019                  * Because we've already flagged the dls_devnet_t as
1020                  * DD_CONDEMNED and we still have a write lock on
1021                  * i_dls_devnet_lock, we should be able to release the dd_mutex.
1022                  */
1023                 mutex_exit(&ddp->dd_mutex);
1024                 dls_devnet_stat_destroy(ddp, ddp->dd_zid);
1025                 mutex_enter(&ddp->dd_mutex);
1026                 (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE,
1027                     B_FALSE);
1028         }
1029 
1030         /*
1031          * Remove this dls_devnet_t from the hash table.
1032          */
1033         VERIFY(mod_hash_remove(i_dls_devnet_hash,
1034             (mod_hash_key_t)ddp->dd_mac, &val) == 0);
1035 
1036         if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
1037                 VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
1038                     (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
1039 
1040                 devnet_need_rebuild = B_TRUE;
1041         }
1042         rw_exit(&i_dls_devnet_lock);
1043 
1044         if (wait) {
1045                 /*
1046                  * Wait until all temporary references are released.
1047                  */
1048                 while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
1049                         cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
1050         } else {
1051                 ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
1052         }
1053 
1054         if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
1055                 /*
1056                  * See the earlier call in this function for an explanation.
1057                  */
1058                 mutex_exit(&ddp->dd_mutex);
1059                 dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);
1060                 mutex_enter(&ddp->dd_mutex);
1061         }
1062 
1063 
1064         ddp->dd_prop_loaded = B_FALSE;
1065         ddp->dd_linkid = DATALINK_INVALID_LINKID;
1066         ddp->dd_flags = 0;
1067         mutex_exit(&ddp->dd_mutex);
1068         kmem_cache_free(i_dls_devnet_cachep, ddp);
1069 
1070         return (0);
1071 }
1072 
1073 static int
1074 dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp,
1075     boolean_t tmp_hold)
1076 {
1077         dls_devnet_t            *ddp;
1078         dev_t                   phydev = 0;
1079         dls_dev_handle_t        ddh = NULL;
1080         int                     err;
1081 
1082         /*
1083          * Hold this link to prevent it being detached in case of a


1342         err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1343         dls_devnet_rele_tmp(ddp);
1344         return (err);
1345 }
1346 
1347 /*
1348  * Handle the renaming requests.  There are two rename cases:
1349  *
1350  * 1. Request to rename a valid link (id1) to an non-existent link name
1351  *    (id2). In this case id2 is DATALINK_INVALID_LINKID.  Just check whether
1352  *    id1 is held by any applications.
1353  *
1354  *    In this case, the link's kstats need to be updated using the given name.
1355  *
1356  * 2. Request to rename a valid link (id1) to the name of a REMOVED
1357  *    physical link (id2). In this case, check that id1 and its associated
1358  *    mac is not held by any application, and update the link's linkid to id2.
1359  *
1360  *    This case does not change the <link name, linkid> mapping, so the link's
1361  *    kstats need to be updated with using name associated the given id2.
1362  *
1363  * The zonename parameter is used to allow us to create a VNIC in the global
1364  * zone which is assigned to a non-global zone.  Since there is a race condition
1365  * in the create process if two VNICs have the same name, we need to rename it
1366  * after it has been assigned to the zone.
1367  */
1368 int
1369 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link,
1370     boolean_t zoneinit)
1371 {
1372         dls_dev_handle_t        ddh = NULL;
1373         int                     err = 0;
1374         dev_t                   phydev = 0;
1375         dls_devnet_t            *ddp;
1376         mac_perim_handle_t      mph = NULL;
1377         mac_handle_t            mh;
1378         mod_hash_val_t          val;
1379         boolean_t               clear_dd_flag = B_FALSE;
1380 
1381         /*
1382          * In the second case, id2 must be a REMOVED physical link.
1383          */
1384         if ((id2 != DATALINK_INVALID_LINKID) &&
1385             (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1386             softmac_hold_device(phydev, &ddh) == 0) {
1387                 softmac_rele_device(ddh);
1388                 return (EEXIST);
1389         }
1390 


1400          * for the property loading to finish.
1401          */
1402         if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) {
1403                 softmac_rele_device(ddh);
1404                 return (err);
1405         }
1406 
1407         rw_enter(&i_dls_devnet_lock, RW_WRITER);
1408         if ((err = mod_hash_find(i_dls_devnet_id_hash,
1409             (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
1410                 ASSERT(err == MH_ERR_NOTFOUND);
1411                 err = ENOENT;
1412                 goto done;
1413         }
1414 
1415         /*
1416          * Return EBUSY if any applications have this link open, if any thread
1417          * is currently accessing the link kstats, or if the link is on-loan
1418          * to a non-global zone. Then set the DD_KSTAT_CHANGING flag to
1419          * prevent any access to the kstats while we delete and recreate
1420          * kstats below.  However, we skip this check if we're renaming the
1421          * vnic as part of bringing it up for a zone.
1422          */
1423         mutex_enter(&ddp->dd_mutex);
1424         if (!zoneinit) {
1425                 if (ddp->dd_ref > 1) {
1426                         mutex_exit(&ddp->dd_mutex);
1427                         err = EBUSY;
1428                         goto done;
1429                 }
1430         }
1431 
1432         ddp->dd_flags |= DD_KSTAT_CHANGING;
1433         clear_dd_flag = B_TRUE;
1434         mutex_exit(&ddp->dd_mutex);
1435 
1436         if (id2 == DATALINK_INVALID_LINKID) {
1437                 (void) strlcpy(ddp->dd_linkname, link,
1438                     sizeof (ddp->dd_linkname));
1439 
1440                 /* rename mac client name and its flow if exists */
1441                 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1442                         goto done;
1443                 if (zoneinit) {
1444                         char tname[MAXLINKNAMELEN];
1445 
1446                         (void) snprintf(tname, sizeof (tname), "z%d_%s",
1447                             ddp->dd_zid, link);
1448                         (void) mac_rename_primary(mh, tname);
1449                 } else {
1450                         (void) mac_rename_primary(mh, link);
1451                 }
1452                 mac_close(mh);
1453                 goto done;
1454         }
1455 
1456         /*
1457          * The second case, check whether the MAC is used by any MAC
1458          * user.  This must be a physical link so ddh must not be NULL.
1459          */
1460         if (ddh == NULL) {
1461                 err = EINVAL;
1462                 goto done;
1463         }
1464 
1465         if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1466                 goto done;
1467 
1468         /*
1469          * We release the reference of the MAC which mac_open() is
1470          * holding. Note that this mac will not be unregistered
1471          * because the physical device is held.


1504 
1505         mac_unmark_exclusive(mh);
1506 
1507         /* load properties for new id */
1508         mutex_enter(&ddp->dd_mutex);
1509         ddp->dd_prop_loaded = B_FALSE;
1510         ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
1511             dls_devnet_prop_task, ddp, TQ_SLEEP);
1512         mutex_exit(&ddp->dd_mutex);
1513 
1514 done:
1515         /*
1516          * Change the name of the kstat based on the new link name.
1517          * We can't hold the i_dls_devnet_lock across calls to the kstat
1518          * subsystem. Instead the DD_KSTAT_CHANGING flag set above in this
1519          * function prevents any access to the dd_ksp while we delete and
1520          * recreate it below.
1521          */
1522         rw_exit(&i_dls_devnet_lock);
1523         if (err == 0)
1524                 dls_devnet_stat_rename(ddp, zoneinit);
1525 
1526         if (clear_dd_flag) {
1527                 mutex_enter(&ddp->dd_mutex);
1528                 ddp->dd_flags &= ~DD_KSTAT_CHANGING;
1529                 mutex_exit(&ddp->dd_mutex);
1530         }
1531 
1532         if (mph != NULL)
1533                 mac_perim_exit(mph);
1534         softmac_rele_device(ddh);
1535         return (err);
1536 }
1537 
1538 static int
1539 i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop,
1540     boolean_t transient)
1541 {
1542         int                     err;
1543         mac_perim_handle_t      mph;
1544         boolean_t               upcall_done = B_FALSE;
1545         datalink_id_t           linkid = ddp->dd_linkid;
1546         zoneid_t                old_zoneid = ddp->dd_zid;
1547         dlmgmt_door_setzoneid_t setzid;
1548         dlmgmt_setzoneid_retval_t retval;
1549 
1550         if (old_zoneid == new_zoneid)
1551                 return (0);
1552 
1553         if ((err = mac_perim_enter_by_macname(ddp->dd_mac, &mph)) != 0)
1554                 return (err);
1555 
1556         /*
1557          * When changing the zoneid of an existing link, we need to tell
1558          * dlmgmtd about it.  dlmgmtd already knows the zoneid associated with
1559          * newly created links.
1560          */
1561         if (setprop) {
1562                 setzid.ld_cmd = DLMGMT_CMD_SETZONEID;
1563                 setzid.ld_linkid = linkid;
1564                 setzid.ld_zoneid = new_zoneid;
1565                 err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1566                     sizeof (retval));
1567                 if (err != 0)
1568                         goto done;
1569                 upcall_done = B_TRUE;
1570         }
1571         if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
1572                 ddp->dd_zid = new_zoneid;
1573                 ddp->dd_transient = transient;
1574                 devnet_need_rebuild = B_TRUE;
1575         }
1576 
1577 done:
1578         if (err != 0 && upcall_done) {
1579                 setzid.ld_zoneid = old_zoneid;
1580                 (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1581                     sizeof (retval));
1582         }
1583         mac_perim_exit(mph);
1584         return (err);
1585 }
1586 
1587 int
1588 dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid, boolean_t transient)
1589 {
1590         dls_devnet_t    *ddp;
1591         int             err;
1592         zoneid_t        old_zid;
1593         boolean_t       refheld = B_FALSE;
1594 
1595         old_zid = ddh->dd_zid;
1596 
1597         if (old_zid == new_zid)
1598                 return (0);
1599 
1600         /*
1601          * Acquire an additional reference to the link if it is being assigned
1602          * to a non-global zone from the global zone.
1603          */
1604         if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
1605                 if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
1606                         return (err);
1607                 refheld = B_TRUE;
1608         }
1609 
1610         if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE, transient)) != 0) {
1611                 if (refheld)
1612                         dls_devnet_rele(ddp);
1613                 return (err);
1614         }
1615 
1616         /*
1617          * Release the additional reference if the link is returning to the
1618          * global zone from a non-global zone.
1619          */
1620         if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
1621                 dls_devnet_rele(ddh);
1622 
1623         /* Re-create kstats in the appropriate zones. */
1624         if (old_zid != GLOBAL_ZONEID)
1625                 dls_devnet_stat_destroy(ddh, old_zid);
1626         if (new_zid != GLOBAL_ZONEID)
1627                 dls_devnet_stat_create(ddh, new_zid, new_zid);
1628 
1629         return (0);
1630 }
1631 
1632 zoneid_t
1633 dls_devnet_getzid(dls_dl_handle_t ddh)
1634 {
1635         return (((dls_devnet_t *)ddh)->dd_zid);
1636 }
1637 
1638 zoneid_t
1639 dls_devnet_getownerzid(dls_dl_handle_t ddh)
1640 {
1641         return (((dls_devnet_t *)ddh)->dd_owner_zid);
1642 }
1643 
1644 /*
1645  * Is linkid visible from zoneid?  A link is visible if it was created in the
1646  * zone, or if it is currently assigned to the zone.
1647  */