Print this page
Commit 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 ↓ 12 lines elided ↑ open up ↑
  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   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       23 + * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  23   24   */
  24   25  
  25   26  #include <errno.h>
  26   27  #include <sys/sockio.h>
       28 +#include <sys/list.h>
  27   29  #include <string.h>
  28   30  #include <assert.h>
  29   31  #include <unistd.h>
  30   32  #include <stropts.h>
  31   33  #include <strings.h>
  32   34  #include <libdlpi.h>
  33   35  #include <libdllink.h>
  34   36  #include <libinetutil.h>
  35   37  #include <inet/ip.h>
  36   38  #include <limits.h>
  37   39  #include <zone.h>
  38   40  #include <ipadm_ndpd.h>
       41 +#include <ipmp_query.h>
  39   42  #include "libipadm_impl.h"
  40   43  
  41   44  static ipadm_status_t   i_ipadm_slifname_arp(char *, uint64_t, int);
  42   45  static ipadm_status_t   i_ipadm_slifname(ipadm_handle_t, char *, char *,
  43   46                              uint64_t, int, uint32_t);
  44   47  static ipadm_status_t   i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
  45   48                              sa_family_t);
  46   49  static ipadm_status_t   i_ipadm_persist_if(ipadm_handle_t, const char *,
  47      -                            sa_family_t);
       50 +                            sa_family_t, uint32_t);
       51 +static ipadm_status_t   i_ipadm_allocate_ifinfo(ipadm_if_info_t **);
       52 +static ipadm_status_t   i_ipadm_get_db_if(ipadm_handle_t, const char *,
       53 +                            nvlist_t **);
       54 +static ipadm_status_t i_ipadm_nvl2ifinfo(nvlist_t *, ipadm_if_info_t **);
       55 +static ipadm_status_t i_ipadm_fill_cmembers(char *, ipadm_ipmp_members_t *);
       56 +static ipadm_status_t i_ipadm_fill_pmembers(nvlist_t *, ipadm_ipmp_members_t *);
       57 +static ipadm_status_t i_ipadm_add_persistent_if_info(ipadm_if_info_t *,
       58 +                    ipadm_if_info_t *);
       59 +static void i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *);
       60 +static ipadm_status_t i_ipadm_persist_update_ipmp(ipadm_handle_t, const char *,
       61 +        const char *,
       62 +        ipadm_ipmp_operation_t);
       63 +static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *,
       64 +        const char *, uint32_t,
       65 +        ipadm_ipmp_operation_t);
  48   66  
  49   67  /*
  50   68   * Returns B_FALSE if the interface in `ifname' has at least one address that is
  51   69   * IFF_UP in the addresses in `ifa'.
  52   70   */
  53   71  static boolean_t
  54   72  i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
  55   73  {
  56   74          struct ifaddrs  *ifap;
  57   75          char            cifname[LIFNAMSIZ];
↓ open down ↓ 57 lines elided ↑ open up ↑
 115  133                          continue;
 116  134                  /*
 117  135                   * Check if the interface already exists in our list.
 118  136                   * If it already exists, we need to update its flags.
 119  137                   */
 120  138                  for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
 121  139                          if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
 122  140                                  break;
 123  141                  }
 124  142                  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      -                        }
      143 +                        if ((status =
      144 +                            i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
      145 +                                        break;
      146 +
 130  147                          (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
 131  148                              sizeof (ifp->ifi_name));
 132  149                          /* Update the `ifi_next' pointer for this new node */
 133  150                          if (*if_info == NULL)
 134  151                                  *if_info = ifp;
 135  152                          else
 136  153                                  last->ifi_next = ifp;
 137  154                          last = ifp;
 138  155                  }
 139  156  
 140  157                  /*
 141  158                   * Retrieve the flags for the interface by doing a
 142  159                   * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
 143  160                   */
 144  161                  (void) strlcpy(lifrl.lifr_name,
 145  162                      lifrp->lifr_name, sizeof (lifrl.lifr_name));
 146  163                  s = (lifrp->lifr_addr.ss_family == AF_INET) ?
 147  164                      iph->iph_sock : iph->iph_sock6;
 148  165                  if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
 149  166                          continue;
      167 +
      168 +                /* a regular interface by default */
      169 +                ifp->ifi_class = IPADM_IF_CLASS_REGULAR;
      170 +
 150  171                  if (lifrl.lifr_flags & IFF_BROADCAST)
 151  172                          ifp->ifi_cflags |= IFIF_BROADCAST;
 152  173                  if (lifrl.lifr_flags & IFF_MULTICAST)
 153  174                          ifp->ifi_cflags |= IFIF_MULTICAST;
 154  175                  if (lifrl.lifr_flags & IFF_POINTOPOINT)
 155  176                          ifp->ifi_cflags |= IFIF_POINTOPOINT;
 156      -                if (lifrl.lifr_flags & IFF_VIRTUAL)
      177 +                if (lifrl.lifr_flags & IFF_VIRTUAL) {
 157  178                          ifp->ifi_cflags |= IFIF_VIRTUAL;
 158      -                if (lifrl.lifr_flags & IFF_IPMP)
      179 +                        ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL;
      180 +                }
      181 +                if (lifrl.lifr_flags & IFF_IPMP) {
 159  182                          ifp->ifi_cflags |= IFIF_IPMP;
      183 +                        ifp->ifi_class = IPADM_IF_CLASS_IPMP;
      184 +                }
 160  185                  if (lifrl.lifr_flags & IFF_STANDBY)
 161  186                          ifp->ifi_cflags |= IFIF_STANDBY;
 162  187                  if (lifrl.lifr_flags & IFF_INACTIVE)
 163  188                          ifp->ifi_cflags |= IFIF_INACTIVE;
 164  189                  if (lifrl.lifr_flags & IFF_VRRP)
 165  190                          ifp->ifi_cflags |= IFIF_VRRP;
 166  191                  if (lifrl.lifr_flags & IFF_NOACCEPT)
 167  192                          ifp->ifi_cflags |= IFIF_NOACCEPT;
 168  193                  if (lifrl.lifr_flags & IFF_IPV4)
 169  194                          ifp->ifi_cflags |= IFIF_IPV4;
 170  195                  if (lifrl.lifr_flags & IFF_IPV6)
 171  196                          ifp->ifi_cflags |= IFIF_IPV6;
 172  197                  if (lifrl.lifr_flags & IFF_L3PROTECT)
 173  198                          ifp->ifi_cflags |= IFIF_L3PROTECT;
      199 +
      200 +        /* Retrive active IPMP members */
      201 +        if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) {
      202 +                if (ioctl(s, SIOCGLIFGROUPNAME,
      203 +                    (caddr_t)&lifrl) < 0) {
      204 +                        status = ipadm_errno2status(errno);
      205 +                        break;
      206 +                }
      207 +
      208 +                if ((status = i_ipadm_fill_cmembers(
      209 +                    lifrl.lifr_groupname,
      210 +                    &ifp->ifi_ipmp_cmembers)) != IPADM_SUCCESS)
      211 +                        break;
      212 +                }
 174  213          }
 175  214          free(buf);
 176      -        return (IPADM_SUCCESS);
 177      -fail:
 178      -        free(buf);
 179      -        ipadm_free_if_info(*if_info);
 180      -        *if_info = NULL;
      215 +        if (status != IPADM_SUCCESS) {
      216 +                ipadm_free_if_info(*if_info);
      217 +                *if_info = NULL;
      218 +        }
 181  219          return (status);
 182  220  }
 183  221  
 184  222  /*
 185  223   * Returns the interface information for `ifname' in `if_info' from persistent
 186  224   * config if `ifname' is non-null. Otherwise, it returns all the interfaces
 187  225   * from persistent config in `if_info'.
 188  226   */
 189  227  static ipadm_status_t
 190  228  i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
 191      -    ipadm_if_info_t **if_info)
      229 +        ipadm_if_info_t **if_info)
 192  230  {
 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;
      231 +        ipadm_status_t  status = IPADM_SUCCESS;
      232 +        nvlist_t        *ifs_info_nvl;
 198  233  
 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  234          *if_info = NULL;
 205  235  
 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      -        }
      236 +        if ((status = i_ipadm_get_db_if(iph,
      237 +            ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
      238 +                return (status);
 219  239  
 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);
      240 +        assert(ifs_info_nvl != NULL);
      241 +
      242 +        return (i_ipadm_nvl2ifinfo(ifs_info_nvl, if_info));
      243 +}
      244 +
      245 +static ipadm_status_t
      246 +i_ipadm_nvl2ifinfo(nvlist_t *ifs_info_nvl, ipadm_if_info_t **if_info)
      247 +{
      248 +        ipadm_if_info_t *ific = NULL, *ifil = NULL;
      249 +        nvlist_t        *if_info_nvl;
      250 +        nvpair_t        *nvp;
      251 +        char    *strval;
      252 +        ipadm_status_t  status = IPADM_SUCCESS;
      253 +        uint16_t        *families;
      254 +        uint_t  nelem = 0;
      255 +
      256 +        for (nvp = nvlist_next_nvpair(ifs_info_nvl, NULL); nvp != NULL;
      257 +            nvp = nvlist_next_nvpair(ifs_info_nvl, nvp)) {
      258 +                if (nvpair_value_nvlist(nvp, &if_info_nvl) != 0)
      259 +                        continue;
      260 +
      261 +                status = i_ipadm_allocate_ifinfo(&ific);
      262 +                if (status != IPADM_SUCCESS) {
      263 +                        ipadm_free_if_info(*if_info);
 226  264                          break;
 227  265                  }
 228      -                (void) bcopy(ifp, curr, sizeof (*curr));
 229      -                curr->ifi_next = prev;
 230      -                prev = curr;
      266 +                if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_IFNAME,
      267 +                    &strval) != 0) {
      268 +                        ipadm_free_if_info(ific);
      269 +                        ific = NULL;
      270 +                        continue;
      271 +                }
      272 +                (void) strlcpy(ific->ifi_name, strval,
      273 +                    sizeof (ific->ifi_name));
      274 +
      275 +                if (nvlist_lookup_uint16_array(if_info_nvl,
      276 +                    IPADM_NVP_FAMILIES, &families, &nelem) == 0) {
      277 +
      278 +                        while (nelem--) {
      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 +                } else {
      285 +                        ipadm_free_if_info(ific);
      286 +                        ific = NULL;
      287 +                        continue;
      288 +                }
      289 +                if (nvlist_lookup_string(if_info_nvl,
      290 +                    IPADM_NVP_IFCLASS, &strval) == 0)
      291 +                        ific->ifi_class = atoi(strval);
      292 +                else
      293 +                        ific->ifi_class = IPADM_IF_CLASS_REGULAR;
      294 +
      295 +                if (ific->ifi_class == IPADM_IF_CLASS_IPMP)
      296 +                        i_ipadm_fill_pmembers(if_info_nvl,
      297 +                            &ific->ifi_ipmp_pmembers);
      298 +
      299 +                if (*if_info == NULL)
      300 +                        *if_info = ific;
      301 +                else
      302 +                        ifil->ifi_next = ific;
      303 +                ifil = ific;
 231  304          }
 232      -        *if_info = curr;
 233      -        free(rvalp);
      305 +
      306 +        nvlist_free(ifs_info_nvl);
 234  307          return (status);
 235  308  }
 236  309  
 237  310  /*
      311 + * Fill the ipadm_if_info_t->ifi_ipmp_pmembers by info from
      312 + * ipadm DB
      313 + */
      314 +static ipadm_status_t
      315 +i_ipadm_fill_pmembers(nvlist_t *if_info_nvl, ipadm_ipmp_members_t *pmembers)
      316 +{
      317 +        uint_t  nelem = 0;
      318 +        char    **members;
      319 +        ipadm_ipmp_member_t *ipmp_member;
      320 +
      321 +        if (nvlist_lookup_string_array(if_info_nvl, IPADM_NVP_MIFNAMES,
      322 +            &members, &nelem) != 0)
      323 +                return (IPADM_SUCCESS);
      324 +
      325 +        while (nelem--) {
      326 +                if ((ipmp_member = calloc(1,
      327 +                    sizeof (ipadm_ipmp_member_t))) == NULL)
      328 +                        return (ipadm_errno2status(errno));
      329 +
      330 +                (void) strlcpy(ipmp_member->if_name, members[nelem],
      331 +                    sizeof (ipmp_member->if_name));
      332 +                list_insert_tail(pmembers, ipmp_member);
      333 +        }
      334 +        return (IPADM_SUCCESS);
      335 +}
      336 +
      337 +/*
      338 + * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from
      339 + * kernel (libipmp is used to retrive the required info)
      340 + */
      341 +static ipadm_status_t
      342 +i_ipadm_fill_cmembers(char *gropname, ipadm_ipmp_members_t *cmembers)
      343 +{
      344 +        ipmp_handle_t ipmp_handle;
      345 +        ipmp_groupinfo_t *grinfo;
      346 +        ipmp_iflist_t *iflistp;
      347 +        ipadm_ipmp_member_t *ipmp_member;
      348 +        ipadm_status_t ipadm_status = IPADM_SUCCESS;
      349 +        int ipmp_status;
      350 +        uint_t  i;
      351 +
      352 +        if ((ipmp_status = ipmp_open(&ipmp_handle)) != IPMP_SUCCESS)
      353 +                return (IPADM_FAILURE);
      354 +
      355 +        if ((ipmp_status = ipmp_getgroupinfo(ipmp_handle,
      356 +            gropname,
      357 +            &grinfo)) != IPMP_SUCCESS) {
      358 +                ipadm_status = IPADM_FAILURE;
      359 +                goto fail;
      360 +        }
      361 +
      362 +        iflistp = grinfo->gr_iflistp;
      363 +        for (i = 0; i < iflistp->il_nif; i++) {
      364 +                if ((ipmp_member = calloc(1,
      365 +                    sizeof (ipadm_ipmp_member_t))) == NULL) {
      366 +                        ipadm_status = ipadm_errno2status(errno);
      367 +                        goto fail;
      368 +                }
      369 +
      370 +                (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i],
      371 +                    sizeof (ipmp_member->if_name));
      372 +                list_insert_tail(cmembers, ipmp_member);
      373 +        }
      374 +
      375 +fail:
      376 +        ipmp_freegroupinfo(grinfo);
      377 +        ipmp_close(ipmp_handle);
      378 +        return (ipadm_status);
      379 +}
      380 +
      381 +/*
 238  382   * Collects information for `ifname' if one is specified from both
 239  383   * active and persistent config in `if_info'. If no `ifname' is specified,
 240  384   * this returns all the interfaces in active and persistent config in
 241  385   * `if_info'.
 242  386   */
 243  387  ipadm_status_t
 244  388  i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
 245  389      ipadm_if_info_t **if_info, int64_t lifc_flags)
 246  390  {
 247  391          ipadm_status_t  status;
↓ open down ↓ 69 lines elided ↑ open up ↑
 317  461          /*
 318  462           * If a persistent interface is also found in `aifinfo', update
 319  463           * its entry in `aifinfo' with the persistent information from
 320  464           * `pifinfo'. If an interface is found in `pifinfo', but not in
 321  465           * `aifinfo', it means that this interface was disabled. We should
 322  466           * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
 323  467           */
 324  468          for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
 325  469                  for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
 326  470                          if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
 327      -                                aifp->ifi_pflags = pifp->ifi_pflags;
 328  471                                  break;
 329  472                          }
 330  473                  }
      474 +
 331  475                  if (aifp == NULL) {
 332      -                        aifp = malloc(sizeof (ipadm_if_info_t));
 333      -                        if (aifp == NULL) {
 334      -                                status = ipadm_errno2status(errno);
      476 +                        if ((status =
      477 +                            i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
 335  478                                  goto fail;
 336      -                        }
 337      -                        *aifp = *pifp;
      479 +
      480 +                        (void) strlcpy(aifp->ifi_name, pifp->ifi_name,
      481 +                            sizeof (aifp->ifi_name));
      482 +
 338  483                          aifp->ifi_next = NULL;
 339  484                          aifp->ifi_state = IFIS_DISABLED;
 340  485                          if (last != NULL)
 341  486                                  last->ifi_next = aifp;
 342  487                          else
 343  488                                  aifinfo = aifp;
 344  489                          last = aifp;
 345  490                  }
      491 +
      492 +                if ((status = i_ipadm_add_persistent_if_info(aifp,
      493 +                    pifp)) != IPADM_SUCCESS)
      494 +                        goto fail;
 346  495          }
 347  496          *if_info = aifinfo;
 348  497          ipadm_free_if_info(pifinfo);
 349  498          return (IPADM_SUCCESS);
 350  499  fail:
 351  500          *if_info = NULL;
 352  501          ipadm_free_if_info(aifinfo);
 353  502          ipadm_free_if_info(pifinfo);
 354  503          return (status);
 355  504  }
 356  505  
      506 +/*
      507 + * Updates active if_info by data from persistent if_info
      508 + */
      509 +static ipadm_status_t
      510 +i_ipadm_add_persistent_if_info(ipadm_if_info_t *aifp, ipadm_if_info_t *pifp)
      511 +{
      512 +        ipadm_ipmp_member_t *pp_ipmp_member, *ap_ipmp_member;
      513 +
      514 +        ipadm_ipmp_members_t *apmembers = &aifp->ifi_ipmp_pmembers;
      515 +        ipadm_ipmp_members_t *ppmembers = &pifp->ifi_ipmp_pmembers;
      516 +
      517 +        aifp->ifi_pflags = pifp->ifi_pflags;
      518 +        aifp->ifi_class = pifp->ifi_class;
      519 +
      520 +        for (pp_ipmp_member = list_head(ppmembers); pp_ipmp_member;
      521 +            pp_ipmp_member = list_next(ppmembers, pp_ipmp_member)) {
      522 +                if ((ap_ipmp_member = calloc(1,
      523 +                    sizeof (ipadm_ipmp_member_t))) == NULL)
      524 +                        return (ipadm_errno2status(errno));
      525 +
      526 +                (void) strlcpy(ap_ipmp_member->if_name,
      527 +                    pp_ipmp_member->if_name,
      528 +                    sizeof (ap_ipmp_member->if_name));
      529 +
      530 +                list_insert_tail(apmembers, ap_ipmp_member);
      531 +        }
      532 +        return (IPADM_SUCCESS);
      533 +}
      534 +
      535 +static ipadm_status_t
      536 +i_ipadm_allocate_ifinfo(ipadm_if_info_t **if_info)
      537 +{
      538 +        *if_info = calloc(1, sizeof (ipadm_if_info_t));
      539 +        if (*if_info == NULL)
      540 +                return (ipadm_errno2status(errno));
      541 +
      542 +        /* List of active (current) members */
      543 +        list_create(&((*if_info)->ifi_ipmp_cmembers),
      544 +            sizeof (ipadm_ipmp_member_t),
      545 +            offsetof(ipadm_ipmp_member_t, node));
      546 +
      547 +        /* List of persistent members */
      548 +        list_create(&((*if_info)->ifi_ipmp_pmembers),
      549 +            sizeof (ipadm_ipmp_member_t),
      550 +            offsetof(ipadm_ipmp_member_t, node));
      551 +
      552 +        return (IPADM_SUCCESS);
      553 +}
      554 +
      555 +/*
      556 + * Reads all the interface lines from the persistent DB into the nvlist `onvl',
      557 + * when `ifname' is NULL.
      558 + * If an `ifname' is specified, then the interface line corresponding to
      559 + * that name will be returned.
      560 + */
      561 +static ipadm_status_t
      562 +i_ipadm_get_db_if(ipadm_handle_t iph, const char *ifname, nvlist_t **onvl)
      563 +{
      564 +        ipmgmt_getif_arg_t      garg;
      565 +
      566 +        /* Populate the door_call argument structure */
      567 +        bzero(&garg, sizeof (garg));
      568 +        garg.ia_cmd = IPMGMT_CMD_GETIF;
      569 +        if (ifname != NULL)
      570 +                (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
      571 +
      572 +        return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
      573 +}
      574 +
 357  575  int
 358  576  i_ipadm_get_lnum(const char *ifname)
 359  577  {
 360  578          char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
 361  579  
 362  580          if (num == NULL)
 363  581                  return (0);
 364  582  
 365  583          return (atoi(++num));
 366  584  }
↓ open down ↓ 19 lines elided ↑ open up ↑
 386  604          if (iph->iph_flags & IPH_IPMGMTD) {
 387  605                  *exists = B_FALSE;
 388  606                  return (IPADM_SUCCESS);
 389  607          }
 390  608          status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
 391  609          if (status == IPADM_SUCCESS) {
 392  610                  *exists = ((af == AF_INET &&
 393  611                      (ifinfo->ifi_pflags & IFIF_IPV4)) ||
 394  612                      (af == AF_INET6 &&
 395  613                      (ifinfo->ifi_pflags & IFIF_IPV6)));
 396      -                free(ifinfo);
      614 +                ipadm_free_if_info(ifinfo);
 397  615          } else if (status == IPADM_NOTFOUND) {
 398  616                  status = IPADM_SUCCESS;
 399  617                  *exists = B_FALSE;
 400  618          }
 401  619          return (status);
 402  620  }
 403  621  
 404  622  /*
 405  623   * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
 406  624   * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
↓ open down ↓ 318 lines elided ↑ open up ↑
 725  943                   * By default, kernel configures 127.0.0.1 on the loopback
 726  944                   * interface. Replace this with 0.0.0.0 to be consistent
 727  945                   * with interface creation on other physical interfaces.
 728  946                   */
 729  947                  if (islo && !legacy) {
 730  948                          bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
 731  949                          lifr.lifr_addr.ss_family = af;
 732  950                          if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
 733  951                                  return (ipadm_errno2status(errno));
 734  952                          if (is_persistent) {
 735      -                                status = i_ipadm_persist_if(iph, ifname, af);
      953 +                                status = i_ipadm_persist_if(iph,
      954 +                                    ifname, af, ipadm_flags);
 736  955                                  if (status != IPADM_SUCCESS) {
 737  956                                          (void) i_ipadm_delete_if(iph, ifname,
 738  957                                              af, IPADM_OPT_ACTIVE);
 739  958                                  }
 740  959                          }
 741  960                  }
 742  961                  return (status);
 743  962          }
 744  963  
 745  964          dlpi_flags = DLPI_NOATTACH;
