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

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libipadm/common/ipadm_addr.c
          +++ new/usr/src/lib/libipadm/common/ipadm_addr.c
↓ open down ↓ 10 lines elided ↑ open up ↑
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
       21 +
  21   22  /*
  22   23   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23   24   * Copyright (c) 2013 by Delphix. All rights reserved.
       25 + * Copyright 2016 Nexenta Systems, Inc.
  24   26   * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  25   27   */
  26   28  
  27   29  /*
  28   30   * This file contains functions for address management such as creating
  29   31   * an address, deleting an address, enabling an address, disabling an
  30   32   * address, bringing an address down or up, setting/getting properties
  31   33   * on an address object and listing address information
  32   34   * for all addresses in active as well as persistent configuration.
  33   35   */
↓ open down ↓ 256 lines elided ↑ open up ↑
 290  292                  if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
 291  293                          af = AF_INET;
 292  294                          break;
 293  295                  } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
 294  296                          af = AF_INET6;
 295  297                          break;
 296  298                  }
 297  299          }
 298  300          assert(af != AF_UNSPEC);
 299  301          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 +            nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0)
 302  303                  goto fail;
 303      -        }
      304 +
      305 +        if (ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS)
      306 +                goto fail;
      307 +
 304  308          nvlist_free(onvl);
 305  309          return (IPADM_SUCCESS);
 306  310  fail:
 307  311          nvlist_free(onvl);
 308  312          return (IPADM_NOTFOUND);
 309  313  }
 310  314  
 311  315  /*
 312  316   * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
 313  317   * fills in the address objname, the address type and the ipadm_flags.
↓ open down ↓ 62 lines elided ↑ open up ↑
 376  380          i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
 377  381          aobj.ipadm_af = af;
 378  382          aobj.ipadm_lifnum = lnum;
 379  383          return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
 380  384  }
 381  385  
 382  386  /*
 383  387   * Gets all the addresses from active configuration and populates the
 384  388   * address information in `addrinfo'.
 385  389   */
 386      -static ipadm_status_t
      390 +ipadm_status_t
 387  391  i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
 388  392      ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
 389  393  {
 390  394          ipadm_status_t          status;
 391  395          struct ifaddrs          *ifap, *ifa;
 392  396          ipadm_addr_info_t       *curr, *prev = NULL;
 393  397          struct ifaddrs          *cifaddr;
 394  398          struct lifreq           lifr;
 395  399          int                     sock;
 396  400          uint64_t                flags;
↓ open down ↓ 1309 lines elided ↑ open up ↑
1706 1710          if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1707 1711                  return (status);
1708 1712  
1709 1713          if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1710 1714                  return (IPADM_OP_DISABLE_OBJ);
1711 1715  
1712 1716          /* Persistent operation not allowed on a temporary object. */
1713 1717          if ((pflags & IPADM_OPT_PERSIST) &&
1714 1718              !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1715 1719                  return (IPADM_TEMPORARY_OBJ);
1716      -
1717 1720          /*
1718 1721           * Currently, setting an address property on an address object of type
1719 1722           * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1720 1723           * in.ndpd retrieving the address properties from ipmgmtd for given
1721 1724           * address object and then setting them on auto-configured addresses,
1722 1725           * whenever in.ndpd gets a new prefix. This will be supported in
1723 1726           * future releases.
1724 1727           */
1725 1728          if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1726 1729                  return (IPADM_NOTSUP);
↓ open down ↓ 675 lines elided ↑ open up ↑
2402 2405  
2403 2406          if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2404 2407                  return (IPADM_INVALID_ARG);
2405 2408  
2406 2409          if ((aname = strchr(ifname, '/')) != NULL)
2407 2410                  *aname++ = '\0';
2408 2411  
2409 2412          /* Check if the interface name is valid. */
2410 2413          if (!ifparse_ifspec(ifname, &ifsp))
2411 2414                  return (IPADM_INVALID_ARG);
2412      -
2413 2415          /* Check if the given addrobj name is valid. */
2414 2416          if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2415 2417                  return (IPADM_INVALID_ARG);
2416      -
2417 2418          if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2418 2419                  return (IPADM_NO_MEMORY);
2419 2420  
2420 2421          /*
2421 2422           * If the ifname has logical interface number, extract it and assign
2422 2423           * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2423 2424           * this today. We will check for the validity later in
2424 2425           * i_ipadm_validate_create_addr().
2425 2426           */
2426 2427          if (ifsp.ifsp_lunvalid) {
↓ open down ↓ 161 lines elided ↑ open up ↑
2588 2589   * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2589 2590   * it returns all the addresses for the given interface `ifname'.
2590 2591   * If an `aobjname' is specified, then the address line corresponding to
2591 2592   * that name will be returned.
2592 2593   */
2593 2594  static ipadm_status_t
2594 2595  i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2595 2596      const char *aobjname, nvlist_t **onvl)
2596 2597  {
2597 2598          ipmgmt_getaddr_arg_t    garg;
2598      -        ipmgmt_get_rval_t       *rvalp;
2599      -        int                     err;
2600      -        size_t                  nvlsize;
2601      -        char                    *nvlbuf;
2602 2599  
2603 2600          /* Populate the door_call argument structure */
2604 2601          bzero(&garg, sizeof (garg));
2605 2602          garg.ia_cmd = IPMGMT_CMD_GETADDR;
2606 2603          if (aobjname != NULL)
2607 2604                  (void) strlcpy(garg.ia_aobjname, aobjname,
2608 2605                      sizeof (garg.ia_aobjname));
2609 2606          if (ifname != NULL)
2610 2607                  (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2611 2608  
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));
     2609 +        return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
2622 2610  }
2623 2611  
2624 2612  /*
2625 2613   * Adds the IP address contained in the 'ipaddr' argument to the physical
2626 2614   * interface represented by 'ifname' after doing the required validation.
2627 2615   * If the interface does not exist, it is created before the address is
2628 2616   * added.
2629 2617   *
2630 2618   * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2631 2619   * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
↓ open down ↓ 15 lines elided ↑ open up ↑
2647 2635          boolean_t               created_af = B_FALSE;
2648 2636          boolean_t               created_other_af = B_FALSE;
2649 2637          ipadm_addr_type_t       type;
2650 2638          char                    *ifname = addr->ipadm_ifname;
2651 2639          boolean_t               legacy = (iph->iph_flags & IPH_LEGACY);
2652 2640          boolean_t               aobjfound;
2653 2641          boolean_t               is_6to4;
2654 2642          struct lifreq           lifr;
2655 2643          uint64_t                ifflags;
2656 2644          boolean_t               is_boot = (iph->iph_flags & IPH_IPMGMTD);
     2645 +        boolean_t               is_ipmp;
     2646 +        char                    gifname[LIFGRNAMSIZ];
2657 2647  
2658 2648          /* check for solaris.network.interface.config authorization */
2659 2649          if (!ipadm_check_auth())
2660 2650                  return (IPADM_EAUTH);
2661 2651  
2662 2652          /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2663 2653          status = i_ipadm_validate_create_addr(iph, addr, flags);
2664 2654          if (status != IPADM_SUCCESS)
2665 2655                  return (status);
2666      -
2667 2656          /*
2668 2657           * For Legacy case, check if an addrobj already exists for the
2669 2658           * given logical interface name. If one does not exist,
2670 2659           * a default name will be generated and added to the daemon's
2671 2660           * aobjmap.
2672 2661           */
2673 2662          if (legacy) {
2674 2663                  struct ipadm_addrobj_s  ipaddr;
2675 2664  
2676 2665                  ipaddr = *addr;
↓ open down ↓ 114 lines elided ↑ open up ↑
2791 2780                  (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2792 2781                      sizeof (lifr.lifr_name));
2793 2782                  if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2794 2783                          status = ipadm_errno2status(errno);
2795 2784                          goto fail;
2796 2785                  }
2797 2786                  if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2798 2787                          return (IPADM_SUCCESS);
2799 2788          }
2800 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 2801          /* Create the address. */
2802 2802          type = addr->ipadm_atype;
2803 2803          switch (type) {
2804 2804          case IPADM_ADDR_STATIC:
2805 2805                  status = i_ipadm_create_addr(iph, addr, flags);
2806 2806                  break;
2807 2807          case IPADM_ADDR_DHCP:
2808 2808                  status = i_ipadm_create_dhcp(iph, addr, flags);
2809 2809                  break;
2810 2810          case IPADM_ADDR_IPV6_ADDRCONF:
2811 2811                  status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2812 2812                  break;
2813 2813          default:
2814 2814                  status = IPADM_INVALID_ARG;
2815 2815                  break;
2816 2816          }
2817 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 +
2818 2824          /*
2819 2825           * If address was not created successfully, unplumb the interface
2820 2826           * if it was plumbed implicitly in this function and remove the
2821 2827           * addrobj created by the ipmgmtd daemon as a placeholder.
2822 2828           * If IPH_LEGACY is set, then remove the addrobj only if it was
2823 2829           * created in this function.
2824 2830           */
2825 2831  fail:
2826 2832          if (status != IPADM_DHCP_IPC_TIMEOUT &&
2827 2833              status != IPADM_SUCCESS) {
↓ open down ↓ 52 lines elided ↑ open up ↑
2880 2886                          return (status);
2881 2887                  default_prefixlen = B_TRUE;
2882 2888          }
2883 2889          (void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2884 2890              (struct sockaddr *)mask);
2885 2891  
2886 2892          /*
2887 2893           * Create a new logical interface if needed; otherwise, just
2888 2894           * use the 0th logical interface.
2889 2895           */
2890      -retry:
2891 2896          if (!(iph->iph_flags & IPH_LEGACY)) {
2892 2897                  status = i_ipadm_do_addif(iph, ipaddr);
2893 2898                  if (status != IPADM_SUCCESS)
2894 2899                          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 2900          }
2910 2901          i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2911 2902              sizeof (lifr.lifr_name));
2912 2903          lifr.lifr_addr = *mask;
2913 2904          if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2914 2905                  status = ipadm_errno2status(errno);
2915 2906                  goto ret;
2916 2907          }
2917 2908          lifr.lifr_addr = *addr;
2918 2909          if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
↓ open down ↓ 3 lines elided ↑ open up ↑
2922 2913          /* Set the destination address, if one is given. */
2923 2914          if (daddr->ss_family != AF_UNSPEC) {
2924 2915                  lifr.lifr_addr = *daddr;
2925 2916                  if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2926 2917                          status = ipadm_errno2status(errno);
2927 2918                          goto ret;
2928 2919                  }
2929 2920          }
2930 2921  
2931 2922          if (flags & IPADM_OPT_UP) {
2932      -                status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
     2923 +                uint32_t        iff_flags = IFF_UP;
2933 2924  
2934 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 +                /*
2935 2936                   * IPADM_DAD_FOUND is a soft-error for create-addr.
2936 2937                   * No need to tear down the address.
2937 2938                   */
2938 2939                  if (status == IPADM_DAD_FOUND)
2939 2940                          status = IPADM_SUCCESS;
2940 2941          }
2941 2942  
2942 2943          if (status == IPADM_SUCCESS && !is_boot) {
2943 2944                  /*
2944 2945                   * For IPH_LEGACY, we might be modifying the address on
↓ open down ↓ 12 lines elided ↑ open up ↑
2957 2958                              legacy_addr.ipadm_lifnum >= 0) {
2958 2959                                  return (status);
2959 2960                          }
2960 2961                  }
2961 2962                  status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2962 2963                      flags, NULL);
2963 2964          }
2964 2965  ret:
2965 2966          if (status != IPADM_SUCCESS && !legacy)
2966 2967                  (void) i_ipadm_delete_addr(iph, ipaddr);
     2968 +
2967 2969          return (status);
2968 2970  }
2969 2971  
2970 2972  /*
2971 2973   * Removes the address object identified by `aobjname' from both active and
2972 2974   * persistent configuration. The address object will be removed from only
2973 2975   * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2974 2976   *
2975 2977   * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2976 2978   * in the address object will be removed from the physical interface.
↓ open down ↓ 44 lines elided ↑ open up ↑
3021 3023          if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
3022 3024              (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
3023 3025                  return (IPADM_NOTFOUND);
3024 3026          }
3025 3027  
3026 3028          /*
3027 3029           * If address is present in active config, remove it from
3028 3030           * kernel.
3029 3031           */
3030 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 +
3031 3048                  switch (ipaddr.ipadm_atype) {
3032 3049                  case IPADM_ADDR_STATIC:
3033 3050                          status = i_ipadm_delete_addr(iph, &ipaddr);
3034 3051                          break;
3035 3052                  case IPADM_ADDR_DHCP:
3036 3053                          status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
3037 3054                          break;
3038 3055                  case IPADM_ADDR_IPV6_ADDRCONF:
3039 3056                          status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
3040 3057                          break;
3041 3058                  default:
3042 3059                          /*
3043 3060                           * This is the case of address object name residing in
3044 3061                           * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
3045 3062                           * through and delete that address object.
3046 3063                           */
3047 3064                          break;
3048 3065                  }
3049 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 +
3050 3073                  /*
3051 3074                   * If the address was previously deleted from the active
3052 3075                   * config, we will get a IPADM_ENXIO from kernel.
3053 3076                   * We will still proceed and purge the address information
3054 3077                   * in the DB.
3055 3078                   */
3056 3079                  if (status == IPADM_ENXIO)
3057 3080                          status = IPADM_SUCCESS;
3058 3081                  else if (status != IPADM_SUCCESS)
3059 3082                          return (status);
↓ open down ↓ 501 lines elided ↑ open up ↑
3561 3584                  return (IPADM_INVALID_ARG);
3562 3585          }
3563 3586  
3564 3587          /* Retrieve the address object information. */
3565 3588          status = i_ipadm_get_addrobj(iph, ipaddr);
3566 3589          if (status != IPADM_SUCCESS)
3567 3590                  return (status);
3568 3591  
3569 3592          if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3570 3593                  return (IPADM_OP_DISABLE_OBJ);
     3594 +
3571 3595          if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3572 3596              !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3573 3597                  return (IPADM_TEMPORARY_OBJ);
     3598 +
3574 3599          if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3575 3600              (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3576 3601              (ipadm_flags & IPADM_OPT_PERSIST)))
3577 3602                  return (IPADM_NOTSUP);
3578 3603  
3579 3604          i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
     3605 +
3580 3606          return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3581 3607  }
3582 3608  
3583 3609  /*
3584 3610   * Marks the address in the address object `aobjname' up. This operation is
3585 3611   * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3586 3612   * For an address object of type IPADM_ADDR_DHCP, this operation can
3587 3613   * only be temporary and no updates will be made to the persistent DB.
3588 3614   */
3589 3615  ipadm_status_t
↓ open down ↓ 206 lines elided ↑ open up ↑
3796 3822                  return (IPADM_BAD_ADDR);
3797 3823  
3798 3824          if (!legacy && ipaddr->ipadm_lifnum != 0)
3799 3825                  return (IPADM_INVALID_ARG);
3800 3826  
3801 3827          if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3802 3828                  return (IPADM_NOTSUP);
3803 3829  
3804 3830          ifname = ipaddr->ipadm_ifname;
3805 3831  
3806      -        if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
3807      -                return (IPADM_NOTSUP);
     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);
3808 3839  
3809 3840          af = ipaddr->ipadm_af;
3810 3841          af_exists = ipadm_if_enabled(iph, ifname, af);
3811 3842          /*
3812 3843           * For legacy case, interfaces are not implicitly plumbed. We need to
3813 3844           * check if the interface exists in the active configuration.
3814 3845           */
3815 3846          if (legacy && !af_exists)
3816 3847                  return (IPADM_ENXIO);
3817 3848  
↓ open down ↓ 3 lines elided ↑ open up ↑
3821 3852           * Check if one of the v4 or the v6 interfaces exists in the
3822 3853           * active configuration. An interface is considered disabled only
3823 3854           * if both v4 and v6 are not active.
3824 3855           */
3825 3856          a_exists = (af_exists || other_af_exists);
3826 3857  
3827 3858          /* Check if interface exists in the persistent configuration. */
3828 3859          status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3829 3860          if (status != IPADM_SUCCESS)
3830 3861                  return (status);
     3862 +
3831 3863          if (!a_exists && p_exists)
3832 3864                  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      -        }
     3865 +
3841 3866          if (af_exists) {
3842 3867                  status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3843 3868                  if (status != IPADM_SUCCESS)
3844 3869                          return (status);
3845 3870          }
3846 3871  
3847 3872          /* Perform validation steps (4) and (5) */
3848 3873          islo = i_ipadm_is_loopback(ifname);
3849 3874          isvni = i_ipadm_is_vni(ifname);
3850 3875          switch (ipaddr->ipadm_atype) {
↓ open down ↓ 144 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX