Print this page
NEX-7823 ipmgmtd can't properly remove interface from the old ipadm.conf format
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-6864 cannot create functional link-based IPMP interface
NEX-7793 unable to add/remove interface with existing address to/from IPMP group
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-2991 leaked buffer in libipadm`i_ipadm_init_ifs()
NEX-2395: new libipadm/ipadm/ipmgmtd shall be backward compatible with old ipadm.conf format
OS-161: Integrate IPMP changes


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


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


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



 703 
 704         (void) strlcpy(newifname, ifname, sizeof (newifname));

 705         /*
 706          * First plumb the given interface and then apply all the persistent
 707          * interface properties and then instantiate any persistent addresses
 708          * objects on that interface.
 709          */
 710         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 711             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 712                 if (nvpair_value_nvlist(nvp, &nvl) != 0)






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




 724                         if (status == IPADM_IF_EXISTS)
 725                                 status = IPADM_SUCCESS;






















 726 
 727                         if (is_ngz)
 728                                 af = atoi(afstr);
 729                 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,








 730                     &aobjstr) == 0) {
 731                         /*
 732                          * For addresses, we need to relocate addrprops from the
 733                          * nvlist `ifnvl'.
 734                          */
 735                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
 736                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
 737                             nvlist_exists(nvl, IPADM_NVP_DHCP)) {
 738                                 status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
 739                                     nvl, aobjstr);

 740                                 if (status != IPADM_SUCCESS)
 741                                         continue;
 742                         }
 743                         status = i_ipadm_init_addrobj(iph, nvl);

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



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


 942                 if (err == 0) {
 943                         void *newp;
 944 
 945                         /* allocated memory will be freed by the caller */
 946                         if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
 947                                 err = ENOMEM;
 948                         } else {
 949                                 *rbufp = newp;
 950                                 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
 951                         }
 952                 }
 953                 /* munmap() the door buffer */
 954                 (void) munmap(darg.rbuf, darg.rsize);
 955         } else {
 956                 if (darg.rsize != rsize)
 957                         err = EBADE;
 958         }
 959         return (err);
 960 }
 961 



























 962 /*
 963  * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
 964  *                      NULL, empty, or a single space (e.g., as returned by
 965  *                      domainname(1M)/sysinfo).
 966  *
 967  *   input: const char *: the hostname to inspect;
 968  *  output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
 969  *                      criteria above; otherwise, B_FALSE;
 970  */
 971 
 972 boolean_t
 973 ipadm_is_nil_hostname(const char *hostname)
 974 {
 975         return (hostname == NULL || *hostname == '\0' ||
 976             (*hostname == ' ' && hostname[1] == '\0'));
 977 }
 978 
 979 /*
 980  * ipadm_is_valid_hostname(): check whether a string is a valid hostname
 981  *




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


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

































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


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

 664         ipadm_status_t  ret_status = IPADM_SUCCESS;
 665         char            newifname[LIFNAMSIZ];
 666         char            *aobjstr;
 667         uint16_t        *afs;
 668         char            *gifname;
 669         uint_t          nelem = 0;
 670         boolean_t       init_from_gz = B_FALSE;
 671         boolean_t       move_to_group = B_FALSE;
 672 
 673         (void) strlcpy(newifname, ifname, sizeof (newifname));
 674 
 675         /*
 676          * First go through the ifnvl nvlist looking for nested nvlist
 677          * containing interface class and address families.

 678          */
 679         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 680             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 681                 char *icstr;
 682                 char **mifnames;
 683                 uint32_t ipadm_flags = IPADM_OPT_ACTIVE;
 684 
 685                 if (nvpair_value_nvlist(nvp, &nvl) != 0 ||
 686                     nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
 687                     &afs, &nelem) != 0)
 688                         continue;
 689 
 690                 /* Check if this is IPMP group interface */
 691                 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS,
 692                     &icstr) == 0 && atoi(icstr) == IPADM_IF_CLASS_IPMP)
 693                         ipadm_flags |= IPADM_OPT_IPMP;
 694 
 695                 /* Create interfaces for address families specified */
 696                 while (nelem-- > 0) {
 697                         uint16_t af = afs[nelem];
 698 
 699                         assert(af == AF_INET || af == AF_INET6);
 700 
 701                         status = i_ipadm_plumb_if(iph, newifname, af,
 702                             ipadm_flags);
 703                         if (status == IPADM_IF_EXISTS)
 704                                 status = IPADM_SUCCESS;
 705                         if (status != IPADM_SUCCESS)
 706                                 return (status);
 707                 }
 708                 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME,
 709                     &gifname) == 0) {
 710                         /*
 711                          * IPMP underlying interface. Move to the
 712                          * specified IPMP group.
 713                          */
 714                         move_to_group = B_TRUE;
 715                 } else if ((ipadm_flags & IPADM_OPT_IPMP) &&
 716                     nvlist_lookup_string_array(nvl, IPADM_NVP_MIFNAMES,
 717                     &mifnames, &nelem) == 0) {
 718                         /* Non-empty IPMP group interface */
 719                         while (nelem-- > 0) {
 720                                 (void) ipadm_add_ipmp_member(iph, newifname,
 721                                     mifnames[nelem], IPADM_OPT_ACTIVE);
 722                         }
 723                 }
 724                 if (iph->iph_zoneid != GLOBAL_ZONEID)
 725                         init_from_gz = B_TRUE;
 726         }
 727 
 728         if (status != IPADM_SUCCESS)
 729                 return (status);
 730 
 731         /*
 732          * Go through the ifnvl nvlist again, applying persistent configuration.
 733          */
 734         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 735             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 736                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
 737                         continue;
 738                 if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 739                     &aobjstr) == 0) {
 740                         /*
 741                          * For addresses, we need to relocate addrprops from the
 742                          * nvlist `ifnvl'.
 743                          */
 744                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
 745                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
 746                             nvlist_exists(nvl, IPADM_NVP_DHCP)) {
 747                                 status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
 748                                     nvl, aobjstr);
 749 
 750                                 if (status != IPADM_SUCCESS)
 751                                         continue;
 752                         }
 753                         status = i_ipadm_init_addrobj(iph, nvl);
 754 
 755                         /*
 756                          * If this address is in use on some other interface,
 757                          * we want to record an error to be returned as
 758                          * a soft error and continue processing the rest of
 759                          * the addresses.
 760                          */
 761                         if (status == IPADM_ADDR_NOTAVAIL) {
 762                                 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
 763                                 status = IPADM_SUCCESS;
 764                         }
 765                 } else if (nvlist_exists(nvl, IPADM_NVP_PROTONAME) == B_TRUE) {

 766                         status = i_ipadm_init_ifprop(iph, nvl);
 767                 }
 768                 if (status != IPADM_SUCCESS)
 769                         return (status);
 770         }
 771         if (move_to_group) {
 772                 (void) ipadm_add_ipmp_member(iph, gifname, newifname,
 773                     IPADM_OPT_ACTIVE);
 774         }
 775         if (init_from_gz)
 776                 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
 777         return (ret_status);
 778 }
 779 
 780 /*
 781  * Retrieves the persistent configuration for the given interface(s) in `ifs'
 782  * by contacting the daemon and dumps the information in `allifs'.
 783  */
 784 ipadm_status_t
 785 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
 786 {
 787         nvlist_t                *nvl = NULL;
 788         size_t                  nvlsize, bufsize;
 789         ipmgmt_initif_arg_t     *iargp;
 790         char                    *buf = NULL, *nvlbuf = NULL;
 791         ipmgmt_get_rval_t       *rvalp = NULL;
 792         int                     err;
 793         ipadm_status_t          status = IPADM_SUCCESS;
 794 
 795         if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)


 955                 if (err == 0) {
 956                         void *newp;
 957 
 958                         /* allocated memory will be freed by the caller */
 959                         if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
 960                                 err = ENOMEM;
 961                         } else {
 962                                 *rbufp = newp;
 963                                 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
 964                         }
 965                 }
 966                 /* munmap() the door buffer */
 967                 (void) munmap(darg.rbuf, darg.rsize);
 968         } else {
 969                 if (darg.rsize != rsize)
 970                         err = EBADE;
 971         }
 972         return (err);
 973 }
 974 
 975 /*
 976  * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
 977  * to do a door_call to ipmgmtd, that should return persistent information
 978  * about interfaces or/and addresses from ipadm DB
 979  */
 980 ipadm_status_t
 981 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg, size_t garg_size,
 982     nvlist_t **onvl)
 983 {
 984         ipmgmt_get_rval_t       *rvalp;
 985         int                     err;
 986         size_t                  nvlsize;
 987         char                    *nvlbuf;
 988 
 989         rvalp = malloc(sizeof (ipmgmt_get_rval_t));
 990         err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
 991             sizeof (*rvalp), B_TRUE);
 992         if (err == 0) {
 993                 nvlsize = rvalp->ir_nvlsize;
 994                 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
 995                 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
 996         }
 997         free(rvalp);
 998 
 999         return (ipadm_errno2status(err));
1000 }
1001 
1002 /*
1003  * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
1004  *                      NULL, empty, or a single space (e.g., as returned by
1005  *                      domainname(1M)/sysinfo).
1006  *
1007  *   input: const char *: the hostname to inspect;
1008  *  output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
1009  *                      criteria above; otherwise, B_FALSE;
1010  */
1011 
1012 boolean_t
1013 ipadm_is_nil_hostname(const char *hostname)
1014 {
1015         return (hostname == NULL || *hostname == '\0' ||
1016             (*hostname == ' ' && hostname[1] == '\0'));
1017 }
1018 
1019 /*
1020  * ipadm_is_valid_hostname(): check whether a string is a valid hostname
1021  *