Print this page
NEX-9226 libipadm`ipadm_enable_if() leaks ifnvl
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
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-3676 Assertion failed when creating address object on IPMP group
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-2460 libfksmbd should not link with libsmb (elfcheck)
NEX-2395: i_ipadm_nvl2ifinfo() shall ignore unknown entries in the per-interface NVL
NEX-2395: new libipadm/ipadm/ipmgmtd shall be backward compatible with old ipadm.conf format
OS-161: Integrate IPMP changes

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libipadm/common/ipadm_if.c
          +++ new/usr/src/lib/libipadm/common/ipadm_if.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.
       24 + * Copyright 2016 Nexenta Systems, Inc.
  23   25   */
  24   26  
  25   27  #include <errno.h>
  26   28  #include <sys/sockio.h>
       29 +#include <sys/list.h>
  27   30  #include <string.h>
  28   31  #include <assert.h>
  29   32  #include <unistd.h>
  30   33  #include <stropts.h>
  31   34  #include <strings.h>
  32   35  #include <libdlpi.h>
  33   36  #include <libdllink.h>
  34   37  #include <libinetutil.h>
  35   38  #include <inet/ip.h>
  36   39  #include <limits.h>
  37   40  #include <zone.h>
  38   41  #include <ipadm_ndpd.h>
       42 +#include <ipmp_query.h>
  39   43  #include "libipadm_impl.h"
  40   44  
  41   45  static ipadm_status_t   i_ipadm_slifname_arp(char *, uint64_t, int);
  42   46  static ipadm_status_t   i_ipadm_slifname(ipadm_handle_t, char *, char *,
  43   47                              uint64_t, int, uint32_t);
  44   48  static ipadm_status_t   i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
  45   49                              sa_family_t);
  46   50  static ipadm_status_t   i_ipadm_persist_if(ipadm_handle_t, const char *,
  47      -                            sa_family_t);
       51 +                            sa_family_t, uint32_t);
       52 +static ipadm_status_t   i_ipadm_allocate_ifinfo(ipadm_if_info_t **);
       53 +static ipadm_status_t   i_ipadm_get_db_if(ipadm_handle_t, const char *,
       54 +                            nvlist_t **);
       55 +static ipadm_status_t i_ipadm_nvl2ifinfo(nvlist_t *, ipadm_if_info_t **);
       56 +static ipadm_status_t i_ipadm_fill_cmembers(char *, ipadm_ipmp_members_t *);
       57 +static ipadm_status_t i_ipadm_fill_pmembers(nvlist_t *, ipadm_ipmp_members_t *);
       58 +static ipadm_status_t i_ipadm_add_persistent_if_info(ipadm_if_info_t *,
       59 +                    ipadm_if_info_t *);
       60 +static void i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *);
       61 +static ipadm_status_t i_ipadm_persist_update_ipmp(ipadm_handle_t, const char *,
       62 +        const char *,
       63 +        ipadm_ipmp_op_t);
       64 +static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *,
       65 +        const char *, uint32_t,
       66 +        ipadm_ipmp_op_t);
  48   67  
  49   68  /*
  50   69   * Returns B_FALSE if the interface in `ifname' has at least one address that is
  51   70   * IFF_UP in the addresses in `ifa'.
  52   71   */
  53   72  static boolean_t
  54   73  i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
  55   74  {
  56   75          struct ifaddrs  *ifap;
  57   76          char            cifname[LIFNAMSIZ];
↓ open down ↓ 57 lines elided ↑ open up ↑
 115  134                          continue;
 116  135                  /*
 117  136                   * Check if the interface already exists in our list.
 118  137                   * If it already exists, we need to update its flags.
 119  138                   */
 120  139                  for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
 121  140                          if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
 122  141                                  break;
 123  142                  }
 124  143                  if (ifp == NULL) {
 125      -                        ifp = calloc(1, sizeof (ipadm_if_info_t));
 126      -                        if (ifp == NULL) {
 127      -                                status = ipadm_errno2status(errno);
 128      -                                goto fail;
 129      -                        }
      144 +                        if ((status =
      145 +                            i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
      146 +                                        break;
      147 +
 130  148                          (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
 131  149                              sizeof (ifp->ifi_name));
 132  150                          /* Update the `ifi_next' pointer for this new node */
 133  151                          if (*if_info == NULL)
 134  152                                  *if_info = ifp;
 135  153                          else
 136  154                                  last->ifi_next = ifp;
 137  155                          last = ifp;
 138  156                  }
 139  157  
 140  158                  /*
 141  159                   * Retrieve the flags for the interface by doing a
 142  160                   * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
 143  161                   */
 144  162                  (void) strlcpy(lifrl.lifr_name,
 145  163                      lifrp->lifr_name, sizeof (lifrl.lifr_name));
 146  164                  s = (lifrp->lifr_addr.ss_family == AF_INET) ?
 147  165                      iph->iph_sock : iph->iph_sock6;
 148  166                  if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
 149  167                          continue;
      168 +
      169 +                /* a regular interface by default */
      170 +                ifp->ifi_class = IPADM_IF_CLASS_REGULAR;
      171 +
 150  172                  if (lifrl.lifr_flags & IFF_BROADCAST)
 151  173                          ifp->ifi_cflags |= IFIF_BROADCAST;
 152  174                  if (lifrl.lifr_flags & IFF_MULTICAST)
 153  175                          ifp->ifi_cflags |= IFIF_MULTICAST;
 154  176                  if (lifrl.lifr_flags & IFF_POINTOPOINT)
 155  177                          ifp->ifi_cflags |= IFIF_POINTOPOINT;
 156      -                if (lifrl.lifr_flags & IFF_VIRTUAL)
      178 +                if (lifrl.lifr_flags & IFF_VIRTUAL) {
 157  179                          ifp->ifi_cflags |= IFIF_VIRTUAL;
 158      -                if (lifrl.lifr_flags & IFF_IPMP)
      180 +                        ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL;
      181 +                }
      182 +                if (lifrl.lifr_flags & IFF_IPMP) {
 159  183                          ifp->ifi_cflags |= IFIF_IPMP;
      184 +                        ifp->ifi_class = IPADM_IF_CLASS_IPMP;
      185 +                }
 160  186                  if (lifrl.lifr_flags & IFF_STANDBY)
 161  187                          ifp->ifi_cflags |= IFIF_STANDBY;
 162  188                  if (lifrl.lifr_flags & IFF_INACTIVE)
 163  189                          ifp->ifi_cflags |= IFIF_INACTIVE;
 164  190                  if (lifrl.lifr_flags & IFF_VRRP)
 165  191                          ifp->ifi_cflags |= IFIF_VRRP;
 166  192                  if (lifrl.lifr_flags & IFF_NOACCEPT)
 167  193                          ifp->ifi_cflags |= IFIF_NOACCEPT;
 168  194                  if (lifrl.lifr_flags & IFF_IPV4)
 169  195                          ifp->ifi_cflags |= IFIF_IPV4;
 170  196                  if (lifrl.lifr_flags & IFF_IPV6)
 171  197                          ifp->ifi_cflags |= IFIF_IPV6;
 172  198                  if (lifrl.lifr_flags & IFF_L3PROTECT)
 173  199                          ifp->ifi_cflags |= IFIF_L3PROTECT;
      200 +
      201 +        /* Retrieve active IPMP members */
      202 +        if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) {
      203 +                if (ioctl(s, SIOCGLIFGROUPNAME,
      204 +                    (caddr_t)&lifrl) < 0) {
      205 +                        status = ipadm_errno2status(errno);
      206 +                        break;
      207 +                }
      208 +
      209 +                if ((status = i_ipadm_fill_cmembers(
      210 +                    lifrl.lifr_groupname,
      211 +                    &ifp->ifi_ipmp_cmembers)) != IPADM_SUCCESS)
      212 +                        break;
      213 +                }
 174  214          }
 175  215          free(buf);
 176      -        return (IPADM_SUCCESS);
 177      -fail:
 178      -        free(buf);
 179      -        ipadm_free_if_info(*if_info);
 180      -        *if_info = NULL;
      216 +        if (status != IPADM_SUCCESS) {
      217 +                ipadm_free_if_info(*if_info);
      218 +                *if_info = NULL;
      219 +        }
 181  220          return (status);
 182  221  }
 183  222  
 184  223  /*
 185  224   * Returns the interface information for `ifname' in `if_info' from persistent
 186  225   * config if `ifname' is non-null. Otherwise, it returns all the interfaces
 187  226   * from persistent config in `if_info'.
 188  227   */
 189  228  static ipadm_status_t
 190  229  i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
 191  230      ipadm_if_info_t **if_info)
 192  231  {
 193      -        ipadm_status_t          status = IPADM_SUCCESS;
 194      -        ipmgmt_getif_arg_t      getif;
 195      -        ipmgmt_getif_rval_t     *rvalp;
 196      -        ipadm_if_info_t         *ifp, *curr, *prev = NULL;
 197      -        int                     i = 0, err = 0;
      232 +        ipadm_status_t  status = IPADM_SUCCESS;
      233 +        nvlist_t        *ifs_info_nvl;
 198  234  
 199      -        bzero(&getif, sizeof (getif));
 200      -        if (ifname != NULL)
 201      -                (void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
 202      -        getif.ia_cmd = IPMGMT_CMD_GETIF;
 203      -
 204  235          *if_info = NULL;
 205  236  
 206      -        if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
 207      -                return (ipadm_errno2status(errno));
 208      -        err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp,
 209      -            sizeof (*rvalp), B_TRUE);
 210      -        if (err == ENOENT) {
 211      -                free(rvalp);
 212      -                if (ifname != NULL)
 213      -                        return (ipadm_errno2status(err));
 214      -                return (IPADM_SUCCESS);
 215      -        } else if (err != 0) {
 216      -                free(rvalp);
 217      -                return (ipadm_errno2status(err));
 218      -        }
      237 +        if ((status = i_ipadm_get_db_if(iph,
      238 +            ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
      239 +                return (status);
 219  240  
 220      -        ifp = rvalp->ir_ifinfo;
 221      -        for (i = 0; i < rvalp->ir_ifcnt; i++) {
 222      -                ifp = rvalp->ir_ifinfo + i;
 223      -                if ((curr = malloc(sizeof (*curr))) == NULL) {
 224      -                        status = ipadm_errno2status(errno);
 225      -                        ipadm_free_if_info(prev);
      241 +        assert(ifs_info_nvl != NULL);
      242 +
      243 +        return (i_ipadm_nvl2ifinfo(ifs_info_nvl, if_info));
      244 +}
      245 +
      246 +static ipadm_status_t
      247 +i_ipadm_nvl2ifinfo(nvlist_t *ifs_info_nvl, ipadm_if_info_t **if_info)
      248 +{
      249 +        ipadm_if_info_t *ific = NULL, *ifil = NULL;
      250 +        nvlist_t        *if_info_nvl;
      251 +        nvpair_t        *nvp;
      252 +        char            *strval;
      253 +        ipadm_status_t  status = IPADM_SUCCESS;
      254 +        uint16_t        *families;
      255 +        uint_t          nelem = 0;
      256 +
      257 +        for (nvp = nvlist_next_nvpair(ifs_info_nvl, NULL); nvp != NULL;
      258 +            nvp = nvlist_next_nvpair(ifs_info_nvl, nvp)) {
      259 +                if (nvpair_value_nvlist(nvp, &if_info_nvl) != 0)
      260 +                        continue;
      261 +
      262 +                status = i_ipadm_allocate_ifinfo(&ific);
      263 +                if (status != IPADM_SUCCESS) {
      264 +                        ipadm_free_if_info(*if_info);
 226  265                          break;
 227  266                  }
 228      -                (void) bcopy(ifp, curr, sizeof (*curr));
 229      -                curr->ifi_next = prev;
 230      -                prev = curr;
      267 +                if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_IFNAME,
      268 +                    &strval) != 0) {
      269 +                        ipadm_free_if_info(ific);
      270 +                        ific = NULL;
      271 +                        continue;
      272 +                }
      273 +                (void) strlcpy(ific->ifi_name, strval,
      274 +                    sizeof (ific->ifi_name));
      275 +
      276 +                if (nvlist_lookup_uint16_array(if_info_nvl,
      277 +                    IPADM_NVP_FAMILIES, &families, &nelem) == 0) {
      278 +                        while (nelem-- > 0) {
      279 +                                if (families[nelem] == AF_INET)
      280 +                                        ific->ifi_pflags |= IFIF_IPV4;
      281 +                                else if (families[nelem] == AF_INET6)
      282 +                                        ific->ifi_pflags |= IFIF_IPV6;
      283 +                        }
      284 +                }
      285 +
      286 +                if (nvlist_lookup_string(if_info_nvl,
      287 +                    IPADM_NVP_IFCLASS, &strval) == 0)
      288 +                        ific->ifi_class = atoi(strval);
      289 +                else
      290 +                        ific->ifi_class = IPADM_IF_CLASS_REGULAR;
      291 +
      292 +                if (ific->ifi_class == IPADM_IF_CLASS_IPMP)
      293 +                        /* do not expect any failures there */
      294 +                        (void) i_ipadm_fill_pmembers(if_info_nvl,
      295 +                            &ific->ifi_ipmp_pmembers);
      296 +
      297 +                if (*if_info == NULL)
      298 +                        *if_info = ific;
      299 +                else
      300 +                        ifil->ifi_next = ific;
      301 +                ifil = ific;
 231  302          }
 232      -        *if_info = curr;
 233      -        free(rvalp);
      303 +
      304 +        nvlist_free(ifs_info_nvl);
 234  305          return (status);
 235  306  }
 236  307  
 237  308  /*
      309 + * Fill the ipadm_if_info_t->ifi_ipmp_pmembers by info from
      310 + * ipadm DB
      311 + */
      312 +static ipadm_status_t
      313 +i_ipadm_fill_pmembers(nvlist_t *if_info_nvl, ipadm_ipmp_members_t *pmembers)
      314 +{
      315 +        uint_t  nelem = 0;
      316 +        char    **members;
      317 +        ipadm_ipmp_member_t *ipmp_member;
      318 +
      319 +        if (nvlist_lookup_string_array(if_info_nvl, IPADM_NVP_MIFNAMES,
      320 +            &members, &nelem) != 0)
      321 +                return (IPADM_SUCCESS);
      322 +
      323 +        while (nelem-- > 0) {
      324 +                if ((ipmp_member = calloc(1,
      325 +                    sizeof (ipadm_ipmp_member_t))) == NULL)
      326 +                        return (ipadm_errno2status(errno));
      327 +
      328 +                (void) strlcpy(ipmp_member->if_name, members[nelem],
      329 +                    sizeof (ipmp_member->if_name));
      330 +                list_insert_tail(pmembers, ipmp_member);
      331 +        }
      332 +        return (IPADM_SUCCESS);
      333 +}
      334 +
      335 +/*
      336 + * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from
      337 + * kernel (libipmp is used to retrieve the required info)
      338 + */
      339 +static ipadm_status_t
      340 +i_ipadm_fill_cmembers(char *grname, ipadm_ipmp_members_t *cmembers)
      341 +{
      342 +        ipmp_handle_t ipmp_handle;
      343 +        ipmp_groupinfo_t *grinfo;
      344 +        ipmp_iflist_t *iflistp;
      345 +        ipadm_ipmp_member_t *ipmp_member;
      346 +        ipadm_status_t ipadm_status = IPADM_SUCCESS;
      347 +        int i;
      348 +
      349 +        if (ipmp_open(&ipmp_handle) != IPMP_SUCCESS)
      350 +                return (IPADM_FAILURE);
      351 +
      352 +        if (ipmp_getgroupinfo(ipmp_handle, grname, &grinfo) != IPMP_SUCCESS) {
      353 +                ipadm_status = IPADM_FAILURE;
      354 +                goto fail2;
      355 +        }
      356 +
      357 +        iflistp = grinfo->gr_iflistp;
      358 +        for (i = 0; i < iflistp->il_nif; i++) {
      359 +                if ((ipmp_member = calloc(1,
      360 +                    sizeof (ipadm_ipmp_member_t))) == NULL) {
      361 +                        ipadm_status = ipadm_errno2status(errno);
      362 +                        goto fail1;
      363 +                }
      364 +                (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i],
      365 +                    sizeof (ipmp_member->if_name));
      366 +                list_insert_tail(cmembers, ipmp_member);
      367 +        }
      368 +
      369 +fail1:
      370 +        ipmp_freegroupinfo(grinfo);
      371 +fail2:
      372 +        ipmp_close(ipmp_handle);
      373 +        return (ipadm_status);
      374 +}
      375 +
      376 +/*
 238  377   * Collects information for `ifname' if one is specified from both
 239  378   * active and persistent config in `if_info'. If no `ifname' is specified,
 240  379   * this returns all the interfaces in active and persistent config in
 241  380   * `if_info'.
 242  381   */
 243  382  ipadm_status_t
 244  383  i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
 245  384      ipadm_if_info_t **if_info, int64_t lifc_flags)
 246  385  {
 247  386          ipadm_status_t  status;
↓ open down ↓ 69 lines elided ↑ open up ↑
 317  456          /*
 318  457           * If a persistent interface is also found in `aifinfo', update
 319  458           * its entry in `aifinfo' with the persistent information from
 320  459           * `pifinfo'. If an interface is found in `pifinfo', but not in
 321  460           * `aifinfo', it means that this interface was disabled. We should
 322  461           * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
 323  462           */
 324  463          for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
 325  464                  for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
 326  465                          if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
 327      -                                aifp->ifi_pflags = pifp->ifi_pflags;
 328  466                                  break;
 329  467                          }
 330  468                  }
      469 +
 331  470                  if (aifp == NULL) {
 332      -                        aifp = malloc(sizeof (ipadm_if_info_t));
 333      -                        if (aifp == NULL) {
 334      -                                status = ipadm_errno2status(errno);
      471 +                        if ((status =
      472 +                            i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
 335  473                                  goto fail;
 336      -                        }
 337      -                        *aifp = *pifp;
      474 +
      475 +                        (void) strlcpy(aifp->ifi_name, pifp->ifi_name,
      476 +                            sizeof (aifp->ifi_name));
      477 +
 338  478                          aifp->ifi_next = NULL;
 339  479                          aifp->ifi_state = IFIS_DISABLED;
 340  480                          if (last != NULL)
 341  481                                  last->ifi_next = aifp;
 342  482                          else
 343  483                                  aifinfo = aifp;
 344  484                          last = aifp;
 345  485                  }
      486 +
      487 +                if ((status = i_ipadm_add_persistent_if_info(aifp,
      488 +                    pifp)) != IPADM_SUCCESS)
      489 +                        goto fail;
 346  490          }
 347  491          *if_info = aifinfo;
 348  492          ipadm_free_if_info(pifinfo);
 349  493          return (IPADM_SUCCESS);
 350  494  fail:
 351  495          *if_info = NULL;
 352  496          ipadm_free_if_info(aifinfo);
 353  497          ipadm_free_if_info(pifinfo);
 354  498          return (status);
 355  499  }
 356  500  
      501 +/*
      502 + * Updates active if_info by data from persistent if_info
      503 + */
      504 +static ipadm_status_t
      505 +i_ipadm_add_persistent_if_info(ipadm_if_info_t *aifp, ipadm_if_info_t *pifp)
      506 +{
      507 +        ipadm_ipmp_member_t *pp_ipmp_member, *ap_ipmp_member;
      508 +
      509 +        ipadm_ipmp_members_t *apmembers = &aifp->ifi_ipmp_pmembers;
      510 +        ipadm_ipmp_members_t *ppmembers = &pifp->ifi_ipmp_pmembers;
      511 +
      512 +        aifp->ifi_pflags = pifp->ifi_pflags;
      513 +        aifp->ifi_class = pifp->ifi_class;
      514 +
      515 +        for (pp_ipmp_member = list_head(ppmembers); pp_ipmp_member;
      516 +            pp_ipmp_member = list_next(ppmembers, pp_ipmp_member)) {
      517 +                if ((ap_ipmp_member = calloc(1,
      518 +                    sizeof (ipadm_ipmp_member_t))) == NULL)
      519 +                        return (ipadm_errno2status(errno));
      520 +
      521 +                (void) strlcpy(ap_ipmp_member->if_name,
      522 +                    pp_ipmp_member->if_name,
      523 +                    sizeof (ap_ipmp_member->if_name));
      524 +
      525 +                list_insert_tail(apmembers, ap_ipmp_member);
      526 +        }
      527 +        return (IPADM_SUCCESS);
      528 +}
      529 +
      530 +static ipadm_status_t
      531 +i_ipadm_allocate_ifinfo(ipadm_if_info_t **if_info)
      532 +{
      533 +        *if_info = calloc(1, sizeof (ipadm_if_info_t));
      534 +        if (*if_info == NULL)
      535 +                return (ipadm_errno2status(errno));
      536 +
      537 +        /* List of active (current) members */
      538 +        list_create(&((*if_info)->ifi_ipmp_cmembers),
      539 +            sizeof (ipadm_ipmp_member_t),
      540 +            offsetof(ipadm_ipmp_member_t, node));
      541 +
      542 +        /* List of persistent members */
      543 +        list_create(&((*if_info)->ifi_ipmp_pmembers),
      544 +            sizeof (ipadm_ipmp_member_t),
      545 +            offsetof(ipadm_ipmp_member_t, node));
      546 +
      547 +        return (IPADM_SUCCESS);
      548 +}
      549 +
      550 +/*
      551 + * Reads all the interface lines from the persistent DB into the nvlist `onvl',
      552 + * when `ifname' is NULL.
      553 + * If an `ifname' is specified, then the interface line corresponding to
      554 + * that name will be returned.
      555 + */
      556 +static ipadm_status_t
      557 +i_ipadm_get_db_if(ipadm_handle_t iph, const char *ifname, nvlist_t **onvl)
      558 +{
      559 +        ipmgmt_getif_arg_t      garg;
      560 +
      561 +        /* Populate the door_call argument structure */
      562 +        bzero(&garg, sizeof (garg));
      563 +        garg.ia_cmd = IPMGMT_CMD_GETIF;
      564 +        if (ifname != NULL)
      565 +                (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
      566 +
      567 +        return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
      568 +}
      569 +
 357  570  int
 358  571  i_ipadm_get_lnum(const char *ifname)
 359  572  {
 360  573          char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
 361  574  
 362  575          if (num == NULL)
 363  576                  return (0);
 364  577  
 365  578          return (atoi(++num));
 366  579  }
↓ open down ↓ 19 lines elided ↑ open up ↑
 386  599          if (iph->iph_flags & IPH_IPMGMTD) {
 387  600                  *exists = B_FALSE;
 388  601                  return (IPADM_SUCCESS);
 389  602          }
 390  603          status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
 391  604          if (status == IPADM_SUCCESS) {
 392  605                  *exists = ((af == AF_INET &&
 393  606                      (ifinfo->ifi_pflags & IFIF_IPV4)) ||
 394  607                      (af == AF_INET6 &&
 395  608                      (ifinfo->ifi_pflags & IFIF_IPV6)));
 396      -                free(ifinfo);
      609 +                ipadm_free_if_info(ifinfo);
 397  610          } else if (status == IPADM_NOTFOUND) {
 398  611                  status = IPADM_SUCCESS;
 399  612                  *exists = B_FALSE;
 400  613          }
 401  614          return (status);
 402  615  }
 403  616  
 404  617  /*
 405  618   * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
 406  619   * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
↓ open down ↓ 318 lines elided ↑ open up ↑
 725  938                   * By default, kernel configures 127.0.0.1 on the loopback
 726  939                   * interface. Replace this with 0.0.0.0 to be consistent
 727  940                   * with interface creation on other physical interfaces.
 728  941                   */
 729  942                  if (islo && !legacy) {
 730  943                          bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
 731  944                          lifr.lifr_addr.ss_family = af;
 732  945                          if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
 733  946                                  return (ipadm_errno2status(errno));
 734  947                          if (is_persistent) {
 735      -                                status = i_ipadm_persist_if(iph, ifname, af);
      948 +                                status = i_ipadm_persist_if(iph,
      949 +                                    ifname, af, ipadm_flags);
 736  950                                  if (status != IPADM_SUCCESS) {
 737  951                                          (void) i_ipadm_delete_if(iph, ifname,
 738  952                                              af, IPADM_OPT_ACTIVE);
 739  953                                  }
 740  954                          }
 741  955                  }
 742  956                  return (status);
 743  957          }
 744  958  
 745  959          dlpi_flags = DLPI_NOATTACH;
↓ open down ↓ 160 lines elided ↑ open up ↑
 906 1120                           */
 907 1121                          if (af == AF_INET6 && !legacy)
 908 1122                                  (void) i_ipadm_disable_autoconf(newif);
 909 1123                  }
 910 1124  
 911 1125                  /*
 912 1126                   * If IPADM_OPT_PERSIST was set in flags, store the
 913 1127                   * interface in persistent DB.
 914 1128                   */
 915 1129                  if (is_persistent) {
 916      -                        status = i_ipadm_persist_if(iph, newif, af);
     1130 +                        status = i_ipadm_persist_if(iph,
     1131 +                            newif, af, ipadm_flags);
 917 1132                          if (status != IPADM_SUCCESS) {
 918 1133                                  (void) i_ipadm_delete_if(iph, newif, af,
 919 1134                                      IPADM_OPT_ACTIVE);
 920 1135                          }
 921 1136                  }
 922 1137          }
 923 1138          if (status == IPADM_EXISTS)
 924 1139                  status = IPADM_IF_EXISTS;
 925 1140          return (status);
 926 1141  }
↓ open down ↓ 212 lines elided ↑ open up ↑
1139 1354                  (void) i_ipadm_enable_autoconf(ifname);
1140 1355          }
1141 1356          return (ret);
1142 1357  }
1143 1358  
1144 1359  /*
1145 1360   * Saves the given interface name `ifname' with address family `af' in
1146 1361   * persistent DB.
1147 1362   */
1148 1363  static ipadm_status_t
1149      -i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
     1364 +i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
     1365 +    uint32_t ipadm_flags)
1150 1366  {
1151 1367          ipmgmt_if_arg_t         ifarg;
1152 1368          int                     err;
1153 1369  
1154 1370          (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1155 1371          ifarg.ia_family = af;
     1372 +        if (ipadm_flags & IPADM_OPT_IPMP)
     1373 +                ifarg.ia_ifclass = IPADM_IF_CLASS_IPMP;
     1374 +        else
     1375 +                ifarg.ia_ifclass = IPADM_IF_CLASS_REGULAR;
     1376 +
1156 1377          ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1157 1378          ifarg.ia_flags = IPMGMT_PERSIST;
1158 1379          err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1159 1380          return (ipadm_errno2status(err));
1160 1381  }
1161 1382  
1162 1383  /*
1163 1384   * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1164 1385   * is set in `ipadm_flags', it is also removed from persistent configuration.
1165 1386   */
↓ open down ↓ 172 lines elided ↑ open up ↑
1338 1559                                  (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1339 1560                                      IPADM_OPT_ACTIVE);
1340 1561                          }
1341 1562                          return (status);
1342 1563                  }
1343 1564          }
1344 1565  
1345 1566          return (IPADM_SUCCESS);
1346 1567  }
1347 1568  
     1569 +ipadm_status_t
     1570 +ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname,
     1571 +    const char *mifname, uint32_t ipadm_flags)
     1572 +{
     1573 +        return (i_ipadm_update_ipmp(iph, gifname, mifname,
     1574 +            ipadm_flags, IPADM_ADD_IPMP));
     1575 +}
     1576 +
     1577 +ipadm_status_t
     1578 +ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname,
     1579 +    const char *mifname, uint32_t ipadm_flags)
     1580 +{
     1581 +        return (i_ipadm_update_ipmp(iph, gifname, mifname,
     1582 +            ipadm_flags, IPADM_REMOVE_IPMP));
     1583 +}
     1584 +
