Print this page
NEX-9305 libipadm`ipadm_enable_addr() leaks addrnvl
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-8955 creating addresses on underlying IPMP links is broken
NEX-9102 deleting addresses from underlying IPMP interfaces leaves them down
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@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-3908 IPMP group can have only one IP address
Reviewed by: Gordon Ross <gwr@nexenta.com>
OS-161: Integrate IPMP changes (lint)
OS-161: Integrate IPMP changes
   1 /*
   2  * CDDL HEADER START
   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 (c) 2013 by Delphix. All rights reserved.

  24  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  25  */
  26 
  27 /*
  28  * This file contains functions for address management such as creating
  29  * an address, deleting an address, enabling an address, disabling an
  30  * address, bringing an address down or up, setting/getting properties
  31  * on an address object and listing address information
  32  * for all addresses in active as well as persistent configuration.
  33  */
  34 #include <sys/types.h>
  35 #include <sys/socket.h>
  36 #include <sys/param.h>
  37 #include <netdb.h>
  38 #include <inet/ip.h>
  39 #include <string.h>
  40 #include <strings.h>
  41 #include <assert.h>
  42 #include <sys/sockio.h>
  43 #include <errno.h>


 280                         continue;
 281                 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
 282                     nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
 283                         break;
 284         }
 285         if (nvp == NULL)
 286                 goto fail;
 287         for (nvp = nvlist_next_nvpair(anvl, NULL);
 288             nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
 289                 name = nvpair_name(nvp);
 290                 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
 291                         af = AF_INET;
 292                         break;
 293                 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
 294                         af = AF_INET6;
 295                         break;
 296                 }
 297         }
 298         assert(af != AF_UNSPEC);
 299         if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
 300             nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
 301             ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
 302                 goto fail;
 303         }



 304         nvlist_free(onvl);
 305         return (IPADM_SUCCESS);
 306 fail:
 307         nvlist_free(onvl);
 308         return (IPADM_NOTFOUND);
 309 }
 310 
 311 /*
 312  * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
 313  * fills in the address objname, the address type and the ipadm_flags.
 314  */
 315 ipadm_status_t
 316 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
 317 {
 318         ipmgmt_aobjop_arg_t     larg;
 319         ipmgmt_aobjop_rval_t    rval, *rvalp;
 320         int                     err;
 321 
 322         larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
 323         (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,


 366  * daemon's aobjmap (active configuration). This API is called by in.ndpd to
 367  * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
 368  * removed.
 369  */
 370 ipadm_status_t
 371 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 372     const char *aobjname, ipadm_addr_type_t atype, int lnum)
 373 {
 374         struct ipadm_addrobj_s  aobj;
 375 
 376         i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
 377         aobj.ipadm_af = af;
 378         aobj.ipadm_lifnum = lnum;
 379         return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
 380 }
 381 
 382 /*
 383  * Gets all the addresses from active configuration and populates the
 384  * address information in `addrinfo'.
 385  */
 386 static ipadm_status_t
 387 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
 388     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
 389 {
 390         ipadm_status_t          status;
 391         struct ifaddrs          *ifap, *ifa;
 392         ipadm_addr_info_t       *curr, *prev = NULL;
 393         struct ifaddrs          *cifaddr;
 394         struct lifreq           lifr;
 395         int                     sock;
 396         uint64_t                flags;
 397         char                    cifname[LIFNAMSIZ];
 398         struct sockaddr_in6     *sin6;
 399         struct ipadm_addrobj_s  ipaddr;
 400         char                    *sep;
 401         int                     lnum;
 402 
 403 retry:
 404         *addrinfo = NULL;
 405 
 406         /* Get all the configured addresses */


1696         if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1697             (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1698                 return (IPADM_INVALID_ARG);
1699         }
1700 
1701         /*
1702          * For the given aobjname, get the addrobj it represents and
1703          * set the property value for that object.
1704          */
1705         i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1706         if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1707                 return (status);
1708 
1709         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1710                 return (IPADM_OP_DISABLE_OBJ);
1711 
1712         /* Persistent operation not allowed on a temporary object. */
1713         if ((pflags & IPADM_OPT_PERSIST) &&
1714             !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1715                 return (IPADM_TEMPORARY_OBJ);
1716 
1717         /*
1718          * Currently, setting an address property on an address object of type
1719          * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1720          * in.ndpd retrieving the address properties from ipmgmtd for given
1721          * address object and then setting them on auto-configured addresses,
1722          * whenever in.ndpd gets a new prefix. This will be supported in
1723          * future releases.
1724          */
1725         if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1726                 return (IPADM_NOTSUP);
1727 
1728         /*
1729          * Setting an address property on an address object that is
1730          * not present in active configuration is not supported.
1731          */
1732         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1733                 return (IPADM_NOTSUP);
1734 
1735         af = ipaddr.ipadm_af;
1736         if (reset) {


2392         char            *aname, *cp;
2393         char            ifname[IPADM_AOBJSIZ];
2394         ifspec_t        ifsp;
2395 
2396         if (ipaddr == NULL)
2397                 return (IPADM_INVALID_ARG);
2398         *ipaddr = NULL;
2399 
2400         if (aobjname == NULL || aobjname[0] == '\0')
2401                 return (IPADM_INVALID_ARG);
2402 
2403         if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2404                 return (IPADM_INVALID_ARG);
2405 
2406         if ((aname = strchr(ifname, '/')) != NULL)
2407                 *aname++ = '\0';
2408 
2409         /* Check if the interface name is valid. */
2410         if (!ifparse_ifspec(ifname, &ifsp))
2411                 return (IPADM_INVALID_ARG);
2412 
2413         /* Check if the given addrobj name is valid. */
2414         if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2415                 return (IPADM_INVALID_ARG);
2416 
2417         if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2418                 return (IPADM_NO_MEMORY);
2419 
2420         /*
2421          * If the ifname has logical interface number, extract it and assign
2422          * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2423          * this today. We will check for the validity later in
2424          * i_ipadm_validate_create_addr().
2425          */
2426         if (ifsp.ifsp_lunvalid) {
2427                 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2428                 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2429                 *cp = '\0';
2430         }
2431         (void) strlcpy(newaddr->ipadm_ifname, ifname,
2432             sizeof (newaddr->ipadm_ifname));
2433 
2434         if (aname != NULL) {
2435                 (void) snprintf(newaddr->ipadm_aobjname,
2436                     sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);


2578                     iph->iph_sock6);
2579                 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2580                         return (ipadm_errno2status(errno));
2581                 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2582         }
2583         return (IPADM_SUCCESS);
2584 }
2585 
2586 /*
2587  * Reads all the address lines from the persistent DB into the nvlist `onvl',
2588  * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2589  * it returns all the addresses for the given interface `ifname'.
2590  * If an `aobjname' is specified, then the address line corresponding to
2591  * that name will be returned.
2592  */
2593 static ipadm_status_t
2594 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2595     const char *aobjname, nvlist_t **onvl)
2596 {
2597         ipmgmt_getaddr_arg_t    garg;
2598         ipmgmt_get_rval_t       *rvalp;
2599         int                     err;
2600         size_t                  nvlsize;
2601         char                    *nvlbuf;
2602 
2603         /* Populate the door_call argument structure */
2604         bzero(&garg, sizeof (garg));
2605         garg.ia_cmd = IPMGMT_CMD_GETADDR;
2606         if (aobjname != NULL)
2607                 (void) strlcpy(garg.ia_aobjname, aobjname,
2608                     sizeof (garg.ia_aobjname));
2609         if (ifname != NULL)
2610                 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2611 
2612         rvalp = malloc(sizeof (ipmgmt_get_rval_t));
2613         err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
2614             sizeof (*rvalp), B_TRUE);
2615         if (err == 0) {
2616                 nvlsize = rvalp->ir_nvlsize;
2617                 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
2618                 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
2619         }
2620         free(rvalp);
2621         return (ipadm_errno2status(err));
2622 }
2623 
2624 /*
2625  * Adds the IP address contained in the 'ipaddr' argument to the physical
2626  * interface represented by 'ifname' after doing the required validation.
2627  * If the interface does not exist, it is created before the address is
2628  * added.
2629  *
2630  * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2631  * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2632  * if provided, will be ignored and replaced with the newly generated name.
2633  * The interface name provided has to be a logical interface name that
2634  * already exists. No new logical interface will be added in this function.
2635  *
2636  * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2637  * are plumbed (if they haven't been already).  Otherwise, just the interface
2638  * specified in `addr' is plumbed.
2639  */
2640 ipadm_status_t
2641 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2642 {
2643         ipadm_status_t          status;
2644         sa_family_t             af;
2645         sa_family_t             daf;
2646         sa_family_t             other_af;
2647         boolean_t               created_af = B_FALSE;
2648         boolean_t               created_other_af = B_FALSE;
2649         ipadm_addr_type_t       type;
2650         char                    *ifname = addr->ipadm_ifname;
2651         boolean_t               legacy = (iph->iph_flags & IPH_LEGACY);
2652         boolean_t               aobjfound;
2653         boolean_t               is_6to4;
2654         struct lifreq           lifr;
2655         uint64_t                ifflags;
2656         boolean_t               is_boot = (iph->iph_flags & IPH_IPMGMTD);


2657 
2658         /* check for solaris.network.interface.config authorization */
2659         if (!ipadm_check_auth())
2660                 return (IPADM_EAUTH);
2661 
2662         /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2663         status = i_ipadm_validate_create_addr(iph, addr, flags);
2664         if (status != IPADM_SUCCESS)
2665                 return (status);
2666 
2667         /*
2668          * For Legacy case, check if an addrobj already exists for the
2669          * given logical interface name. If one does not exist,
2670          * a default name will be generated and added to the daemon's
2671          * aobjmap.
2672          */
2673         if (legacy) {
2674                 struct ipadm_addrobj_s  ipaddr;
2675 
2676                 ipaddr = *addr;
2677                 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2678                 if (status == IPADM_SUCCESS) {
2679                         aobjfound = B_TRUE;
2680                         /*
2681                          * With IPH_LEGACY, modifying an address that is not
2682                          * a static address will return with an error.
2683                          */
2684                         if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2685                                 return (IPADM_NOTSUP);
2686                         /*


2781                 }
2782         }
2783 
2784         /*
2785          * For 6to4 interfaces, kernel configures a default link-local
2786          * address. We need to replace it, if the caller has provided
2787          * an address that is different from the default link-local.
2788          */
2789         if (status == IPADM_SUCCESS && is_6to4) {
2790                 bzero(&lifr, sizeof (lifr));
2791                 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2792                     sizeof (lifr.lifr_name));
2793                 if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2794                         status = ipadm_errno2status(errno);
2795                         goto fail;
2796                 }
2797                 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2798                         return (IPADM_SUCCESS);
2799         }
2800 











2801         /* Create the address. */
2802         type = addr->ipadm_atype;
2803         switch (type) {
2804         case IPADM_ADDR_STATIC:
2805                 status = i_ipadm_create_addr(iph, addr, flags);
2806                 break;
2807         case IPADM_ADDR_DHCP:
2808                 status = i_ipadm_create_dhcp(iph, addr, flags);
2809                 break;
2810         case IPADM_ADDR_IPV6_ADDRCONF:
2811                 status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2812                 break;
2813         default:
2814                 status = IPADM_INVALID_ARG;
2815                 break;
2816         }
2817 






2818         /*
2819          * If address was not created successfully, unplumb the interface
2820          * if it was plumbed implicitly in this function and remove the
2821          * addrobj created by the ipmgmtd daemon as a placeholder.
2822          * If IPH_LEGACY is set, then remove the addrobj only if it was
2823          * created in this function.
2824          */
2825 fail:
2826         if (status != IPADM_DHCP_IPC_TIMEOUT &&
2827             status != IPADM_SUCCESS) {
2828                 if (!legacy) {
2829                         if (created_af || created_other_af) {
2830                                 if (created_af) {
2831                                         (void) i_ipadm_delete_if(iph, ifname,
2832                                             af, flags);
2833                                 }
2834                                 if (created_other_af) {
2835                                         (void) i_ipadm_delete_if(iph, ifname,
2836                                             other_af, flags);
2837                                 }


2870         af = ipaddr->ipadm_af;
2871         sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2872 
2873         /* If prefixlen was not provided, get default prefixlen */
2874         if (ipaddr->ipadm_static_prefixlen == 0) {
2875                 /* prefixlen was not provided, get default prefixlen */
2876                 status = i_ipadm_get_default_prefixlen(
2877                     &ipaddr->ipadm_static_addr,
2878                     &ipaddr->ipadm_static_prefixlen);
2879                 if (status != IPADM_SUCCESS)
2880                         return (status);
2881                 default_prefixlen = B_TRUE;
2882         }
2883         (void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2884             (struct sockaddr *)mask);
2885 
2886         /*
2887          * Create a new logical interface if needed; otherwise, just
2888          * use the 0th logical interface.
2889          */
2890 retry:
2891         if (!(iph->iph_flags & IPH_LEGACY)) {
2892                 status = i_ipadm_do_addif(iph, ipaddr);
2893                 if (status != IPADM_SUCCESS)
2894                         return (status);
2895                 /*
2896                  * We don't have to set the lifnum for IPH_INIT case, because
2897                  * there is no placeholder created for the address object in
2898                  * this case. For IPH_LEGACY, we don't do this because the
2899                  * lifnum is given by the caller and it will be set in the
2900                  * end while we call the i_ipadm_addr_persist().
2901                  */
2902                 if (!(iph->iph_flags & IPH_INIT)) {
2903                         status = i_ipadm_setlifnum_addrobj(iph, ipaddr);
2904                         if (status == IPADM_ADDROBJ_EXISTS)
2905                                 goto retry;
2906                         if (status != IPADM_SUCCESS)
2907                                 return (status);
2908                 }
2909         }
2910         i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2911             sizeof (lifr.lifr_name));
2912         lifr.lifr_addr = *mask;
2913         if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2914                 status = ipadm_errno2status(errno);
2915                 goto ret;
2916         }
2917         lifr.lifr_addr = *addr;
2918         if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2919                 status = ipadm_errno2status(errno);
2920                 goto ret;
2921         }
2922         /* Set the destination address, if one is given. */
2923         if (daddr->ss_family != AF_UNSPEC) {
2924                 lifr.lifr_addr = *daddr;
2925                 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2926                         status = ipadm_errno2status(errno);
2927                         goto ret;
2928                 }
2929         }
2930 
2931         if (flags & IPADM_OPT_UP) {
2932                 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
2933 
2934                 /*










2935                  * IPADM_DAD_FOUND is a soft-error for create-addr.
2936                  * No need to tear down the address.
2937                  */
2938                 if (status == IPADM_DAD_FOUND)
2939                         status = IPADM_SUCCESS;
2940         }
2941 
2942         if (status == IPADM_SUCCESS && !is_boot) {
2943                 /*
2944                  * For IPH_LEGACY, we might be modifying the address on
2945                  * an address object that already exists e.g. by doing
2946                  * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2947                  * So, we need to store the object only if it does not
2948                  * already exist in ipmgmtd.
2949                  */
2950                 if (legacy) {
2951                         bzero(&legacy_addr, sizeof (legacy_addr));
2952                         (void) strlcpy(legacy_addr.ipadm_aobjname,
2953                             ipaddr->ipadm_aobjname,
2954                             sizeof (legacy_addr.ipadm_aobjname));
2955                         status = i_ipadm_get_addrobj(iph, &legacy_addr);
2956                         if (status == IPADM_SUCCESS &&
2957                             legacy_addr.ipadm_lifnum >= 0) {
2958                                 return (status);
2959                         }
2960                 }
2961                 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2962                     flags, NULL);
2963         }
2964 ret:
2965         if (status != IPADM_SUCCESS && !legacy)
2966                 (void) i_ipadm_delete_addr(iph, ipaddr);

2967         return (status);
2968 }
2969 
2970 /*
2971  * Removes the address object identified by `aobjname' from both active and
2972  * persistent configuration. The address object will be removed from only
2973  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2974  *
2975  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2976  * in the address object will be removed from the physical interface.
2977  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2978  * whether the lease should be released. If IPADM_OPT_RELEASE is not
2979  * specified, the lease will be dropped. This option is not supported
2980  * for other address types.
2981  *
2982  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
2983  * all the autoconfigured addresses will be removed.
2984  * Finally, the address object is also removed from ipmgmtd's aobjmap and from
2985  * the persistent DB.
2986  */


3011         status = i_ipadm_get_addrobj(iph, &ipaddr);
3012         if (status != IPADM_SUCCESS)
3013                 return (status);
3014 
3015         if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
3016                 return (IPADM_NOTSUP);
3017         /*
3018          * If requested to delete just from active config but the address
3019          * is not in active config, return error.
3020          */
3021         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
3022             (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
3023                 return (IPADM_NOTFOUND);
3024         }
3025 
3026         /*
3027          * If address is present in active config, remove it from
3028          * kernel.
3029          */
3030         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {















3031                 switch (ipaddr.ipadm_atype) {
3032                 case IPADM_ADDR_STATIC:
3033                         status = i_ipadm_delete_addr(iph, &ipaddr);
3034                         break;
3035                 case IPADM_ADDR_DHCP:
3036                         status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
3037                         break;
3038                 case IPADM_ADDR_IPV6_ADDRCONF:
3039                         status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
3040                         break;
3041                 default:
3042                         /*
3043                          * This is the case of address object name residing in
3044                          * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
3045                          * through and delete that address object.
3046                          */
3047                         break;
3048                 }
3049 






3050                 /*
3051                  * If the address was previously deleted from the active
3052                  * config, we will get a IPADM_ENXIO from kernel.
3053                  * We will still proceed and purge the address information
3054                  * in the DB.
3055                  */
3056                 if (status == IPADM_ENXIO)
3057                         status = IPADM_SUCCESS;
3058                 else if (status != IPADM_SUCCESS)
3059                         return (status);
3060         }
3061 
3062         if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
3063             (flags & IPADM_OPT_PERSIST)) {
3064                 flags &= ~IPADM_OPT_PERSIST;
3065         }
3066         status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
3067         if (status == IPADM_NOTFOUND)
3068                 return (status);
3069         return (IPADM_SUCCESS);


3551         ipadm_status_t  status;
3552         char            lifname[LIFNAMSIZ];
3553 
3554         /* check for solaris.network.interface.config authorization */
3555         if (!ipadm_check_auth())
3556                 return (IPADM_EAUTH);
3557 
3558         /* validate input */
3559         if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3560             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3561                 return (IPADM_INVALID_ARG);
3562         }
3563 
3564         /* Retrieve the address object information. */
3565         status = i_ipadm_get_addrobj(iph, ipaddr);
3566         if (status != IPADM_SUCCESS)
3567                 return (status);
3568 
3569         if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3570                 return (IPADM_OP_DISABLE_OBJ);

3571         if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3572             !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3573                 return (IPADM_TEMPORARY_OBJ);

3574         if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3575             (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3576             (ipadm_flags & IPADM_OPT_PERSIST)))
3577                 return (IPADM_NOTSUP);
3578 
3579         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));

3580         return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3581 }
3582 
3583 /*
3584  * Marks the address in the address object `aobjname' up. This operation is
3585  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3586  * For an address object of type IPADM_ADDR_DHCP, this operation can
3587  * only be temporary and no updates will be made to the persistent DB.
3588  */
3589 ipadm_status_t
3590 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3591 {
3592         struct ipadm_addrobj_s ipaddr;
3593         ipadm_status_t  status;
3594         uint64_t        flags;
3595         char            lifname[LIFNAMSIZ];
3596 
3597         status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3598             &flags);
3599         if (status != IPADM_SUCCESS)


