3 *
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <strings.h>
32 #include <sys/stat.h>
33 #include <sys/dld.h>
34 #include <sys/vlan.h>
35 #include <zone.h>
36 #include <librcm.h>
37 #include <libdlpi.h>
38 #include <libdevinfo.h>
39 #include <libdlaggr.h>
40 #include <libdlvlan.h>
41 #include <libdlvnic.h>
42 #include <libdlib.h>
369 const char *s;
370
371 switch (duplex) {
372 case LINK_DUPLEX_FULL:
373 s = "full";
374 break;
375 case LINK_DUPLEX_HALF:
376 s = "half";
377 break;
378 default:
379 s = "unknown";
380 break;
381 }
382 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
383 return (buf);
384 }
385
386 /*
387 * Case 1: rename an existing link1 to a link2 that does not exist.
388 * Result: <linkid1, link2>
389 */
390 static dladm_status_t
391 i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
392 const char *link1, const char *link2, uint32_t flags)
393 {
394 dld_ioc_rename_t dir;
395 dladm_status_t status = DLADM_STATUS_OK;
396
397 /*
398 * Link is currently available. Check to see whether anything is
399 * holding this link to prevent a rename operation.
400 */
401 if (flags & DLADM_OPT_ACTIVE) {
402 dir.dir_linkid1 = linkid1;
403 dir.dir_linkid2 = DATALINK_INVALID_LINKID;
404 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
405
406 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
407 status = dladm_errno2status(errno);
408 return (status);
409 }
410 }
411
412 status = dladm_remap_datalink_id(handle, linkid1, link2);
413 if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
414 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
415 (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
416 }
417 return (status);
418 }
419
420 typedef struct link_hold_arg_s {
421 datalink_id_t linkid;
422 datalink_id_t holder;
423 uint32_t flags;
424 } link_hold_arg_t;
425
426 static int
427 i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
428 {
429 link_hold_arg_t *hold_arg = arg;
430 dladm_aggr_grp_attr_t ginfo;
431 dladm_status_t status;
432 int i;
433
434 status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags);
491 arg.flags = DLADM_OPT_PERSIST;
492 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg,
493 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
494 if (arg.holder != DATALINK_INVALID_LINKID)
495 return (DLADM_STATUS_LINKBUSY);
496
497 arg.flags = DLADM_OPT_PERSIST;
498 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg,
499 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
500 if (arg.holder != DATALINK_INVALID_LINKID)
501 return (DLADM_STATUS_LINKBUSY);
502
503 /*
504 * Send DLDIOC_RENAME to request to rename link1's linkid to
505 * be linkid2. This will check whether link1 is used by any
506 * aggregations or VLANs, or is held by any application. If yes,
507 * return failure.
508 */
509 dir.dir_linkid1 = linkid1;
510 dir.dir_linkid2 = linkid2;
511 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
512 status = dladm_errno2status(errno);
513
514 if (status != DLADM_STATUS_OK) {
515 return (status);
516 }
517
518 /*
519 * Now change the phymaj, phyinst and devname associated with linkid1
520 * to be associated with linkid2. Before doing that, the old active
521 * linkprop of linkid1 should be deleted.
522 */
523 (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0,
524 DLADM_OPT_ACTIVE);
525
526 if (((status = dladm_getsnap_conf(handle, linkid1, &conf1)) !=
527 DLADM_STATUS_OK) ||
528 ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname,
529 MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
530 ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj,
600
601 if (!dladm_valid_linkname(link1))
602 return (DLADM_STATUS_LINKINVAL);
603
604 status = dladm_open_conf(handle, linkid2, &conf);
605 if (status != DLADM_STATUS_OK)
606 goto done;
607
608 if ((status = dladm_set_conf_field(handle, conf, FDEVNAME,
609 DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) {
610 status = dladm_write_conf(handle, conf);
611 }
612
613 dladm_destroy_conf(handle, conf);
614
615 done:
616 return (status);
617 }
618
619 dladm_status_t
620 dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
621 {
622 datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
623 datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
624 uint32_t flags1, flags2;
625 datalink_class_t class1, class2;
626 uint32_t media1, media2;
627 boolean_t remphy2 = B_FALSE;
628 dladm_status_t status;
629
630 (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1,
631 &media1);
632 if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2,
633 &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
634 (flags2 == DLADM_OPT_PERSIST)) {
635 /*
636 * see whether link2 is a removed physical link.
637 */
638 remphy2 = B_TRUE;
639 }
640
641 if (linkid1 != DATALINK_INVALID_LINKID) {
642 if (linkid2 == DATALINK_INVALID_LINKID) {
643 /*
644 * case 1: rename an existing link to a link that
645 * does not exist.
646 */
647 status = i_dladm_rename_link_c1(handle, linkid1, link1,
648 link2, flags1);
649 } else if (remphy2) {
650 /*
651 * case 2: rename an available link to a REMOVED
652 * physical link. Return failure if link1 is not
653 * an active physical link.
654 */
655 if ((class1 != class2) || (media1 != media2) ||
656 !(flags1 & DLADM_OPT_ACTIVE)) {
657 status = DLADM_STATUS_BADARG;
658 } else {
659 status = i_dladm_rename_link_c2(handle, linkid1,
660 linkid2);
661 }
662 } else {
663 status = DLADM_STATUS_EXIST;
664 }
665 } else if (remphy2) {
666 status = i_dladm_rename_link_c3(handle, link1, linkid2);
667 } else {
668 status = DLADM_STATUS_NOTFOUND;
|
3 *
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011, Joyent Inc. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <strings.h>
33 #include <sys/stat.h>
34 #include <sys/dld.h>
35 #include <sys/vlan.h>
36 #include <zone.h>
37 #include <librcm.h>
38 #include <libdlpi.h>
39 #include <libdevinfo.h>
40 #include <libdlaggr.h>
41 #include <libdlvlan.h>
42 #include <libdlvnic.h>
43 #include <libdlib.h>
370 const char *s;
371
372 switch (duplex) {
373 case LINK_DUPLEX_FULL:
374 s = "full";
375 break;
376 case LINK_DUPLEX_HALF:
377 s = "half";
378 break;
379 default:
380 s = "unknown";
381 break;
382 }
383 (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
384 return (buf);
385 }
386
387 /*
388 * Case 1: rename an existing link1 to a link2 that does not exist.
389 * Result: <linkid1, link2>
390 * The zonename parameter is used to allow us to create a VNIC in the global
391 * zone which is assigned to a non-global zone. Since there is a race condition
392 * in the create process if two VNICs have the same name, we need to rename it
393 * after it has been assigned to the zone.
394 */
395 static dladm_status_t
396 i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
397 const char *link1, const char *link2, uint32_t flags, const char *zonename)
398 {
399 dld_ioc_rename_t dir;
400 dladm_status_t status = DLADM_STATUS_OK;
401
402 /*
403 * Link is currently available. Check to see whether anything is
404 * holding this link to prevent a rename operation.
405 */
406 if (flags & DLADM_OPT_ACTIVE) {
407 dir.dir_linkid1 = linkid1;
408 dir.dir_linkid2 = DATALINK_INVALID_LINKID;
409 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
410 if (zonename != NULL)
411 dir.dir_zoneinit = B_TRUE;
412 else
413 dir.dir_zoneinit = B_FALSE;
414
415 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
416 status = dladm_errno2status(errno);
417 return (status);
418 }
419 }
420
421 status = dladm_remap_datalink_id(handle, linkid1, link2);
422 if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
423 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
424 dir.dir_zoneinit = B_FALSE;
425 (void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
426 }
427 return (status);
428 }
429
430 typedef struct link_hold_arg_s {
431 datalink_id_t linkid;
432 datalink_id_t holder;
433 uint32_t flags;
434 } link_hold_arg_t;
435
436 static int
437 i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
438 {
439 link_hold_arg_t *hold_arg = arg;
440 dladm_aggr_grp_attr_t ginfo;
441 dladm_status_t status;
442 int i;
443
444 status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags);
501 arg.flags = DLADM_OPT_PERSIST;
502 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg,
503 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
504 if (arg.holder != DATALINK_INVALID_LINKID)
505 return (DLADM_STATUS_LINKBUSY);
506
507 arg.flags = DLADM_OPT_PERSIST;
508 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg,
509 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
510 if (arg.holder != DATALINK_INVALID_LINKID)
511 return (DLADM_STATUS_LINKBUSY);
512
513 /*
514 * Send DLDIOC_RENAME to request to rename link1's linkid to
515 * be linkid2. This will check whether link1 is used by any
516 * aggregations or VLANs, or is held by any application. If yes,
517 * return failure.
518 */
519 dir.dir_linkid1 = linkid1;
520 dir.dir_linkid2 = linkid2;
521 dir.dir_zoneinit = B_FALSE;
522 if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
523 status = dladm_errno2status(errno);
524
525 if (status != DLADM_STATUS_OK) {
526 return (status);
527 }
528
529 /*
530 * Now change the phymaj, phyinst and devname associated with linkid1
531 * to be associated with linkid2. Before doing that, the old active
532 * linkprop of linkid1 should be deleted.
533 */
534 (void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0,
535 DLADM_OPT_ACTIVE);
536
537 if (((status = dladm_getsnap_conf(handle, linkid1, &conf1)) !=
538 DLADM_STATUS_OK) ||
539 ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname,
540 MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
541 ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj,
611
612 if (!dladm_valid_linkname(link1))
613 return (DLADM_STATUS_LINKINVAL);
614
615 status = dladm_open_conf(handle, linkid2, &conf);
616 if (status != DLADM_STATUS_OK)
617 goto done;
618
619 if ((status = dladm_set_conf_field(handle, conf, FDEVNAME,
620 DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) {
621 status = dladm_write_conf(handle, conf);
622 }
623
624 dladm_destroy_conf(handle, conf);
625
626 done:
627 return (status);
628 }
629
630 dladm_status_t
631 dladm_rename_link(dladm_handle_t handle, const char *zonename,
632 const char *link1, const char *link2)
633 {
634 datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
635 datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
636 uint32_t flags1, flags2;
637 datalink_class_t class1, class2;
638 uint32_t media1, media2;
639 boolean_t remphy2 = B_FALSE;
640 dladm_status_t status;
641
642 (void) dladm_zname2info(handle, zonename, link1, &linkid1, &flags1,
643 &class1, &media1);
644 if ((dladm_zname2info(handle, zonename, link2, &linkid2, &flags2,
645 &class2, &media2) == DLADM_STATUS_OK) &&
646 (class2 == DATALINK_CLASS_PHYS) && (flags2 == DLADM_OPT_PERSIST)) {
647 /*
648 * see whether link2 is a removed physical link.
649 */
650 remphy2 = B_TRUE;
651 }
652
653 if (linkid1 != DATALINK_INVALID_LINKID) {
654 if (linkid2 == DATALINK_INVALID_LINKID) {
655 /*
656 * case 1: rename an existing link to a link that
657 * does not exist.
658 */
659 status = i_dladm_rename_link_c1(handle, linkid1, link1,
660 link2, flags1, zonename);
661 } else if (remphy2) {
662 /*
663 * case 2: rename an available link to a REMOVED
664 * physical link. Return failure if link1 is not
665 * an active physical link.
666 */
667 if ((class1 != class2) || (media1 != media2) ||
668 !(flags1 & DLADM_OPT_ACTIVE)) {
669 status = DLADM_STATUS_BADARG;
670 } else {
671 status = i_dladm_rename_link_c2(handle, linkid1,
672 linkid2);
673 }
674 } else {
675 status = DLADM_STATUS_EXIST;
676 }
677 } else if (remphy2) {
678 status = i_dladm_rename_link_c3(handle, link1, linkid2);
679 } else {
680 status = DLADM_STATUS_NOTFOUND;
|