1348 1585  /*
     1586 + * Updates active IPMP configuration according to the specified
     1587 + * command. It also persists the configuration if IPADM_OPT_PERSIST
     1588 + * is set in `ipadm_flags'.
     1589 + */
     1590 +static ipadm_status_t
     1591 +i_ipadm_update_ipmp(ipadm_handle_t iph, const char *gifname,
     1592 +    const char *mifname, uint32_t ipadm_flags, ipadm_ipmp_op_t op)
     1593 +{
     1594 +        ipadm_status_t status;
     1595 +        char    groupname1[LIFGRNAMSIZ];
     1596 +        char    groupname2[LIFGRNAMSIZ];
     1597 +
     1598 +        /* Check for the required authorization */
     1599 +        if (!ipadm_check_auth())
     1600 +                return (IPADM_EAUTH);
     1601 +
     1602 +        if (!(ipadm_flags & IPADM_OPT_ACTIVE) ||
     1603 +            gifname == NULL || mifname == NULL)
     1604 +                return (IPADM_INVALID_ARG);
     1605 +
     1606 +        if (!ipadm_if_enabled(iph, gifname, AF_UNSPEC) ||
     1607 +            !ipadm_if_enabled(iph, mifname, AF_UNSPEC))
     1608 +                return (IPADM_OP_DISABLE_OBJ);
     1609 +
     1610 +        if (!i_ipadm_is_ipmp(iph, gifname))
     1611 +                return (IPADM_INVALID_ARG);
     1612 +
     1613 +        if (op == IPADM_ADD_IPMP && i_ipadm_is_under_ipmp(iph, mifname))
     1614 +                return (IPADM_IF_INUSE);
     1615 +
     1616 +        if ((status = i_ipadm_get_groupname_active(iph, gifname,
     1617 +            groupname2, sizeof (groupname2))) != IPADM_SUCCESS)
     1618 +                return (status);
     1619 +
     1620 +        if (op == IPADM_REMOVE_IPMP) {
     1621 +                if ((status = i_ipadm_get_groupname_active(iph, mifname,
     1622 +                    groupname1, sizeof (groupname1))) != IPADM_SUCCESS)
     1623 +                        return (status);
     1624 +
     1625 +                if (groupname1[0] == '\0' ||
     1626 +                    strcmp(groupname1, groupname2) != 0)
     1627 +                        return (IPADM_INVALID_ARG);
     1628 +
     1629 +                groupname2[0] = '\0';
     1630 +        }
     1631 +
     1632 +        if ((ipadm_flags & IPADM_OPT_PERSIST) &&
     1633 +            (status = i_ipadm_persist_update_ipmp(iph, gifname,
     1634 +            mifname, op)) != IPADM_SUCCESS)
     1635 +                return (status);
     1636 +
     1637 +        return (i_ipadm_set_groupname_active(iph, mifname, groupname2));
     1638 +}
     1639 +
     1640 +/*
     1641 + * Call the ipmgmtd to update the IPMP configuration in ipadm DB.
     1642 + * After this call the DB will know that mifname is under gifname and
     1643 + * gifname has a member, which name is mifname.
     1644 + */
     1645 +static ipadm_status_t
     1646 +i_ipadm_persist_update_ipmp(ipadm_handle_t iph, const char *gifname,
     1647 +    const char *mifname, ipadm_ipmp_op_t op)
     1648 +{
     1649 +        ipmgmt_ipmp_update_arg_t args;
     1650 +        int err;
     1651 +
     1652 +        assert(op == IPADM_ADD_IPMP || op == IPADM_REMOVE_IPMP);
     1653 +
     1654 +        bzero(&args, sizeof (ipmgmt_ipmp_update_arg_t));
     1655 +
     1656 +        args.ia_cmd = IPMGMT_CMD_IPMP_UPDATE;
     1657 +
     1658 +        (void) strlcpy(args.ia_gifname, gifname, sizeof (args.ia_gifname));
     1659 +        (void) strlcpy(args.ia_mifname, mifname, sizeof (args.ia_mifname));
     1660 +
     1661 +        if (op == IPADM_ADD_IPMP)
     1662 +                args.ia_flags = IPMGMT_APPEND;
     1663 +        else
     1664 +                args.ia_flags = IPMGMT_REMOVE;
     1665 +
     1666 +        args.ia_flags |= IPMGMT_PERSIST;
     1667 +
     1668 +        err = ipadm_door_call(iph, &args, sizeof (args), NULL, 0, B_FALSE);
     1669 +        return (ipadm_errno2status(err));
     1670 +}
     1671 +
     1672 +/*
1349 1673   * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1350 1674   * when `af' = AF_UNSPEC.
1351 1675   */
1352 1676  ipadm_status_t
1353 1677  ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1354 1678      uint32_t flags)
1355 1679  {
1356 1680          ipadm_status_t status1 = IPADM_SUCCESS;
1357 1681          ipadm_status_t status2 = IPADM_SUCCESS;
1358 1682          ipadm_status_t other;
↓ open down ↓ 82 lines elided ↑ open up ↑
1441 1765  /*
1442 1766   * Frees the linked list allocated by ipadm_if_info().
1443 1767   */
1444 1768  void
1445 1769  ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1446 1770  {
1447 1771          ipadm_if_info_t *ifinfo_next;
1448 1772  
1449 1773          for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1450 1774                  ifinfo_next = ifinfo->ifi_next;
     1775 +                i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_cmembers);
     1776 +                i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_pmembers);