3786         uint64_t                ifflags = 0;
3787         boolean_t               p_exists;
3788         boolean_t               af_exists, other_af_exists, a_exists;
3789 
3790         if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3791             (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3792                 return (IPADM_INVALID_ARG);
3793         }
3794 
3795         if (ipaddr->ipadm_af == AF_UNSPEC)
3796                 return (IPADM_BAD_ADDR);
3797 
3798         if (!legacy && ipaddr->ipadm_lifnum != 0)
3799                 return (IPADM_INVALID_ARG);
3800 
3801         if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3802                 return (IPADM_NOTSUP);
3803 
3804         ifname = ipaddr->ipadm_ifname;
3805 
3806         if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
3807                 return (IPADM_NOTSUP);





3808 
3809         af = ipaddr->ipadm_af;
3810         af_exists = ipadm_if_enabled(iph, ifname, af);
3811         /*
3812          * For legacy case, interfaces are not implicitly plumbed. We need to
3813          * check if the interface exists in the active configuration.
3814          */
3815         if (legacy && !af_exists)
3816                 return (IPADM_ENXIO);
3817 
3818         other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3819         other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3820         /*
3821          * Check if one of the v4 or the v6 interfaces exists in the
3822          * active configuration. An interface is considered disabled only
3823          * if both v4 and v6 are not active.
3824          */
3825         a_exists = (af_exists || other_af_exists);
3826 
3827         /* Check if interface exists in the persistent configuration. */
3828         status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3829         if (status != IPADM_SUCCESS)
3830                 return (status);

3831         if (!a_exists && p_exists)
3832                 return (IPADM_OP_DISABLE_OBJ);
3833         if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
3834                 /*
3835                  * If address has to be created persistently,
3836                  * and the interface does not exist in the persistent
3837                  * store but in active config, fail.
3838                  */
3839                 return (IPADM_TEMPORARY_OBJ);
3840         }
3841         if (af_exists) {
3842                 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3843                 if (status != IPADM_SUCCESS)
3844                         return (status);
3845         }
3846 
3847         /* Perform validation steps (4) and (5) */
3848         islo = i_ipadm_is_loopback(ifname);
3849         isvni = i_ipadm_is_vni(ifname);
3850         switch (ipaddr->ipadm_atype) {
3851         case IPADM_ADDR_STATIC:
3852                 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3853                         return (IPADM_INVALID_ARG);
3854                 /* Check for a valid src address */
3855                 if (!legacy && sockaddrunspec(
3856                     (struct sockaddr *)&ipaddr->ipadm_static_addr))
3857                         return (IPADM_BAD_ADDR);
3858                 break;
3859         case IPADM_ADDR_DHCP:
3860                 if (islo || (ifflags & IFF_VRRP))


   1 /*
   2  * CDDL HEADER START
   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 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2013 by Delphix. All rights reserved.
  25  * Copyright 2016 Nexenta Systems, Inc.
  26  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  27  */
  28 
  29 /*
  30  * This file contains functions for address management such as creating
  31  * an address, deleting an address, enabling an address, disabling an
  32  * address, bringing an address down or up, setting/getting properties
  33  * on an address object and listing address information
  34  * for all addresses in active as well as persistent configuration.
  35  */
  36 #include <sys/types.h>
  37 #include <sys/socket.h>
  38 #include <sys/param.h>
  39 #include <netdb.h>
  40 #include <inet/ip.h>
  41 #include <string.h>
  42 #include <strings.h>
  43 #include <assert.h>
  44 #include <sys/sockio.h>
  45 #include <errno.h>


 282                         continue;
 283                 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
 284                     nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
 285                         break;
 286         }
 287         if (nvp == NULL)
 288                 goto fail;
 289         for (nvp = nvlist_next_nvpair(anvl, NULL);
 290             nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
 291                 name = nvpair_name(nvp);
 292                 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
 293                         af = AF_INET;
 294                         break;
 295                 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
 296                         af = AF_INET6;
 297                         break;
 298                 }
 299         }
 300         assert(af != AF_UNSPEC);
 301         if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
 302             nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0)

 303                 goto fail;
 304 
 305         if (ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS)
 306                 goto fail;
 307 
 308         nvlist_free(onvl);
 309         return (IPADM_SUCCESS);
 310 fail:
 311         nvlist_free(onvl);
 312         return (IPADM_NOTFOUND);
 313 }
 314 
 315 /*
 316  * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
 317  * fills in the address objname, the address type and the ipadm_flags.
 318  */
 319 ipadm_status_t
 320 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
 321 {
 322         ipmgmt_aobjop_arg_t     larg;
 323         ipmgmt_aobjop_rval_t    rval, *rvalp;
 324         int                     err;
 325 
 326         larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
 327         (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,


 370  * daemon's aobjmap (active configuration). This API is called by in.ndpd to
 371  * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
 372  * removed.
 373  */
 374 ipadm_status_t
 375 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 376     const char *aobjname, ipadm_addr_type_t atype, int lnum)
 377 {
 378         struct ipadm_addrobj_s  aobj;
 379 
 380         i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
 381         aobj.ipadm_af = af;
 382         aobj.ipadm_lifnum = lnum;
 383         return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
 384 }
 385 
 386 /*
 387  * Gets all the addresses from active configuration and populates the
 388  * address information in `addrinfo'.
 389  */
 390 ipadm_status_t
 391 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
 392     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
 393 {
 394         ipadm_status_t          status;
 395         struct ifaddrs          *ifap, *ifa;
 396         ipadm_addr_info_t       *curr, *prev = NULL;
 397         struct ifaddrs          *cifaddr;
 398         struct lifreq           lifr;
 399         int                     sock;
 400         uint64_t                flags;
 401         char                    cifname[LIFNAMSIZ];
 402         struct sockaddr_in6     *sin6;
 403         struct ipadm_addrobj_s  ipaddr;
 404         char                    *sep;
 405         int                     lnum;
 406 
 407 retry:
 408         *addrinfo = NULL;
 409 
 410         /* Get all the configured addresses */


1700         if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1701             (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1702                 return (IPADM_INVALID_ARG);
1703         }
1704 
1705         /*
1706          * For the given aobjname, get the addrobj it represents and
1707          * set the property value for that object.
1708          */
1709         i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1710         if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1711                 return (status);
1712 
1713         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1714                 return (IPADM_OP_DISABLE_OBJ);
1715 
1716         /* Persistent operation not allowed on a temporary object. */
1717         if ((pflags & IPADM_OPT_PERSIST) &&
1718             !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1719                 return (IPADM_TEMPORARY_OBJ);

1720         /*
1721          * Currently, setting an address property on an address object of type
1722          * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1723          * in.ndpd retrieving the address properties from ipmgmtd for given
1724          * address object and then setting them on auto-configured addresses,
1725          * whenever in.ndpd gets a new prefix. This will be supported in
1726          * future releases.
1727          */
1728         if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1729                 return (IPADM_NOTSUP);
1730 
1731         /*
1732          * Setting an address property on an address object that is
1733          * not present in active configuration is not supported.
1734          */
1735         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1736                 return (IPADM_NOTSUP);
1737 
1738         af = ipaddr.ipadm_af;
1739         if (reset) {


2395         char            *aname, *cp;
2396         char            ifname[IPADM_AOBJSIZ];
2397         ifspec_t        ifsp;
2398 
2399         if (ipaddr == NULL)
2400                 return (IPADM_INVALID_ARG);
2401         *ipaddr = NULL;
2402 
2403         if (aobjname == NULL || aobjname[0] == '\0')
2404                 return (IPADM_INVALID_ARG);
2405 
2406         if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2407                 return (IPADM_INVALID_ARG);
2408 
2409         if ((aname = strchr(ifname, '/')) != NULL)
2410                 *aname++ = '\0';
2411 
2412         /* Check if the interface name is valid. */
2413         if (!ifparse_ifspec(ifname, &ifsp))
2414                 return (IPADM_INVALID_ARG);

2415         /* Check if the given addrobj name is valid. */
2416         if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2417                 return (IPADM_INVALID_ARG);

2418         if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2419                 return (IPADM_NO_MEMORY);
2420 
2421         /*
2422          * If the ifname has logical interface number, extract it and assign
2423          * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2424          * this today. We will check for the validity later in
2425          * i_ipadm_validate_create_addr().
2426          */
2427         if (ifsp.ifsp_lunvalid) {
2428                 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2429                 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2430                 *cp = '\0';
2431         }
2432         (void) strlcpy(newaddr->ipadm_ifname, ifname,
2433             sizeof (newaddr->ipadm_ifname));
2434 
2435         if (aname != NULL) {
2436                 (void) snprintf(newaddr->ipadm_aobjname,
2437                     sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);


2579                     iph->iph_sock6);
2580                 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2581                         return (ipadm_errno2status(errno));
2582                 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2583         }
2584         return (IPADM_SUCCESS);
2585 }
2586 
2587 /*
2588  * Reads all the address lines from the persistent DB into the nvlist `onvl',
2589  * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2590  * it returns all the addresses for the given interface `ifname'.
2591  * If an `aobjname' is specified, then the address line corresponding to
2592  * that name will be returned.
2593  */
2594 static ipadm_status_t
2595 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2596     const char *aobjname, nvlist_t **onvl)
2597 {
2598         ipmgmt_getaddr_arg_t    garg;




2599 
2600         /* Populate the door_call argument structure */
2601         bzero(&garg, sizeof (garg));
2602         garg.ia_cmd = IPMGMT_CMD_GETADDR;
2603         if (aobjname != NULL)
2604                 (void) strlcpy(garg.ia_aobjname, aobjname,
2605                     sizeof (garg.ia_aobjname));
2606         if (ifname != NULL)
2607                 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2608 
2609         return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));









2610 }
2611 
2612 /*
2613  * Adds the IP address contained in the 'ipaddr' argument to the physical
2614  * interface represented by 'ifname' after doing the required validation.
2615  * If the interface does not exist, it is created before the address is
2616  * added.
2617  *
2618  * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2619  * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2620  * if provided, will be ignored and replaced with the newly generated name.
2621  * The interface name provided has to be a logical interface name that
2622  * already exists. No new logical interface will be added in this function.
2623  *
2624  * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2625  * are plumbed (if they haven't been already).  Otherwise, just the interface
2626  * specified in `addr' is plumbed.
2627  */
2628 ipadm_status_t
2629 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2630 {
2631         ipadm_status_t          status;
2632         sa_family_t             af;
2633         sa_family_t             daf;
2634         sa_family_t             other_af;
2635         boolean_t               created_af = B_FALSE;
2636         boolean_t               created_other_af = B_FALSE;
2637         ipadm_addr_type_t       type;
2638         char                    *ifname = addr->ipadm_ifname;
2639         boolean_t               legacy = (iph->iph_flags & IPH_LEGACY);
2640         boolean_t               aobjfound;
2641         boolean_t               is_6to4;
2642         struct lifreq           lifr;
2643         uint64_t                ifflags;
2644         boolean_t               is_boot = (iph->iph_flags & IPH_IPMGMTD);
2645         boolean_t               is_ipmp;
2646         char                    gifname[LIFGRNAMSIZ];
2647 
2648         /* check for solaris.network.interface.config authorization */
2649         if (!ipadm_check_auth())
2650                 return (IPADM_EAUTH);
2651 
2652         /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2653         status = i_ipadm_validate_create_addr(iph, addr, flags);
2654         if (status != IPADM_SUCCESS)
2655                 return (status);

2656         /*
2657          * For Legacy case, check if an addrobj already exists for the
2658          * given logical interface name. If one does not exist,
2659          * a default name will be generated and added to the daemon's
2660          * aobjmap.
2661          */
2662         if (legacy) {
2663                 struct ipadm_addrobj_s  ipaddr;
2664 
2665                 ipaddr = *addr;
2666                 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2667                 if (status == IPADM_SUCCESS) {
2668                         aobjfound = B_TRUE;
2669                         /*
2670                          * With IPH_LEGACY, modifying an address that is not
2671                          * a static address will return with an error.
2672                          */
2673                         if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2674                                 return (IPADM_NOTSUP);
2675                         /*


2770                 }
2771         }
2772 
2773         /*
2774          * For 6to4 interfaces, kernel configures a default link-local
2775          * address. We need to replace it, if the caller has provided
2776          * an address that is different from the default link-local.
2777          */
2778         if (status == IPADM_SUCCESS && is_6to4) {
2779                 bzero(&lifr, sizeof (lifr));
2780                 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2781                     sizeof (lifr.lifr_name));
2782                 if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2783                         status = ipadm_errno2status(errno);
2784                         goto fail;
2785                 }
2786                 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2787                         return (IPADM_SUCCESS);
2788         }
2789 
2790         /*
2791          * If interface is an IPMP group member, move it out of the group before
2792          * performing any operations on it.
2793          */
2794         if ((is_ipmp = i_ipadm_is_under_ipmp(iph, addr->ipadm_ifname))) {
2795                 (void) i_ipadm_get_groupname_active(iph, addr->ipadm_ifname,
2796                     gifname, sizeof (gifname));
2797                 (void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
2798                     "");
2799         }
2800 
2801         /* Create the address. */
2802         type = addr->ipadm_atype;
2803         switch (type) {
2804         case IPADM_ADDR_STATIC:
2805                 status = i_ipadm_create_addr(iph, addr, flags);
2806                 break;
2807         case IPADM_ADDR_DHCP:
2808                 status = i_ipadm_create_dhcp(iph, addr, flags);
2809                 break;
2810         case IPADM_ADDR_IPV6_ADDRCONF:
2811                 status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2812                 break;
2813         default:
2814                 status = IPADM_INVALID_ARG;
2815                 break;
2816         }
2817 
2818         /* Move the underlying IPMP interface back to the group */
2819         if (is_ipmp) {
2820                 (void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
2821                     gifname);
2822         }
2823 
2824         /*
2825          * If address was not created successfully, unplumb the interface
2826          * if it was plumbed implicitly in this function and remove the
2827          * addrobj created by the ipmgmtd daemon as a placeholder.
2828          * If IPH_LEGACY is set, then remove the addrobj only if it was
2829          * created in this function.
2830          */
2831 fail:
2832         if (status != IPADM_DHCP_IPC_TIMEOUT &&
2833             status != IPADM_SUCCESS) {
2834                 if (!legacy) {
2835                         if (created_af || created_other_af) {
2836                                 if (created_af) {
2837                                         (void) i_ipadm_delete_if(iph, ifname,
2838                                             af, flags);
2839                                 }
2840                                 if (created_other_af) {
2841                                         (void) i_ipadm_delete_if(iph, ifname,
2842                                             other_af, flags);
2843                                 }


2876         af = ipaddr->ipadm_af;
2877         sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2878 
2879         /* If prefixlen was not provided, get default prefixlen */
2880         if (ipaddr->ipadm_static_prefixlen == 0) {
2881                 /* prefixlen was not provided, get default prefixlen */
2882                 status = i_ipadm_get_default_prefixlen(
2883                     &ipaddr->ipadm_static_addr,
2884                     &ipaddr->ipadm_static_prefixlen);
2885                 if (status != IPADM_SUCCESS)
2886                         return (status);
2887                 default_prefixlen = B_TRUE;
2888         }
2889         (void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2890             (struct sockaddr *)mask);
2891 
2892         /*
2893          * Create a new logical interface if needed; otherwise, just
2894          * use the 0th logical interface.
2895          */

2896         if (!(iph->iph_flags & IPH_LEGACY)) {
2897                 status = i_ipadm_do_addif(iph, ipaddr);
2898                 if (status != IPADM_SUCCESS)
2899                         return (status);













2900         }

2901         i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2902             sizeof (lifr.lifr_name));
2903         lifr.lifr_addr = *mask;
2904         if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2905                 status = ipadm_errno2status(errno);
2906                 goto ret;
2907         }
2908         lifr.lifr_addr = *addr;
2909         if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2910                 status = ipadm_errno2status(errno);
2911                 goto ret;
2912         }
2913         /* Set the destination address, if one is given. */
2914         if (daddr->ss_family != AF_UNSPEC) {
2915                 lifr.lifr_addr = *daddr;
2916                 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2917                         status = ipadm_errno2status(errno);
2918                         goto ret;
2919                 }
2920         }
2921 
2922         if (flags & IPADM_OPT_UP) {
2923                 uint32_t        iff_flags = IFF_UP;
2924 
2925                 /*
2926                  * Set the NOFAILOVER flag only on underlying IPMP interface
2927                  * and not the IPMP group interface itself.
2928                  */
2929                 if (i_ipadm_is_under_ipmp(iph, lifr.lifr_name) &&
2930                     !i_ipadm_is_ipmp(iph, lifr.lifr_name))
2931                         iff_flags |= IFF_NOFAILOVER;
2932                 status = i_ipadm_set_flags(iph, lifr.lifr_name,
2933                     af, iff_flags, 0);
2934 
2935                 /*
2936                  * IPADM_DAD_FOUND is a soft-error for create-addr.
2937                  * No need to tear down the address.
2938                  */
2939                 if (status == IPADM_DAD_FOUND)
2940                         status = IPADM_SUCCESS;
2941         }
2942 
2943         if (status == IPADM_SUCCESS && !is_boot) {
2944                 /*
2945                  * For IPH_LEGACY, we might be modifying the address on
2946                  * an address object that already exists e.g. by doing
2947                  * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2948                  * So, we need to store the object only if it does not
2949                  * already exist in ipmgmtd.
2950                  */
2951                 if (legacy) {
2952                         bzero(&legacy_addr, sizeof (legacy_addr));
2953                         (void) strlcpy(legacy_addr.ipadm_aobjname,
2954                             ipaddr->ipadm_aobjname,
2955                             sizeof (legacy_addr.ipadm_aobjname));
2956                         status = i_ipadm_get_addrobj(iph, &legacy_addr);
2957                         if (status == IPADM_SUCCESS &&
2958                             legacy_addr.ipadm_lifnum >= 0) {
2959                                 return (status);
2960                         }
2961                 }
2962                 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2963                     flags, NULL);
2964         }
2965 ret:
2966         if (status != IPADM_SUCCESS && !legacy)
2967                 (void) i_ipadm_delete_addr(iph, ipaddr);
2968 
2969         return (status);
2970 }
2971 
2972 /*
2973  * Removes the address object identified by `aobjname' from both active and
2974  * persistent configuration. The address object will be removed from only
2975  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2976  *
2977  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2978  * in the address object will be removed from the physical interface.
2979  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2980  * whether the lease should be released. If IPADM_OPT_RELEASE is not
2981  * specified, the lease will be dropped. This option is not supported
2982  * for other address types.
2983  *
2984  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
2985  * all the autoconfigured addresses will be removed.
2986  * Finally, the address object is also removed from ipmgmtd's aobjmap and from
2987  * the persistent DB.
2988  */


3013         status = i_ipadm_get_addrobj(iph, &ipaddr);
3014         if (status != IPADM_SUCCESS)
3015                 return (status);
3016 
3017         if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
3018                 return (IPADM_NOTSUP);
3019         /*
3020          * If requested to delete just from active config but the address
3021          * is not in active config, return error.
3022          */
3023         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
3024             (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
3025                 return (IPADM_NOTFOUND);
3026         }
3027 
3028         /*
3029          * If address is present in active config, remove it from
3030          * kernel.
3031          */
3032         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
3033                 boolean_t       is_ipmp;
3034                 char            gifname[LIFGRNAMSIZ];
3035 
3036                 /*
3037                  * If interface is an IPMP group member, move it out of the
3038                  * group before performing any operations on it.
3039                  */
3040                 if ((is_ipmp = i_ipadm_is_under_ipmp(iph,
3041                     ipaddr.ipadm_ifname))) {
3042                         (void) i_ipadm_get_groupname_active(iph,
3043                             ipaddr.ipadm_ifname, gifname, sizeof (gifname));
3044                         (void) i_ipadm_set_groupname_active(iph,
3045                             ipaddr.ipadm_ifname, "");
3046                 }
3047 
3048                 switch (ipaddr.ipadm_atype) {
3049                 case IPADM_ADDR_STATIC:
3050                         status = i_ipadm_delete_addr(iph, &ipaddr);
3051                         break;
3052                 case IPADM_ADDR_DHCP:
3053                         status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
3054                         break;
3055                 case IPADM_ADDR_IPV6_ADDRCONF:
3056                         status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
3057                         break;
3058                 default:
3059                         /*
3060                          * This is the case of address object name residing in
3061                          * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
3062                          * through and delete that address object.
3063                          */
3064                         break;
3065                 }
3066 
3067                 /* Move the underlying IPMP interface back to the group */
3068                 if (is_ipmp) {
3069                         (void) i_ipadm_set_groupname_active(iph,
3070                             ipaddr.ipadm_ifname, gifname);
3071                 }
3072 
3073                 /*
3074                  * If the address was previously deleted from the active
3075                  * config, we will get a IPADM_ENXIO from kernel.
3076                  * We will still proceed and purge the address information
3077                  * in the DB.
3078                  */
3079                 if (status == IPADM_ENXIO)
3080                         status = IPADM_SUCCESS;
3081                 else if (status != IPADM_SUCCESS)
3082                         return (status);
3083         }
3084 
3085         if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
3086             (flags & IPADM_OPT_PERSIST)) {
3087                 flags &= ~IPADM_OPT_PERSIST;
3088         }
3089         status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
3090         if (status == IPADM_NOTFOUND)
3091                 return (status);
3092         return (IPADM_SUCCESS);


3574         ipadm_status_t  status;
3575         char            lifname[LIFNAMSIZ];
3576 
3577         /* check for solaris.network.interface.config authorization */
3578         if (!ipadm_check_auth())
3579                 return (IPADM_EAUTH);
3580 
3581         /* validate input */
3582         if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3583             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3584                 return (IPADM_INVALID_ARG);
3585         }
3586 
3587         /* Retrieve the address object information. */
3588         status = i_ipadm_get_addrobj(iph, ipaddr);
3589         if (status != IPADM_SUCCESS)
3590                 return (status);
3591 
3592         if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3593                 return (IPADM_OP_DISABLE_OBJ);
3594 
3595         if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3596             !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3597                 return (IPADM_TEMPORARY_OBJ);
3598 
3599         if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3600             (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3601             (ipadm_flags & IPADM_OPT_PERSIST)))
3602                 return (IPADM_NOTSUP);
3603 
3604         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3605 
3606         return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3607 }
3608 
3609 /*
3610  * Marks the address in the address object `aobjname' up. This operation is
3611  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3612  * For an address object of type IPADM_ADDR_DHCP, this operation can
3613  * only be temporary and no updates will be made to the persistent DB.
3614  */
3615 ipadm_status_t
3616 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3617 {
3618         struct ipadm_addrobj_s ipaddr;
3619         ipadm_status_t  status;
3620         uint64_t        flags;
3621         char            lifname[LIFNAMSIZ];
3622 
3623         status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3624             &flags);
3625         if (status != IPADM_SUCCESS)


3812         uint64_t                ifflags = 0;
3813         boolean_t               p_exists;
3814         boolean_t               af_exists, other_af_exists, a_exists;
3815 
3816         if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3817             (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3818                 return (IPADM_INVALID_ARG);
3819         }
3820 
3821         if (ipaddr->ipadm_af == AF_UNSPEC)
3822                 return (IPADM_BAD_ADDR);
3823 
3824         if (!legacy && ipaddr->ipadm_lifnum != 0)
3825                 return (IPADM_INVALID_ARG);
3826 
3827         if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3828                 return (IPADM_NOTSUP);
3829 
3830         ifname = ipaddr->ipadm_ifname;
3831 
3832         /*
3833          * Do not go further when we are under ipmp.
3834          * The interface is plumbed up and we are going to add
3835          * NOFAILOVER address to make in.mpathd happy.
3836          */
3837         if (i_ipadm_is_under_ipmp(iph, ifname))
3838                 return (IPADM_SUCCESS);
3839 
3840         af = ipaddr->ipadm_af;
3841         af_exists = ipadm_if_enabled(iph, ifname, af);
3842         /*
3843          * For legacy case, interfaces are not implicitly plumbed. We need to
3844          * check if the interface exists in the active configuration.
3845          */
3846         if (legacy && !af_exists)
3847                 return (IPADM_ENXIO);
3848 
3849         other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3850         other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3851         /*
3852          * Check if one of the v4 or the v6 interfaces exists in the
3853          * active configuration. An interface is considered disabled only
3854          * if both v4 and v6 are not active.
3855          */
3856         a_exists = (af_exists || other_af_exists);
3857 
3858         /* Check if interface exists in the persistent configuration. */
3859         status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3860         if (status != IPADM_SUCCESS)
3861                 return (status);
3862 
3863         if (!a_exists && p_exists)
3864                 return (IPADM_OP_DISABLE_OBJ);
3865 







3866         if (af_exists) {
3867                 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3868                 if (status != IPADM_SUCCESS)
3869                         return (status);
3870         }
3871 
3872         /* Perform validation steps (4) and (5) */
3873         islo = i_ipadm_is_loopback(ifname);
3874         isvni = i_ipadm_is_vni(ifname);
3875         switch (ipaddr->ipadm_atype) {
3876         case IPADM_ADDR_STATIC:
3877                 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3878                         return (IPADM_INVALID_ARG);
3879                 /* Check for a valid src address */
3880                 if (!legacy && sockaddrunspec(
3881                     (struct sockaddr *)&ipaddr->ipadm_static_addr))
3882                         return (IPADM_BAD_ADDR);
3883                 break;
3884         case IPADM_ADDR_DHCP:
3885                 if (islo || (ifflags & IFF_VRRP))