↓ open down ↓ 160 lines elided ↑ open up ↑
 906 1125                           */
 907 1126                          if (af == AF_INET6 && !legacy)
 908 1127                                  (void) i_ipadm_disable_autoconf(newif);
 909 1128                  }
 910 1129  
 911 1130                  /*
 912 1131                   * If IPADM_OPT_PERSIST was set in flags, store the
 913 1132                   * interface in persistent DB.
 914 1133                   */
 915 1134                  if (is_persistent) {
 916      -                        status = i_ipadm_persist_if(iph, newif, af);
     1135 +                        status = i_ipadm_persist_if(iph,
     1136 +                            newif, af, ipadm_flags);
 917 1137                          if (status != IPADM_SUCCESS) {
 918 1138                                  (void) i_ipadm_delete_if(iph, newif, af,
 919 1139                                      IPADM_OPT_ACTIVE);
 920 1140                          }
 921 1141                  }
 922 1142          }
 923 1143          if (status == IPADM_EXISTS)
 924 1144                  status = IPADM_IF_EXISTS;
 925 1145          return (status);
 926 1146  }
↓ open down ↓ 212 lines elided ↑ open up ↑
1139 1359                  (void) i_ipadm_enable_autoconf(ifname);
1140 1360          }
1141 1361          return (ret);
1142 1362  }
1143 1363  
1144 1364  /*
1145 1365   * Saves the given interface name `ifname' with address family `af' in
1146 1366   * persistent DB.
1147 1367   */
1148 1368  static ipadm_status_t
1149      -i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
     1369 +i_ipadm_persist_if(ipadm_handle_t iph,
     1370 +        const char *ifname, sa_family_t af, uint32_t ipadm_flags)
1150 1371  {
1151 1372          ipmgmt_if_arg_t         ifarg;
1152 1373          int                     err;
1153 1374  
1154 1375          (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1155 1376          ifarg.ia_family = af;
     1377 +        if (ipadm_flags & IPADM_OPT_IPMP) {
     1378 +                ifarg.ia_ifclass = IPADM_IF_CLASS_IPMP;
     1379 +        } else {
     1380 +                ifarg.ia_ifclass = IPADM_IF_CLASS_REGULAR;
     1381 +        }
1156 1382          ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1157 1383          ifarg.ia_flags = IPMGMT_PERSIST;
1158 1384          err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1159 1385          return (ipadm_errno2status(err));
1160 1386  }
1161 1387  
1162 1388  /*
1163 1389   * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1164 1390   * is set in `ipadm_flags', it is also removed from persistent configuration.
1165 1391   */
↓ open down ↓ 90 lines elided ↑ open up ↑
1256 1482          boolean_t       p_exists;
1257 1483          sa_family_t     other_af;
1258 1484  
1259 1485          /*
1260 1486           * Return error, if the interface already exists in either the active
1261 1487           * or the persistent configuration.
1262 1488           */
1263 1489          if (ipadm_if_enabled(iph, ifname, af))
1264 1490                  return (IPADM_IF_EXISTS);
1265 1491  
     1492 +#if 0
1266 1493          if (!(iph->iph_flags & IPH_LEGACY)) {
1267 1494                  status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1268 1495                  if (status != IPADM_SUCCESS)
1269 1496                          return (status);
1270 1497                  other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1271 1498                  if (p_exists) {
1272 1499                          if (!ipadm_if_enabled(iph, ifname, other_af))
1273 1500                                  return (IPADM_OP_DISABLE_OBJ);
1274 1501                          else
1275 1502                                  ipadm_flags &= ~IPADM_OPT_PERSIST;
1276 1503                  }
1277 1504          }
1278      -
     1505 +#endif
1279 1506          return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1280 1507  }
1281 1508  
1282 1509  /*
1283 1510   * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1284 1511   * default, unless a value in `af' is specified. The interface may be plumbed
1285 1512   * only if there is no previously saved persistent configuration information
1286 1513   * for the interface (in which case the ipadm_enable_if() function must
1287 1514   * be used to enable the interface).
1288 1515   *
↓ open down ↓ 49 lines elided ↑ open up ↑
1338 1565                                  (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1339 1566                                      IPADM_OPT_ACTIVE);
1340 1567                          }
1341 1568                          return (status);
1342 1569                  }
1343 1570          }
1344 1571  
1345 1572          return (IPADM_SUCCESS);
1346 1573  }
1347 1574  
     1575 +ipadm_status_t
     1576 +ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname,
     1577 +        const char *mifname, uint32_t flags)
     1578 +{
     1579 +        return (i_ipadm_update_ipmp(iph, gifname, mifname,
     1580 +            flags, IPADM_ADD_IPMP_MEMBER));
     1581 +}
     1582 +
     1583 +ipadm_status_t
     1584 +ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname,
     1585 +        const char *mifname, uint32_t flags)
     1586 +{
     1587 +        return (i_ipadm_update_ipmp(iph, gifname, mifname,
     1588 +            flags, IPADM_REMOVE_IPMP_MEMBER));
     1589 +}
     1590 +
1348 1591  /*
     1592 + * Update IPMP configuration according to requested operation,
     1593 + * that can be
     1594 + *
     1595 + * IPADM_ADD_IPMP_MEMBER
     1596 + *
     1597 + * IPADM_REMOVE_IPMP_MEMBER
     1598 + *
     1599 + * At first it update the active config and if IPADM_OPT_PERSIST is set,
     1600 + * then we also update persistent ipadm DB
     1601 + */
     1602 +static ipadm_status_t
     1603 +i_ipadm_update_ipmp(ipadm_handle_t iph,
     1604 +        const char *gifname, const char *mifname,
     1605 +        uint32_t flags, ipadm_ipmp_operation_t operation)
     1606 +{
     1607 +        ipadm_status_t status;
     1608 +        char    group_name1[LIFGRNAMSIZ];
     1609 +        char    group_name2[LIFGRNAMSIZ];
     1610 +
     1611 +        /* Check for the required authorization */
     1612 +        if (!ipadm_check_auth())
     1613 +                return (IPADM_EAUTH);
     1614 +
     1615 +        if (!(flags & IPADM_OPT_ACTIVE) ||
     1616 +            gifname == NULL || mifname == NULL)
     1617 +                return (IPADM_INVALID_ARG);
     1618 +
     1619 +        if (!ipadm_if_enabled(iph, gifname, AF_UNSPEC) ||
     1620 +            !ipadm_if_enabled(iph, mifname, AF_UNSPEC))
     1621 +                return (IPADM_OP_DISABLE_OBJ);
     1622 +
     1623 +#if 1
     1624 +        if (!i_ipadm_is_ipmp(iph, gifname)) {
     1625 +                return (IPADM_INVALID_ARG);
     1626 +        }
     1627 +#endif
     1628 +        if (operation == IPADM_ADD_IPMP_MEMBER &&
     1629 +            i_ipadm_is_under_ipmp(iph, mifname))
     1630 +                return (IPADM_IF_INUSE);
     1631 +
     1632 +        if ((status = i_ipadm_get_groupname_active(iph, gifname,
     1633 +            group_name2, LIFGRNAMSIZ)) != IPADM_SUCCESS)
     1634 +                return (status);
     1635 +
     1636 +        if (operation == IPADM_REMOVE_IPMP_MEMBER) {
     1637 +                if ((status = i_ipadm_get_groupname_active(iph, mifname,
     1638 +                    group_name1, LIFGRNAMSIZ)) != IPADM_SUCCESS)
     1639 +                        return (status);
     1640 +
     1641 +                /* FIXME: Need to return something another */
     1642 +                if (group_name1[0] == '\0')
     1643 +                        return (IPADM_INVALID_ARG);
     1644 +
     1645 +                /* FIXME: Need to return something another */
     1646 +                if (strcmp(group_name1, group_name2) != 0)
     1647 +                        return (IPADM_INVALID_ARG);
     1648 +
     1649 +                group_name2[0] = '\0';
     1650 +        }
     1651 +
     1652 +        if ((status = i_ipadm_set_groupname_active(iph, mifname,
     1653 +            group_name2)) != IPADM_SUCCESS) {
     1654 +                return (status);
     1655 +        }
     1656 +        if (flags & IPADM_OPT_PERSIST) {
     1657 +                if ((status = i_ipadm_persist_update_ipmp(iph, gifname,
     1658 +                    mifname, operation)) != IPADM_SUCCESS) {
     1659 +                        /* Need to revert the active configuration */
     1660 +                        if (operation == IPADM_ADD_IPMP_MEMBER) {
     1661 +                                group_name2[0] = '\0';
     1662 +                                (void) i_ipadm_set_groupname_active(iph,
     1663 +                                    mifname, group_name2);
     1664 +                        }
     1665 +                }
     1666 +        }
     1667 +
     1668 +        return (status);
     1669 +}
     1670 +
     1671 +/*
     1672 + * Call the ipmgmtd to update the IPMP configuration in ipadm DB
     1673 + * after this call the DB will know that mifname is under gifname and
     1674 + * gifname has a member, which name is mifname
     1675 + */
     1676 +static ipadm_status_t
     1677 +i_ipadm_persist_update_ipmp(ipadm_handle_t iph, const char *gifname,
     1678 +        const char *mifname, ipadm_ipmp_operation_t operation)
     1679 +{
     1680 +        ipmgmt_ipmp_update_arg_t args;
     1681 +        int err;
     1682 +
     1683 +        assert(operation == IPADM_ADD_IPMP_MEMBER ||
     1684 +            operation == IPADM_REMOVE_IPMP_MEMBER);
     1685 +
     1686 +        bzero(&args, sizeof (ipmgmt_ipmp_update_arg_t));
     1687 +
     1688 +        args.ia_cmd = IPMGMT_CMD_IPMP_UPDATE;
     1689 +
     1690 +        (void) strlcpy(args.ia_gifname, gifname, sizeof (args.ia_gifname));
     1691 +        (void) strlcpy(args.ia_mifname, mifname, sizeof (args.ia_mifname));
     1692 +
     1693 +        if (operation == IPADM_ADD_IPMP_MEMBER)
     1694 +                args.ia_flags = IPMGMT_APPEND;
     1695 +        else
     1696 +                args.ia_flags = IPMGMT_REMOVE;
     1697 +
     1698 +        args.ia_flags |= IPMGMT_PERSIST;
     1699 +
     1700 +        err = ipadm_door_call(iph, &args, sizeof (args), NULL, 0, B_FALSE);
     1701 +        return (ipadm_errno2status(err));
     1702 +}
     1703 +
     1704 +/*
1349 1705   * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1350 1706   * when `af' = AF_UNSPEC.
1351 1707   */
1352 1708  ipadm_status_t
1353 1709  ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1354 1710      uint32_t flags)
1355 1711  {
1356 1712          ipadm_status_t status1 = IPADM_SUCCESS;
1357 1713          ipadm_status_t status2 = IPADM_SUCCESS;
1358 1714          ipadm_status_t other;
↓ open down ↓ 82 lines elided ↑ open up ↑
1441 1797  /*
1442 1798   * Frees the linked list allocated by ipadm_if_info().
1443 1799   */
1444 1800  void
1445 1801  ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1446 1802  {
1447 1803          ipadm_if_info_t *ifinfo_next;
1448 1804  
1449 1805          for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1450 1806                  ifinfo_next = ifinfo->ifi_next;
     1807 +                i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_cmembers);
     1808 +                i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_pmembers);
1451 1809                  free(ifinfo);
1452 1810          }
1453 1811  }
1454 1812  
     1813 +static void
     1814 +i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *ipmp_members)
     1815 +{
     1816 +        ipadm_ipmp_member_t *ipmp_member;
     1817 +
     1818 +        while ((ipmp_member = list_remove_head(ipmp_members)) != NULL)
     1819 +                free(ipmp_member);
     1820 +
     1821 +        list_destroy(ipmp_members);
     1822 +}
     1823 +
1455 1824  /*
1456 1825   * Re-enable the interface `ifname' based on the saved configuration
1457 1826   * for `ifname'.
1458 1827   */
1459 1828  ipadm_status_t
1460 1829  ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1461 1830  {
1462 1831          nvlist_t        *ifnvl;
1463 1832          ipadm_status_t  status;
1464 1833          ifspec_t        ifsp;
↓ open down ↓ 88 lines elided ↑ open up ↑
1553 1922   *
1554 1923   * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1555 1924   * door_call(3C) fails. Also, there is no use in returning error because
1556 1925   * `ifname' would have been successfuly moved into IPMP group, by this time.
1557 1926   */
1558 1927  void
1559 1928  ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1560 1929  {
1561 1930          (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1562 1931          (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
     1932 +}
     1933 +
     1934 +ipadm_status_t
     1935 +i_ipadm_set_groupname_active(ipadm_handle_t iph, const char *ifname,
     1936 +        const char *groupname)
     1937 +{
     1938 +        struct lifreq   lifr;
     1939 +
     1940 +        memset(&lifr, 0, sizeof (lifr));
     1941 +
     1942 +        (void) strlcpy(lifr.lifr_name, ifname,
     1943 +            sizeof (lifr.lifr_name));
     1944 +
     1945 +        (void) strlcpy(lifr.lifr_groupname, groupname,
     1946 +            sizeof (lifr.lifr_groupname));
     1947 +
     1948 +        if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0 &&
     1949 +            ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) {
     1950 +                return (ipadm_errno2status(errno));
     1951 +        }
     1952 +
     1953 +        return (IPADM_SUCCESS);
     1954 +}
     1955 +
     1956 +ipadm_status_t
     1957 +i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname,
     1958 +        char *groupname, size_t size)
     1959 +{
     1960 +        struct lifreq   lifr;
     1961 +
     1962 +        memset(&lifr, 0, sizeof (lifr));
     1963 +
     1964 +        (void) strlcpy(lifr.lifr_name, ifname,
     1965 +            sizeof (lifr.lifr_name));
     1966 +
     1967 +        if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0 &&
     1968 +            ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0)
     1969 +                return (ipadm_errno2status(errno));
     1970 +
     1971 +        (void) strlcpy(groupname, lifr.lifr_groupname, size);
     1972 +
     1973 +        return (IPADM_SUCCESS);
     1974 +}
     1975 +
     1976 +/*
     1977 + * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
     1978 + */
     1979 +boolean_t
     1980 +i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
     1981 +{
     1982 +
     1983 +        char    groupname[LIFGRNAMSIZ];
     1984 +
     1985 +        if (i_ipadm_get_groupname_active(iph, ifname, groupname,
     1986 +            LIFGRNAMSIZ) != IPADM_SUCCESS ||
     1987 +            groupname[0] == '\0')
     1988 +                return (B_FALSE);
     1989 +
     1990 +        if (strcmp(ifname, groupname) == 0)
     1991 +                return (B_FALSE);
     1992 +
     1993 +        return (B_TRUE);
     1994 +}
     1995 +
     1996 +/*
     1997 + * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
     1998 + */
     1999 +boolean_t
     2000 +i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
     2001 +{
     2002 +        uint64_t flags;
     2003 +
     2004 +        if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
     2005 +            i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
     2006 +                return (B_FALSE);
     2007 +
     2008 +        return ((flags & IFF_IPMP) != 0);
1563 2009  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX