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 */
|