1451 1777                  free(ifinfo);
1452 1778          }
1453 1779  }
1454 1780  
     1781 +static void
     1782 +i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *ipmp_members)
     1783 +{
     1784 +        ipadm_ipmp_member_t *ipmp_member;
     1785 +
     1786 +        while ((ipmp_member = list_remove_head(ipmp_members)) != NULL)
     1787 +                free(ipmp_member);
     1788 +
     1789 +        list_destroy(ipmp_members);
     1790 +}
     1791 +
1455 1792  /*
1456 1793   * Re-enable the interface `ifname' based on the saved configuration
1457 1794   * for `ifname'.
1458 1795   */
1459 1796  ipadm_status_t
1460 1797  ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1461 1798  {
1462 1799          nvlist_t        *ifnvl;
1463 1800          ipadm_status_t  status;
1464 1801          ifspec_t        ifsp;
↓ open down ↓ 7 lines elided ↑ open up ↑
1472 1809                  return (IPADM_INVALID_ARG);
1473 1810  
1474 1811          /* Enabling an interface persistently is not supported. */
1475 1812          if (flags & IPADM_OPT_PERSIST)
1476 1813                  return (IPADM_NOTSUP);
1477 1814  
1478 1815          /*
1479 1816           * Return early by checking if the interface is already enabled.
1480 1817           */
1481 1818          if (ipadm_if_enabled(iph, ifname, AF_INET) &&
1482      -            ipadm_if_enabled(iph, ifname, AF_INET6)) {
     1819 +            ipadm_if_enabled(iph, ifname, AF_INET6))
1483 1820                  return (IPADM_IF_EXISTS);
1484      -        }
     1821 +
1485 1822          /*
1486 1823           * Enable the interface and restore all its interface properties
1487 1824           * and address objects.
1488 1825           */
1489 1826          status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
1490 1827          if (status != IPADM_SUCCESS)
1491 1828                  return (status);
1492 1829  
1493 1830          assert(ifnvl != NULL);
1494 1831          /*
↓ open down ↓ 46 lines elided ↑ open up ↑
1541 1878                          other = status2;
1542 1879                  else
1543 1880                          other = status1;
1544 1881                  return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1545 1882          } else {
1546 1883                  return (IPADM_FAILURE);
1547 1884          }
1548 1885  }
1549 1886  
1550 1887  /*
1551      - * This workaround is until libipadm supports IPMP and is required whenever an
1552      - * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1553      - * yet, we will have to update the daemon's in-memory mapping of
1554      - * `aobjname' to 'lifnum'.
     1888 + * FIXME Remove this when ifconfig(1M) is updated to use IPMP support
     1889 + * in libipadm.
     1890 + */
     1891 +/*
     1892 + * This workaround is required by ifconfig(1M) whenever an
     1893 + * interface is moved into an IPMP group to update the daemon's
     1894 + * in-memory mapping of `aobjname' to 'lifnum'.
1555 1895   *
1556 1896   * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1557 1897   * door_call(3C) fails. Also, there is no use in returning error because
1558 1898   * `ifname' would have been successfuly moved into IPMP group, by this time.
1559 1899   */
1560 1900  void
1561 1901  ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1562 1902  {
1563 1903          (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1564 1904          (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
     1905 +}
     1906 +
     1907 +ipadm_status_t
     1908 +i_ipadm_set_groupname_active(ipadm_handle_t iph, const char *ifname,
     1909 +    const char *groupname)
     1910 +{
     1911 +        struct lifreq   lifr;
     1912 +        ipadm_addr_info_t *addrinfo, *ia;
     1913 +        ipadm_status_t  status = IPADM_SUCCESS;
     1914 +
     1915 +        (void) memset(&lifr, 0, sizeof (lifr));
     1916 +
     1917 +        (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
     1918 +        (void) strlcpy(lifr.lifr_groupname, groupname,
     1919 +            sizeof (lifr.lifr_groupname));
     1920 +
     1921 +        /* Disable all addresses on the interface */
     1922 +        (void) i_ipadm_active_addr_info(iph, ifname, &addrinfo,
     1923 +            IPADM_OPT_ACTIVE, IFF_UP | IFF_DUPLICATE);
     1924 +        for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia))
     1925 +                (void) ipadm_disable_addr(iph, ia->ia_aobjname, 0);
     1926 +
     1927 +        if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1 &&
     1928 +            ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1)
     1929 +                status = ipadm_errno2status(errno);
     1930 +
     1931 +        /* Enable all addresses on the interface */
     1932 +        for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia))
     1933 +                (void) ipadm_enable_addr(iph, ia->ia_aobjname, 0);
     1934 +
     1935 +        if (status == IPADM_SUCCESS) {
     1936 +                if (groupname[0] == '\0') {
     1937 +                        /*
     1938 +                         * If interface was removed from IPMP group, unset the
     1939 +                         * DEPRECATED and NOFAILOVER flags.
     1940 +                         */
     1941 +                        (void) i_ipadm_set_flags(iph, ifname, AF_INET, 0,
     1942 +                            IFF_DEPRECATED | IFF_NOFAILOVER);
     1943 +                        (void) i_ipadm_set_flags(iph, ifname, AF_INET6, 0,
     1944 +                            IFF_DEPRECATED | IFF_NOFAILOVER);
     1945 +                } else if (addrinfo == NULL) {
     1946 +                        /*
     1947 +                         * If interface was added to IPMP group and there are no
     1948 +                         * active addresses, explicitly bring it up to be used
     1949 +                         * for link-based IPMP configuration.
     1950 +                         */
     1951 +                        (void) i_ipadm_set_flags(iph, ifname, AF_INET,
     1952 +                            IFF_UP, 0);
     1953 +                        (void) i_ipadm_set_flags(iph, ifname, AF_INET6,
     1954 +                            IFF_UP, 0);
     1955 +                }
     1956 +        }
     1957 +
     1958 +        ipadm_free_addr_info(addrinfo);
     1959 +
     1960 +        return (status);
     1961 +}
     1962 +
     1963 +ipadm_status_t
     1964 +i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname,
     1965 +    char *groupname, size_t size)
     1966 +{
     1967 +        struct lifreq   lifr;
     1968 +
     1969 +        (void) memset(&lifr, 0, sizeof (lifr));
     1970 +
     1971 +        (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
     1972 +
     1973 +        if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1 &&
     1974 +            ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1)
     1975 +                return (ipadm_errno2status(errno));
     1976 +
     1977 +        (void) strlcpy(groupname, lifr.lifr_groupname, size);
     1978 +
     1979 +        return (IPADM_SUCCESS);
     1980 +}
     1981 +
     1982 +/*
     1983 + * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
     1984 + */
     1985 +boolean_t
     1986 +i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
     1987 +{
     1988 +
     1989 +        char    groupname[LIFGRNAMSIZ];
     1990 +
     1991 +        if (i_ipadm_get_groupname_active(iph, ifname, groupname,
     1992 +            sizeof (groupname)) != IPADM_SUCCESS ||
     1993 +            groupname[0] == '\0' ||
     1994 +            strcmp(ifname, groupname) == 0)
     1995 +                return (B_FALSE);
     1996 +
     1997 +        return (B_TRUE);
     1998 +}
     1999 +
     2000 +/*
     2001 + * Returns B_TRUE if `ifname' represents an IPMP group interface.
     2002 + */
     2003 +boolean_t
     2004 +i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
     2005 +{
     2006 +        uint64_t flags, flags6;
     2007 +
     2008 +        if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
     2009 +            i_ipadm_get_flags(iph, ifname, AF_INET6, &flags6) != IPADM_SUCCESS)
     2010 +                return (B_FALSE);
     2011 +
     2012 +        return ((flags & IFF_IPMP) != 0 || (flags6 & IFF_IPMP) != 0);
1565 2013  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX