Print this page
Commit IPMP changes


   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) 2010, Oracle and/or its affiliates. All rights reserved.

  23  */
  24 
  25 #include <stdio.h>
  26 #include <stdlib.h>
  27 #include <string.h>
  28 #include <errno.h>
  29 #include <fcntl.h>
  30 #include <unistd.h>
  31 #include <stropts.h>
  32 #include <sys/sockio.h>
  33 #include <sys/types.h>
  34 #include <sys/stat.h>
  35 #include <sys/socket.h>
  36 #include <net/route.h>
  37 #include <netinet/in.h>
  38 #include <inet/ip.h>
  39 #include <arpa/inet.h>
  40 #include <libintl.h>
  41 #include <libdlpi.h>
  42 #include <libinetutil.h>


 508 
 509         if (iph->iph_dlh == NULL) {
 510                 assert(iph->iph_zoneid != GLOBAL_ZONEID);
 511                 return (B_FALSE);
 512         }
 513         dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
 514             &class, NULL);
 515         if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
 516                 params.iptun_param_linkid = linkid;
 517                 dlstatus = dladm_iptun_getparams(iph->iph_dlh, &params,
 518                     DLADM_OPT_ACTIVE);
 519                 if (dlstatus == DLADM_STATUS_OK &&
 520                     params.iptun_param_type == IPTUN_TYPE_6TO4) {
 521                         return (B_TRUE);
 522                 }
 523         }
 524         return (B_FALSE);
 525 }
 526 
 527 /*
 528  * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
 529  */
 530 boolean_t
 531 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
 532 {
 533         struct lifreq   lifr;
 534 
 535         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 536         if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
 537                 if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
 538                     (caddr_t)&lifr) < 0) {
 539                         return (B_FALSE);
 540                 }
 541         }
 542         return (lifr.lifr_groupname[0] != '\0');
 543 }
 544 
 545 /*
 546  * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
 547  */
 548 boolean_t
 549 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
 550 {
 551         uint64_t flags;
 552 
 553         if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
 554             i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
 555                 return (B_FALSE);
 556 
 557         return ((flags & IFF_IPMP) != 0);
 558 }
 559 
 560 /*
 561  * For a given interface name, ipadm_if_enabled() checks if v4
 562  * or v6 or both IP interfaces exist in the active configuration.
 563  */
 564 boolean_t
 565 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
 566 {
 567         struct lifreq   lifr;
 568         int             s4 = iph->iph_sock;
 569         int             s6 = iph->iph_sock6;
 570 
 571         bzero(&lifr, sizeof (lifr));
 572         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 573         switch (af) {
 574         case AF_INET:
 575                 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 576                         return (B_TRUE);
 577                 break;
 578         case AF_INET6:
 579                 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 580                         return (B_TRUE);


 673         case IPADM_ADDR_NONE:
 674                 status = ipadm_set_addrprop(iph, name, pval, aobjname,
 675                     IPADM_OPT_ACTIVE);
 676                 break;
 677         }
 678 
 679         return (status);
 680 }
 681 
 682 /*
 683  * Instantiate the interface object by retrieving the configuration from
 684  * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
 685  * (interface properties and address objects on that interface) for the
 686  * given `ifname'.
 687  */
 688 ipadm_status_t
 689 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
 690 {
 691         nvlist_t        *nvl = NULL;
 692         nvpair_t        *nvp;
 693         char            *afstr;
 694         ipadm_status_t  status;
 695         ipadm_status_t  ret_status = IPADM_SUCCESS;
 696         char            newifname[LIFNAMSIZ];
 697         char            *aobjstr;
 698         sa_family_t     af = AF_UNSPEC;




 699         boolean_t       is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);

 700 
 701         (void) strlcpy(newifname, ifname, sizeof (newifname));
 702         /*
 703          * First plumb the given interface and then apply all the persistent
 704          * interface properties and then instantiate any persistent addresses
 705          * objects on that interface.
 706          */
 707         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 708             nvp = nvlist_next_nvpair(ifnvl, nvp)) {

 709                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
 710                         continue;
 711 
 712                 if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
 713                         status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
 714                             IPADM_OPT_ACTIVE);
 715                         /*
 716                          * If the interface is already plumbed, we should
 717                          * ignore this error because there might be address
 718                          * address objects on that interface that needs to
 719                          * be enabled again.
 720                          */








 721                         if (status == IPADM_IF_EXISTS)
 722                                 status = IPADM_SUCCESS;
 723 















 724                         if (is_ngz)
 725                                 af = atoi(afstr);
 726                 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 727                     &aobjstr) == 0) {
 728                         /*
 729                          * For a static address, we need to search for
 730                          * the prefixlen in the nvlist `ifnvl'.
 731                          */
 732                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
 733                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
 734                                 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
 735                                     nvl, aobjstr);

 736                                 if (status != IPADM_SUCCESS)
 737                                         continue;
 738                         }
 739                         status = i_ipadm_init_addrobj(iph, nvl);
 740                         /*
 741                          * If this address is in use on some other interface,
 742                          * we want to record an error to be returned as
 743                          * a soft error and continue processing the rest of
 744                          * the addresses.
 745                          */
 746                         if (status == IPADM_ADDR_NOTAVAIL) {
 747                                 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
 748                                 status = IPADM_SUCCESS;
 749                         }
 750                 } else {
 751                         assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
 752                         status = i_ipadm_init_ifprop(iph, nvl);
 753                 }
 754                 if (status != IPADM_SUCCESS)
 755                         return (status);
 756         }
 757 
 758         if (is_ngz && af != AF_UNSPEC)
 759                 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);

 760         return (ret_status);
 761 }
 762 
 763 /*
 764  * Retrieves the persistent configuration for the given interface(s) in `ifs'
 765  * by contacting the daemon and dumps the information in `allifs'.
 766  */
 767 ipadm_status_t
 768 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
 769 {
 770         nvlist_t                *nvl = NULL;
 771         size_t                  nvlsize, bufsize;
 772         ipmgmt_initif_arg_t     *iargp;
 773         char                    *buf = NULL, *nvlbuf = NULL;
 774         ipmgmt_get_rval_t       *rvalp = NULL;
 775         int                     err;
 776         ipadm_status_t          status = IPADM_SUCCESS;
 777 
 778         if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
 779                 return (ipadm_errno2status(err));


 936                  * to new buffer.
 937                  */
 938                 if (err == 0) {
 939                         void *newp;
 940 
 941                         /* allocated memory will be freed by the caller */
 942                         if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
 943                                 err = ENOMEM;
 944                         } else {
 945                                 *rbufp = newp;
 946                                 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
 947                         }
 948                 }
 949                 /* munmap() the door buffer */
 950                 (void) munmap(darg.rbuf, darg.rsize);
 951         } else {
 952                 if (darg.rsize != rsize)
 953                         err = EBADE;
 954         }
 955         return (err);



























 956 }


   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) 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <errno.h>
  30 #include <fcntl.h>
  31 #include <unistd.h>
  32 #include <stropts.h>
  33 #include <sys/sockio.h>
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include <sys/socket.h>
  37 #include <net/route.h>
  38 #include <netinet/in.h>
  39 #include <inet/ip.h>
  40 #include <arpa/inet.h>
  41 #include <libintl.h>
  42 #include <libdlpi.h>
  43 #include <libinetutil.h>


 509 
 510         if (iph->iph_dlh == NULL) {
 511                 assert(iph->iph_zoneid != GLOBAL_ZONEID);
 512                 return (B_FALSE);
 513         }
 514         dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
 515             &class, NULL);
 516         if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
 517                 params.iptun_param_linkid = linkid;
 518                 dlstatus = dladm_iptun_getparams(iph->iph_dlh, &params,
 519                     DLADM_OPT_ACTIVE);
 520                 if (dlstatus == DLADM_STATUS_OK &&
 521                     params.iptun_param_type == IPTUN_TYPE_6TO4) {
 522                         return (B_TRUE);
 523                 }
 524         }
 525         return (B_FALSE);
 526 }
 527 
 528 /*

































 529  * For a given interface name, ipadm_if_enabled() checks if v4
 530  * or v6 or both IP interfaces exist in the active configuration.
 531  */
 532 boolean_t
 533 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
 534 {
 535         struct lifreq   lifr;
 536         int             s4 = iph->iph_sock;
 537         int             s6 = iph->iph_sock6;
 538 
 539         bzero(&lifr, sizeof (lifr));
 540         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 541         switch (af) {
 542         case AF_INET:
 543                 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 544                         return (B_TRUE);
 545                 break;
 546         case AF_INET6:
 547                 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 548                         return (B_TRUE);


 641         case IPADM_ADDR_NONE:
 642                 status = ipadm_set_addrprop(iph, name, pval, aobjname,
 643                     IPADM_OPT_ACTIVE);
 644                 break;
 645         }
 646 
 647         return (status);
 648 }
 649 
 650 /*
 651  * Instantiate the interface object by retrieving the configuration from
 652  * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
 653  * (interface properties and address objects on that interface) for the
 654  * given `ifname'.
 655  */
 656 ipadm_status_t
 657 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
 658 {
 659         nvlist_t        *nvl = NULL;
 660         nvpair_t        *nvp;

 661         ipadm_status_t  status;
 662         ipadm_status_t  ret_status = IPADM_SUCCESS;
 663         char            newifname[LIFNAMSIZ];
 664         char            *aobjstr;
 665         char    *ifclass_str, *gif_name;
 666         uint16_t        *families;
 667         uint_t  nelem = 0;
 668         char **members;
 669         uint32_t        ipadm_flags;
 670         boolean_t       is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
 671         boolean_t   init_from_gz = B_FALSE;
 672 
 673         (void) strlcpy(newifname, ifname, sizeof (newifname));
 674         /*
 675          * First plumb the given interface and then apply all the persistent
 676          * interface properties and then instantiate any persistent addresses
 677          * objects on that interface.
 678          */
 679         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 680             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 681 
 682                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
 683                         continue;
 684 
 685 
 686                 if (nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
 687                     &families, &nelem) == 0) {
 688 
 689                         ipadm_flags = IPADM_OPT_ACTIVE;
 690 
 691                         if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS, &ifclass_str) == 0 &&
 692                             atoi(ifclass_str) == IPADM_IF_CLASS_IPMP)
 693                                 ipadm_flags |= IPADM_OPT_IPMP;
 694 
 695                         while (nelem--) {
 696                                 assert(families[nelem] == AF_INET ||
 697                                     families[nelem] == AF_INET6);
 698 
 699                                 status = i_ipadm_plumb_if(iph, newifname, families[nelem],
 700                                     ipadm_flags);
 701 
 702                                 if (status == IPADM_IF_EXISTS)
 703                                         status = IPADM_SUCCESS;
 704 
 705                                 /* plumbing can fail for ipmp, this is expected */
 706                                 if (status != IPADM_SUCCESS && !(ipadm_flags & IPADM_OPT_IPMP))
 707                                         break;
 708                         }
 709                         /* does this interface belong to ipmp ? */
 710                         if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME, &gif_name) == 0) {
 711                                 (void) ipadm_create_if(iph, gif_name, AF_INET, IPADM_OPT_IPMP |
 712                                     IPADM_OPT_ACTIVE);
 713                                 (void) ipadm_create_if(iph, gif_name, AF_INET6, IPADM_OPT_IPMP |
 714                                    IPADM_OPT_ACTIVE);
 715                                 /** add itself to the group */
 716                                 status = ipadm_add_ipmp_member(iph, gif_name, newifname, IPADM_OPT_ACTIVE);
 717                                 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
 718                                         break;
 719                         }
 720                         if (is_ngz)
 721                                 init_from_gz = B_TRUE;
 722                  } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 723                     &aobjstr) == 0) {
 724                         /*
 725                          * For a static address, we need to search for
 726                          * the prefixlen in the nvlist `ifnvl'.
 727                          */
 728                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
 729                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
 730                                 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
 731                                     nvl, aobjstr);
 732 
 733                                 if (status != IPADM_SUCCESS)
 734                                         continue;
 735                         }
 736                         status = i_ipadm_init_addrobj(iph, nvl);
 737                         /*
 738                          * If this address is in use on some other interface,
 739                          * we want to record an error to be returned as
 740                          * a soft error and continue processing the rest of
 741                          * the addresses.
 742                          */
 743                         if (status == IPADM_ADDR_NOTAVAIL) {
 744                                 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
 745                                 status = IPADM_SUCCESS;
 746                         }
 747                 } else {
 748                         assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
 749                         status = i_ipadm_init_ifprop(iph, nvl);
 750                 }
 751                 if (status != IPADM_SUCCESS)
 752                         return (status);
 753         }
 754         if (init_from_gz)

 755                 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
 756 
 757         return (ret_status);
 758 }
 759 
 760 /*
 761  * Retrieves the persistent configuration for the given interface(s) in `ifs'
 762  * by contacting the daemon and dumps the information in `allifs'.
 763  */
 764 ipadm_status_t
 765 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
 766 {
 767         nvlist_t                *nvl = NULL;
 768         size_t                  nvlsize, bufsize;
 769         ipmgmt_initif_arg_t     *iargp;
 770         char                    *buf = NULL, *nvlbuf = NULL;
 771         ipmgmt_get_rval_t       *rvalp = NULL;
 772         int                     err;
 773         ipadm_status_t          status = IPADM_SUCCESS;
 774 
 775         if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
 776                 return (ipadm_errno2status(err));


 933                  * to new buffer.
 934                  */
 935                 if (err == 0) {
 936                         void *newp;
 937 
 938                         /* allocated memory will be freed by the caller */
 939                         if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
 940                                 err = ENOMEM;
 941                         } else {
 942                                 *rbufp = newp;
 943                                 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
 944                         }
 945                 }
 946                 /* munmap() the door buffer */
 947                 (void) munmap(darg.rbuf, darg.rsize);
 948         } else {
 949                 if (darg.rsize != rsize)
 950                         err = EBADE;
 951         }
 952         return (err);
 953 }
 954 
 955 /*
 956  * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
 957  * to do a door_call to ipmgmtd, that should return persistent information
 958  * about interfaces or/and addresses from ipadm DB
 959  */
 960 ipadm_status_t
 961 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg,
 962         size_t garg_size, nvlist_t **onvl)
 963 {
 964         ipmgmt_get_rval_t       *rvalp;
 965         int                     err;
 966         size_t                  nvlsize;
 967         char                    *nvlbuf;
 968 
 969         rvalp = malloc(sizeof (ipmgmt_get_rval_t));
 970         err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
 971             sizeof (*rvalp), B_TRUE);
 972         if (err == 0) {
 973                 nvlsize = rvalp->ir_nvlsize;
 974                 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
 975                 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
 976         }
 977         free(rvalp);
 978 
 979         return (ipadm_errno2status(err));
 980 }