Print this page
OS-249


   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;