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
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */

  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.

  23  */
  24 
  25 #include <errno.h>
  26 #include <sys/sockio.h>

  27 #include <string.h>
  28 #include <assert.h>
  29 #include <unistd.h>
  30 #include <stropts.h>
  31 #include <strings.h>
  32 #include <libdlpi.h>
  33 #include <libdllink.h>
  34 #include <libinetutil.h>
  35 #include <inet/ip.h>
  36 #include <limits.h>
  37 #include <zone.h>
  38 #include <ipadm_ndpd.h>

  39 #include "libipadm_impl.h"
  40 
  41 static ipadm_status_t   i_ipadm_slifname_arp(char *, uint64_t, int);
  42 static ipadm_status_t   i_ipadm_slifname(ipadm_handle_t, char *, char *,
  43                             uint64_t, int, uint32_t);
  44 static ipadm_status_t   i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
  45                             sa_family_t);
  46 static ipadm_status_t   i_ipadm_persist_if(ipadm_handle_t, const char *,
  47                             sa_family_t);















  48 
  49 /*
  50  * Returns B_FALSE if the interface in `ifname' has at least one address that is
  51  * IFF_UP in the addresses in `ifa'.
  52  */
  53 static boolean_t
  54 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
  55 {
  56         struct ifaddrs  *ifap;
  57         char            cifname[LIFNAMSIZ];
  58         char            *sep;
  59 
  60         for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
  61                 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
  62                 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
  63                         *sep = '\0';
  64                 /*
  65                  * If this condition is true, there is at least one
  66                  * address that is IFF_UP. So, we need to return B_FALSE.
  67                  */


 105         for (n = 0; n < numifs; n++, lifrp++) {
 106                 /* Skip interfaces with logical num != 0 */
 107                 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
 108                         continue;
 109                 /*
 110                  * Skip the current interface if a specific `ifname' has
 111                  * been requested and current interface does not match
 112                  * `ifname'.
 113                  */
 114                 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
 115                         continue;
 116                 /*
 117                  * Check if the interface already exists in our list.
 118                  * If it already exists, we need to update its flags.
 119                  */
 120                 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
 121                         if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
 122                                 break;
 123                 }
 124                 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                         }
 130                         (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
 131                             sizeof (ifp->ifi_name));
 132                         /* Update the `ifi_next' pointer for this new node */
 133                         if (*if_info == NULL)
 134                                 *if_info = ifp;
 135                         else
 136                                 last->ifi_next = ifp;
 137                         last = ifp;
 138                 }
 139 
 140                 /*
 141                  * Retrieve the flags for the interface by doing a
 142                  * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
 143                  */
 144                 (void) strlcpy(lifrl.lifr_name,
 145                     lifrp->lifr_name, sizeof (lifrl.lifr_name));
 146                 s = (lifrp->lifr_addr.ss_family == AF_INET) ?
 147                     iph->iph_sock : iph->iph_sock6;
 148                 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
 149                         continue;




 150                 if (lifrl.lifr_flags & IFF_BROADCAST)
 151                         ifp->ifi_cflags |= IFIF_BROADCAST;
 152                 if (lifrl.lifr_flags & IFF_MULTICAST)
 153                         ifp->ifi_cflags |= IFIF_MULTICAST;
 154                 if (lifrl.lifr_flags & IFF_POINTOPOINT)
 155                         ifp->ifi_cflags |= IFIF_POINTOPOINT;
 156                 if (lifrl.lifr_flags & IFF_VIRTUAL)
 157                         ifp->ifi_cflags |= IFIF_VIRTUAL;
 158                 if (lifrl.lifr_flags & IFF_IPMP)


 159                         ifp->ifi_cflags |= IFIF_IPMP;


 160                 if (lifrl.lifr_flags & IFF_STANDBY)
 161                         ifp->ifi_cflags |= IFIF_STANDBY;
 162                 if (lifrl.lifr_flags & IFF_INACTIVE)
 163                         ifp->ifi_cflags |= IFIF_INACTIVE;
 164                 if (lifrl.lifr_flags & IFF_VRRP)
 165                         ifp->ifi_cflags |= IFIF_VRRP;
 166                 if (lifrl.lifr_flags & IFF_NOACCEPT)
 167                         ifp->ifi_cflags |= IFIF_NOACCEPT;
 168                 if (lifrl.lifr_flags & IFF_IPV4)
 169                         ifp->ifi_cflags |= IFIF_IPV4;
 170                 if (lifrl.lifr_flags & IFF_IPV6)
 171                         ifp->ifi_cflags |= IFIF_IPV6;
 172                 if (lifrl.lifr_flags & IFF_L3PROTECT)
 173                         ifp->ifi_cflags |= IFIF_L3PROTECT;







 174         }







 175         free(buf);
 176         return (IPADM_SUCCESS);
 177 fail:
 178         free(buf);
 179         ipadm_free_if_info(*if_info);
 180         *if_info = NULL;

 181         return (status);
 182 }
 183 
 184 /*
 185  * Returns the interface information for `ifname' in `if_info' from persistent
 186  * config if `ifname' is non-null. Otherwise, it returns all the interfaces
 187  * from persistent config in `if_info'.
 188  */
 189 static ipadm_status_t
 190 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
 191     ipadm_if_info_t **if_info)
 192 {
 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;
 198 
 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         *if_info = NULL;
 205 
 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         }
 219 
 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);
 226                         break;
 227                 }
 228                 (void) bcopy(ifp, curr, sizeof (*curr));
 229                 curr->ifi_next = prev;
 230                 prev = curr;
 231         }
 232         *if_info = curr;
 233         free(rvalp);
 234         return (status);



 235 }
 236 
 237 /*
 238  * Collects information for `ifname' if one is specified from both
 239  * active and persistent config in `if_info'. If no `ifname' is specified,
 240  * this returns all the interfaces in active and persistent config in
 241  * `if_info'.
 242  */
 243 ipadm_status_t
 244 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
 245     ipadm_if_info_t **if_info, int64_t lifc_flags)
 246 {
 247         ipadm_status_t  status;
 248         ipadm_if_info_t *aifinfo = NULL;
 249         ipadm_if_info_t *pifinfo = NULL;
 250         ipadm_if_info_t *aifp;
 251         ipadm_if_info_t *pifp;
 252         ipadm_if_info_t *last = NULL;
 253         struct ifaddrs  *ifa;
 254         struct ifaddrs  *ifap;


 307         /*
 308          * Get the persistent interface information in `pifinfo'.
 309          */
 310         status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
 311         if (status == IPADM_NOTFOUND) {
 312                 *if_info = aifinfo;
 313                 return (IPADM_SUCCESS);
 314         }
 315         if (status != IPADM_SUCCESS)
 316                 goto fail;
 317         /*
 318          * If a persistent interface is also found in `aifinfo', update
 319          * its entry in `aifinfo' with the persistent information from
 320          * `pifinfo'. If an interface is found in `pifinfo', but not in
 321          * `aifinfo', it means that this interface was disabled. We should
 322          * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
 323          */
 324         for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
 325                 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
 326                         if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
 327                                 aifp->ifi_pflags = pifp->ifi_pflags;
 328                                 break;
 329                         }
 330                 }

 331                 if (aifp == NULL) {
 332                         aifp = malloc(sizeof (ipadm_if_info_t));
 333                         if (aifp == NULL) {
 334                                 status = ipadm_errno2status(errno);
 335                                 goto fail;
 336                         }
 337                         *aifp = *pifp;


 338                         aifp->ifi_next = NULL;
 339                         aifp->ifi_state = IFIS_DISABLED;
 340                         if (last != NULL)
 341                                 last->ifi_next = aifp;
 342                         else
 343                                 aifinfo = aifp;
 344                         last = aifp;
 345                 }




 346         }
 347         *if_info = aifinfo;
 348         ipadm_free_if_info(pifinfo);
 349         return (IPADM_SUCCESS);
 350 fail:
 351         *if_info = NULL;
 352         ipadm_free_if_info(aifinfo);
 353         ipadm_free_if_info(pifinfo);
 354         return (status);
 355 }
 356 





































































 357 int
 358 i_ipadm_get_lnum(const char *ifname)
 359 {
 360         char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
 361 
 362         if (num == NULL)
 363                 return (0);
 364 
 365         return (atoi(++num));
 366 }
 367 
 368 /*
 369  * Sets the output argument `exists' to true or false based on whether
 370  * any persistent configuration is available for `ifname' and returns
 371  * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
 372  * `exists' is unmodified and an error status is returned.
 373  */
 374 ipadm_status_t
 375 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 376     boolean_t *exists)
 377 {
 378         ipadm_if_info_t *ifinfo;
 379         ipadm_status_t  status;
 380 
 381         /*
 382          * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
 383          * knows about persistent configuration in the first place, so we
 384          * just return success.
 385          */
 386         if (iph->iph_flags & IPH_IPMGMTD) {
 387                 *exists = B_FALSE;
 388                 return (IPADM_SUCCESS);
 389         }
 390         status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
 391         if (status == IPADM_SUCCESS) {
 392                 *exists = ((af == AF_INET &&
 393                     (ifinfo->ifi_pflags & IFIF_IPV4)) ||
 394                     (af == AF_INET6 &&
 395                     (ifinfo->ifi_pflags & IFIF_IPV6)));
 396                 free(ifinfo);
 397         } else if (status == IPADM_NOTFOUND) {
 398                 status = IPADM_SUCCESS;
 399                 *exists = B_FALSE;
 400         }
 401         return (status);
 402 }
 403 
 404 /*
 405  * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
 406  * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
 407  * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
 408  * the bottom of the stream for tunneling interfaces.
 409  */
 410 ipadm_status_t
 411 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
 412 {
 413         int err;
 414 
 415         if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
 416                 return (ipadm_errno2status(errno));


 715                 if (af == AF_INET)
 716                         sock = iph->iph_sock;
 717                 else
 718                         sock = iph->iph_sock6;
 719                 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
 720                         return (IPADM_IF_EXISTS);
 721                 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
 722                         return (ipadm_errno2status(errno));
 723 
 724                 /*
 725                  * By default, kernel configures 127.0.0.1 on the loopback
 726                  * interface. Replace this with 0.0.0.0 to be consistent
 727                  * with interface creation on other physical interfaces.
 728                  */
 729                 if (islo && !legacy) {
 730                         bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
 731                         lifr.lifr_addr.ss_family = af;
 732                         if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
 733                                 return (ipadm_errno2status(errno));
 734                         if (is_persistent) {
 735                                 status = i_ipadm_persist_if(iph, ifname, af);

 736                                 if (status != IPADM_SUCCESS) {
 737                                         (void) i_ipadm_delete_if(iph, ifname,
 738                                             af, IPADM_OPT_ACTIVE);
 739                                 }
 740                         }
 741                 }
 742                 return (status);
 743         }
 744 
 745         dlpi_flags = DLPI_NOATTACH;
 746 
 747         /*
 748          * If IPADM_OPT_IPMP is specified, then this is a request
 749          * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
 750          * pass "ipmpstub0" as devname since an admin *could* have a normal
 751          * vanity-named link named "ipmpstub0" that they'd like to plumb.)
 752          */
 753         if (ipadm_flags & IPADM_OPT_IPMP) {
 754                 dlpi_flags |= DLPI_DEVONLY;
 755                 linkname = "ipmpstub0";


 896                         status = i_ipadm_set_flags(iph, lifname, af,
 897                             IFF_UP, 0);
 898                         if (status != IPADM_SUCCESS)
 899                                 return (status);
 900                 } else {
 901                         /*
 902                          * Prevent static IPv6 addresses from triggering
 903                          * autoconf. This does not have to be done for
 904                          * 6to4 tunnel interfaces, since in.ndpd will
 905                          * not autoconfigure those interfaces.
 906                          */
 907                         if (af == AF_INET6 && !legacy)
 908                                 (void) i_ipadm_disable_autoconf(newif);
 909                 }
 910 
 911                 /*
 912                  * If IPADM_OPT_PERSIST was set in flags, store the
 913                  * interface in persistent DB.
 914                  */
 915                 if (is_persistent) {
 916                         status = i_ipadm_persist_if(iph, newif, af);

 917                         if (status != IPADM_SUCCESS) {
 918                                 (void) i_ipadm_delete_if(iph, newif, af,
 919                                     IPADM_OPT_ACTIVE);
 920                         }
 921                 }
 922         }
 923         if (status == IPADM_EXISTS)
 924                 status = IPADM_IF_EXISTS;
 925         return (status);
 926 }
 927 
 928 /*
 929  * Unplumbs the interface in `ifname' of family `af'.
 930  */
 931 ipadm_status_t
 932 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
 933 {
 934         int             ip_muxid, arp_muxid;
 935         int             mux_fd = -1;
 936         int             muxid_fd = -1;


1129         if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1130                 /*
1131                  * in.ndpd maintains the phyints in its memory even after
1132                  * the interface is plumbed, so that it can be reused when
1133                  * the interface gets plumbed again. The default behavior
1134                  * of in.ndpd is to start autoconfiguration for an interface
1135                  * that gets plumbed. We need to send the
1136                  * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1137                  * default behavior on replumb.
1138                  */
1139                 (void) i_ipadm_enable_autoconf(ifname);
1140         }
1141         return (ret);
1142 }
1143 
1144 /*
1145  * Saves the given interface name `ifname' with address family `af' in
1146  * persistent DB.
1147  */
1148 static ipadm_status_t
1149 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)

1150 {
1151         ipmgmt_if_arg_t         ifarg;
1152         int                     err;
1153 
1154         (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1155         ifarg.ia_family = af;





1156         ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1157         ifarg.ia_flags = IPMGMT_PERSIST;
1158         err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1159         return (ipadm_errno2status(err));
1160 }
1161 
1162 /*
1163  * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1164  * is set in `ipadm_flags', it is also removed from persistent configuration.
1165  */
1166 ipadm_status_t
1167 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1168     uint32_t ipadm_flags)
1169 {
1170         ipadm_status_t          ret = IPADM_SUCCESS;
1171         ipadm_status_t          db_status;
1172         char                    tmp_ifname[LIFNAMSIZ];
1173         char                    *cp;
1174         struct ipadm_addrobj_s  ipaddr;
1175         boolean_t               is_persistent =


1328             !i_ipadm_is_6to4(iph, ifname)) {
1329                 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1330                 if (status != IPADM_SUCCESS)
1331                         return (status);
1332                 created_v4 = B_TRUE;
1333         }
1334         if (af == AF_INET6 || af == AF_UNSPEC) {
1335                 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1336                 if (status != IPADM_SUCCESS) {
1337                         if (created_v4) {
1338                                 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1339                                     IPADM_OPT_ACTIVE);
1340                         }
1341                         return (status);
1342                 }
1343         }
1344 
1345         return (IPADM_SUCCESS);
1346 }
1347 
















1348 /*























































































1349  * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1350  * when `af' = AF_UNSPEC.
1351  */
1352 ipadm_status_t
1353 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1354     uint32_t flags)
1355 {
1356         ipadm_status_t status1 = IPADM_SUCCESS;
1357         ipadm_status_t status2 = IPADM_SUCCESS;
1358         ipadm_status_t other;
1359 
1360         /* Check for the required authorization */
1361         if (!ipadm_check_auth())
1362                 return (IPADM_EAUTH);
1363 
1364         /* Validate the `ifname' for any logical interface. */
1365         if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1366             !i_ipadm_validate_ifname(iph, ifname))
1367                 return (IPADM_INVALID_ARG);
1368 


1431 
1432         status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1433         if (status != IPADM_SUCCESS)
1434                 return (status);
1435         if (ifname != NULL && *if_info == NULL)
1436                 return (IPADM_ENXIO);
1437 
1438         return (IPADM_SUCCESS);
1439 }
1440 
1441 /*
1442  * Frees the linked list allocated by ipadm_if_info().
1443  */
1444 void
1445 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1446 {
1447         ipadm_if_info_t *ifinfo_next;
1448 
1449         for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1450                 ifinfo_next = ifinfo->ifi_next;


1451                 free(ifinfo);
1452         }
1453 }
1454 











1455 /*
1456  * Re-enable the interface `ifname' based on the saved configuration
1457  * for `ifname'.
1458  */
1459 ipadm_status_t
1460 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1461 {
1462         nvlist_t        *ifnvl;
1463         ipadm_status_t  status;
1464         ifspec_t        ifsp;
1465 
1466         /* Check for the required authorization */
1467         if (!ipadm_check_auth())
1468                 return (IPADM_EAUTH);
1469 
1470         /* Check for logical interfaces. */
1471         if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1472                 return (IPADM_INVALID_ARG);
1473 
1474         /* Enabling an interface persistently is not supported. */
1475         if (flags & IPADM_OPT_PERSIST)
1476                 return (IPADM_NOTSUP);
1477 
1478         /*
1479          * Return early by checking if the interface is already enabled.
1480          */
1481         if (ipadm_if_enabled(iph, ifname, AF_INET) &&
1482             ipadm_if_enabled(iph, ifname, AF_INET6)) {
1483                 return (IPADM_IF_EXISTS);
1484         }
1485         /*
1486          * Enable the interface and restore all its interface properties
1487          * and address objects.
1488          */
1489         status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
1490         if (status != IPADM_SUCCESS)
1491                 return (status);
1492 
1493         assert(ifnvl != NULL);
1494         /*
1495          * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1496          * but only for one interface. We need to set IPH_INIT because
1497          * ipmgmtd daemon does not have to write the interface to persistent
1498          * db. The interface is already available in persistent db
1499          * and we are here to re-enable the persistent configuration.
1500          */
1501         iph->iph_flags |= IPH_INIT;
1502         status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
1503         iph->iph_flags &= ~IPH_INIT;
1504 


1531         status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
1532         if (status1 == IPADM_SUCCESS)
1533                 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1534         status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
1535         if (status2 == IPADM_SUCCESS)
1536                 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1537         if (status1 == status2) {
1538                 return (status2);
1539         } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1540                 if (status1 == IPADM_SUCCESS)
1541                         other = status2;
1542                 else
1543                         other = status1;
1544                 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1545         } else {
1546                 return (IPADM_FAILURE);
1547         }
1548 }
1549 
1550 /*
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'.



1555  *
1556  * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1557  * door_call(3C) fails. Also, there is no use in returning error because
1558  * `ifname' would have been successfuly moved into IPMP group, by this time.
1559  */
1560 void
1561 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1562 {
1563         (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1564         (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);












































































































1565 }
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2016 Nexenta Systems, Inc.
  25  */
  26 
  27 #include <errno.h>
  28 #include <sys/sockio.h>
  29 #include <sys/list.h>
  30 #include <string.h>
  31 #include <assert.h>
  32 #include <unistd.h>
  33 #include <stropts.h>
  34 #include <strings.h>
  35 #include <libdlpi.h>
  36 #include <libdllink.h>
  37 #include <libinetutil.h>
  38 #include <inet/ip.h>
  39 #include <limits.h>
  40 #include <zone.h>
  41 #include <ipadm_ndpd.h>
  42 #include <ipmp_query.h>
  43 #include "libipadm_impl.h"
  44 
  45 static ipadm_status_t   i_ipadm_slifname_arp(char *, uint64_t, int);
  46 static ipadm_status_t   i_ipadm_slifname(ipadm_handle_t, char *, char *,
  47                             uint64_t, int, uint32_t);
  48 static ipadm_status_t   i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
  49                             sa_family_t);
  50 static ipadm_status_t   i_ipadm_persist_if(ipadm_handle_t, const char *,
  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);
  67 
  68 /*
  69  * Returns B_FALSE if the interface in `ifname' has at least one address that is
  70  * IFF_UP in the addresses in `ifa'.
  71  */
  72 static boolean_t
  73 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
  74 {
  75         struct ifaddrs  *ifap;
  76         char            cifname[LIFNAMSIZ];
  77         char            *sep;
  78 
  79         for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
  80                 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
  81                 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
  82                         *sep = '\0';
  83                 /*
  84                  * If this condition is true, there is at least one
  85                  * address that is IFF_UP. So, we need to return B_FALSE.
  86                  */


 124         for (n = 0; n < numifs; n++, lifrp++) {
 125                 /* Skip interfaces with logical num != 0 */
 126                 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
 127                         continue;
 128                 /*
 129                  * Skip the current interface if a specific `ifname' has
 130                  * been requested and current interface does not match
 131                  * `ifname'.
 132                  */
 133                 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
 134                         continue;
 135                 /*
 136                  * Check if the interface already exists in our list.
 137                  * If it already exists, we need to update its flags.
 138                  */
 139                 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
 140                         if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
 141                                 break;
 142                 }
 143                 if (ifp == NULL) {
 144                         if ((status =
 145                             i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
 146                                         break;
 147 

 148                         (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
 149                             sizeof (ifp->ifi_name));
 150                         /* Update the `ifi_next' pointer for this new node */
 151                         if (*if_info == NULL)
 152                                 *if_info = ifp;
 153                         else
 154                                 last->ifi_next = ifp;
 155                         last = ifp;
 156                 }
 157 
 158                 /*
 159                  * Retrieve the flags for the interface by doing a
 160                  * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
 161                  */
 162                 (void) strlcpy(lifrl.lifr_name,
 163                     lifrp->lifr_name, sizeof (lifrl.lifr_name));
 164                 s = (lifrp->lifr_addr.ss_family == AF_INET) ?
 165                     iph->iph_sock : iph->iph_sock6;
 166                 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
 167                         continue;
 168 
 169                 /* a regular interface by default */
 170                 ifp->ifi_class = IPADM_IF_CLASS_REGULAR;
 171 
 172                 if (lifrl.lifr_flags & IFF_BROADCAST)
 173                         ifp->ifi_cflags |= IFIF_BROADCAST;
 174                 if (lifrl.lifr_flags & IFF_MULTICAST)
 175                         ifp->ifi_cflags |= IFIF_MULTICAST;
 176                 if (lifrl.lifr_flags & IFF_POINTOPOINT)
 177                         ifp->ifi_cflags |= IFIF_POINTOPOINT;
 178                 if (lifrl.lifr_flags & IFF_VIRTUAL) {
 179                         ifp->ifi_cflags |= IFIF_VIRTUAL;
 180                         ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL;
 181                 }
 182                 if (lifrl.lifr_flags & IFF_IPMP) {
 183                         ifp->ifi_cflags |= IFIF_IPMP;
 184                         ifp->ifi_class = IPADM_IF_CLASS_IPMP;
 185                 }
 186                 if (lifrl.lifr_flags & IFF_STANDBY)
 187                         ifp->ifi_cflags |= IFIF_STANDBY;
 188                 if (lifrl.lifr_flags & IFF_INACTIVE)
 189                         ifp->ifi_cflags |= IFIF_INACTIVE;
 190                 if (lifrl.lifr_flags & IFF_VRRP)
 191                         ifp->ifi_cflags |= IFIF_VRRP;
 192                 if (lifrl.lifr_flags & IFF_NOACCEPT)
 193                         ifp->ifi_cflags |= IFIF_NOACCEPT;
 194                 if (lifrl.lifr_flags & IFF_IPV4)
 195                         ifp->ifi_cflags |= IFIF_IPV4;
 196                 if (lifrl.lifr_flags & IFF_IPV6)
 197                         ifp->ifi_cflags |= IFIF_IPV6;
 198                 if (lifrl.lifr_flags & IFF_L3PROTECT)
 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                 }
 214         }
 215         free(buf);
 216         if (status != IPADM_SUCCESS) {


 217                 ipadm_free_if_info(*if_info);
 218                 *if_info = NULL;
 219         }
 220         return (status);
 221 }
 222 
 223 /*
 224  * Returns the interface information for `ifname' in `if_info' from persistent
 225  * config if `ifname' is non-null. Otherwise, it returns all the interfaces
 226  * from persistent config in `if_info'.
 227  */
 228 static ipadm_status_t
 229 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
 230     ipadm_if_info_t **if_info)
 231 {
 232         ipadm_status_t  status = IPADM_SUCCESS;
 233         nvlist_t        *ifs_info_nvl;



 234 





 235         *if_info = NULL;
 236 
 237         if ((status = i_ipadm_get_db_if(iph,
 238             ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
 239                 return (status);
 240 
 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);
 265                         break;
 266                 }
 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;
 302         }
 303 
 304         nvlist_free(ifs_info_nvl);
 305         return (status);
 306 }
 307 
 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 /*
 377  * Collects information for `ifname' if one is specified from both
 378  * active and persistent config in `if_info'. If no `ifname' is specified,
 379  * this returns all the interfaces in active and persistent config in
 380  * `if_info'.
 381  */
 382 ipadm_status_t
 383 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
 384     ipadm_if_info_t **if_info, int64_t lifc_flags)
 385 {
 386         ipadm_status_t  status;
 387         ipadm_if_info_t *aifinfo = NULL;
 388         ipadm_if_info_t *pifinfo = NULL;
 389         ipadm_if_info_t *aifp;
 390         ipadm_if_info_t *pifp;
 391         ipadm_if_info_t *last = NULL;
 392         struct ifaddrs  *ifa;
 393         struct ifaddrs  *ifap;


 446         /*
 447          * Get the persistent interface information in `pifinfo'.
 448          */
 449         status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
 450         if (status == IPADM_NOTFOUND) {
 451                 *if_info = aifinfo;
 452                 return (IPADM_SUCCESS);
 453         }
 454         if (status != IPADM_SUCCESS)
 455                 goto fail;
 456         /*
 457          * If a persistent interface is also found in `aifinfo', update
 458          * its entry in `aifinfo' with the persistent information from
 459          * `pifinfo'. If an interface is found in `pifinfo', but not in
 460          * `aifinfo', it means that this interface was disabled. We should
 461          * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
 462          */
 463         for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
 464                 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
 465                         if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {

 466                                 break;
 467                         }
 468                 }
 469 
 470                 if (aifp == NULL) {
 471                         if ((status =
 472                             i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)

 473                                 goto fail;
 474 
 475                         (void) strlcpy(aifp->ifi_name, pifp->ifi_name,
 476                             sizeof (aifp->ifi_name));
 477 
 478                         aifp->ifi_next = NULL;
 479                         aifp->ifi_state = IFIS_DISABLED;
 480                         if (last != NULL)
 481                                 last->ifi_next = aifp;
 482                         else
 483                                 aifinfo = aifp;
 484                         last = aifp;
 485                 }
 486 
 487                 if ((status = i_ipadm_add_persistent_if_info(aifp,
 488                     pifp)) != IPADM_SUCCESS)
 489                         goto fail;
 490         }
 491         *if_info = aifinfo;
 492         ipadm_free_if_info(pifinfo);
 493         return (IPADM_SUCCESS);
 494 fail:
 495         *if_info = NULL;
 496         ipadm_free_if_info(aifinfo);
 497         ipadm_free_if_info(pifinfo);
 498         return (status);
 499 }
 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 
 570 int
 571 i_ipadm_get_lnum(const char *ifname)
 572 {
 573         char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
 574 
 575         if (num == NULL)
 576                 return (0);
 577 
 578         return (atoi(++num));
 579 }
 580 
 581 /*
 582  * Sets the output argument `exists' to true or false based on whether
 583  * any persistent configuration is available for `ifname' and returns
 584  * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
 585  * `exists' is unmodified and an error status is returned.
 586  */
 587 ipadm_status_t
 588 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 589     boolean_t *exists)
 590 {
 591         ipadm_if_info_t *ifinfo;
 592         ipadm_status_t  status;
 593 
 594         /*
 595          * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
 596          * knows about persistent configuration in the first place, so we
 597          * just return success.
 598          */
 599         if (iph->iph_flags & IPH_IPMGMTD) {
 600                 *exists = B_FALSE;
 601                 return (IPADM_SUCCESS);
 602         }
 603         status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
 604         if (status == IPADM_SUCCESS) {
 605                 *exists = ((af == AF_INET &&
 606                     (ifinfo->ifi_pflags & IFIF_IPV4)) ||
 607                     (af == AF_INET6 &&
 608                     (ifinfo->ifi_pflags & IFIF_IPV6)));
 609                 ipadm_free_if_info(ifinfo);
 610         } else if (status == IPADM_NOTFOUND) {
 611                 status = IPADM_SUCCESS;
 612                 *exists = B_FALSE;
 613         }
 614         return (status);
 615 }
 616 
 617 /*
 618  * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
 619  * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
 620  * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
 621  * the bottom of the stream for tunneling interfaces.
 622  */
 623 ipadm_status_t
 624 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
 625 {
 626         int err;
 627 
 628         if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
 629                 return (ipadm_errno2status(errno));


 928                 if (af == AF_INET)
 929                         sock = iph->iph_sock;
 930                 else
 931                         sock = iph->iph_sock6;
 932                 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
 933                         return (IPADM_IF_EXISTS);
 934                 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
 935                         return (ipadm_errno2status(errno));
 936 
 937                 /*
 938                  * By default, kernel configures 127.0.0.1 on the loopback
 939                  * interface. Replace this with 0.0.0.0 to be consistent
 940                  * with interface creation on other physical interfaces.
 941                  */
 942                 if (islo && !legacy) {
 943                         bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
 944                         lifr.lifr_addr.ss_family = af;
 945                         if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
 946                                 return (ipadm_errno2status(errno));
 947                         if (is_persistent) {
 948                                 status = i_ipadm_persist_if(iph,
 949                                     ifname, af, ipadm_flags);
 950                                 if (status != IPADM_SUCCESS) {
 951                                         (void) i_ipadm_delete_if(iph, ifname,
 952                                             af, IPADM_OPT_ACTIVE);
 953                                 }
 954                         }
 955                 }
 956                 return (status);
 957         }
 958 
 959         dlpi_flags = DLPI_NOATTACH;
 960 
 961         /*
 962          * If IPADM_OPT_IPMP is specified, then this is a request
 963          * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
 964          * pass "ipmpstub0" as devname since an admin *could* have a normal
 965          * vanity-named link named "ipmpstub0" that they'd like to plumb.)
 966          */
 967         if (ipadm_flags & IPADM_OPT_IPMP) {
 968                 dlpi_flags |= DLPI_DEVONLY;
 969                 linkname = "ipmpstub0";


1110                         status = i_ipadm_set_flags(iph, lifname, af,
1111                             IFF_UP, 0);
1112                         if (status != IPADM_SUCCESS)
1113                                 return (status);
1114                 } else {
1115                         /*
1116                          * Prevent static IPv6 addresses from triggering
1117                          * autoconf. This does not have to be done for
1118                          * 6to4 tunnel interfaces, since in.ndpd will
1119                          * not autoconfigure those interfaces.
1120                          */
1121                         if (af == AF_INET6 && !legacy)
1122                                 (void) i_ipadm_disable_autoconf(newif);
1123                 }
1124 
1125                 /*
1126                  * If IPADM_OPT_PERSIST was set in flags, store the
1127                  * interface in persistent DB.
1128                  */
1129                 if (is_persistent) {
1130                         status = i_ipadm_persist_if(iph,
1131                             newif, af, ipadm_flags);
1132                         if (status != IPADM_SUCCESS) {
1133                                 (void) i_ipadm_delete_if(iph, newif, af,
1134                                     IPADM_OPT_ACTIVE);
1135                         }
1136                 }
1137         }
1138         if (status == IPADM_EXISTS)
1139                 status = IPADM_IF_EXISTS;
1140         return (status);
1141 }
1142 
1143 /*
1144  * Unplumbs the interface in `ifname' of family `af'.
1145  */
1146 ipadm_status_t
1147 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
1148 {
1149         int             ip_muxid, arp_muxid;
1150         int             mux_fd = -1;
1151         int             muxid_fd = -1;


1344         if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1345                 /*
1346                  * in.ndpd maintains the phyints in its memory even after
1347                  * the interface is plumbed, so that it can be reused when
1348                  * the interface gets plumbed again. The default behavior
1349                  * of in.ndpd is to start autoconfiguration for an interface
1350                  * that gets plumbed. We need to send the
1351                  * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1352                  * default behavior on replumb.
1353                  */
1354                 (void) i_ipadm_enable_autoconf(ifname);
1355         }
1356         return (ret);
1357 }
1358 
1359 /*
1360  * Saves the given interface name `ifname' with address family `af' in
1361  * persistent DB.
1362  */
1363 static ipadm_status_t
1364 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1365     uint32_t ipadm_flags)
1366 {
1367         ipmgmt_if_arg_t         ifarg;
1368         int                     err;
1369 
1370         (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
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 
1377         ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1378         ifarg.ia_flags = IPMGMT_PERSIST;
1379         err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1380         return (ipadm_errno2status(err));
1381 }
1382 
1383 /*
1384  * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1385  * is set in `ipadm_flags', it is also removed from persistent configuration.
1386  */
1387 ipadm_status_t
1388 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1389     uint32_t ipadm_flags)
1390 {
1391         ipadm_status_t          ret = IPADM_SUCCESS;
1392         ipadm_status_t          db_status;
1393         char                    tmp_ifname[LIFNAMSIZ];
1394         char                    *cp;
1395         struct ipadm_addrobj_s  ipaddr;
1396         boolean_t               is_persistent =


1549             !i_ipadm_is_6to4(iph, ifname)) {
1550                 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1551                 if (status != IPADM_SUCCESS)
1552                         return (status);
1553                 created_v4 = B_TRUE;
1554         }
1555         if (af == AF_INET6 || af == AF_UNSPEC) {
1556                 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1557                 if (status != IPADM_SUCCESS) {
1558                         if (created_v4) {
1559                                 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1560                                     IPADM_OPT_ACTIVE);
1561                         }
1562                         return (status);
1563                 }
1564         }
1565 
1566         return (IPADM_SUCCESS);
1567 }
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 
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 /*
1673  * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1674  * when `af' = AF_UNSPEC.
1675  */
1676 ipadm_status_t
1677 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1678     uint32_t flags)
1679 {
1680         ipadm_status_t status1 = IPADM_SUCCESS;
1681         ipadm_status_t status2 = IPADM_SUCCESS;
1682         ipadm_status_t other;
1683 
1684         /* Check for the required authorization */
1685         if (!ipadm_check_auth())
1686                 return (IPADM_EAUTH);
1687 
1688         /* Validate the `ifname' for any logical interface. */
1689         if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1690             !i_ipadm_validate_ifname(iph, ifname))
1691                 return (IPADM_INVALID_ARG);
1692 


1755 
1756         status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1757         if (status != IPADM_SUCCESS)
1758                 return (status);
1759         if (ifname != NULL && *if_info == NULL)
1760                 return (IPADM_ENXIO);
1761 
1762         return (IPADM_SUCCESS);
1763 }
1764 
1765 /*
1766  * Frees the linked list allocated by ipadm_if_info().
1767  */
1768 void
1769 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1770 {
1771         ipadm_if_info_t *ifinfo_next;
1772 
1773         for (; ifinfo != NULL; ifinfo = ifinfo_next) {
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);
1777                 free(ifinfo);
1778         }
1779 }
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 
1792 /*
1793  * Re-enable the interface `ifname' based on the saved configuration
1794  * for `ifname'.
1795  */
1796 ipadm_status_t
1797 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1798 {
1799         nvlist_t        *ifnvl;
1800         ipadm_status_t  status;
1801         ifspec_t        ifsp;
1802 
1803         /* Check for the required authorization */
1804         if (!ipadm_check_auth())
1805                 return (IPADM_EAUTH);
1806 
1807         /* Check for logical interfaces. */
1808         if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1809                 return (IPADM_INVALID_ARG);
1810 
1811         /* Enabling an interface persistently is not supported. */
1812         if (flags & IPADM_OPT_PERSIST)
1813                 return (IPADM_NOTSUP);
1814 
1815         /*
1816          * Return early by checking if the interface is already enabled.
1817          */
1818         if (ipadm_if_enabled(iph, ifname, AF_INET) &&
1819             ipadm_if_enabled(iph, ifname, AF_INET6))
1820                 return (IPADM_IF_EXISTS);
1821 
1822         /*
1823          * Enable the interface and restore all its interface properties
1824          * and address objects.
1825          */
1826         status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
1827         if (status != IPADM_SUCCESS)
1828                 return (status);
1829 
1830         assert(ifnvl != NULL);
1831         /*
1832          * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1833          * but only for one interface. We need to set IPH_INIT because
1834          * ipmgmtd daemon does not have to write the interface to persistent
1835          * db. The interface is already available in persistent db
1836          * and we are here to re-enable the persistent configuration.
1837          */
1838         iph->iph_flags |= IPH_INIT;
1839         status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
1840         iph->iph_flags &= ~IPH_INIT;
1841 


1868         status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
1869         if (status1 == IPADM_SUCCESS)
1870                 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1871         status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
1872         if (status2 == IPADM_SUCCESS)
1873                 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1874         if (status1 == status2) {
1875                 return (status2);
1876         } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1877                 if (status1 == IPADM_SUCCESS)
1878                         other = status2;
1879                 else
1880                         other = status1;
1881                 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1882         } else {
1883                 return (IPADM_FAILURE);
1884         }
1885 }
1886 
1887 /*
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'.
1895  *
1896  * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1897  * door_call(3C) fails. Also, there is no use in returning error because
1898  * `ifname' would have been successfuly moved into IPMP group, by this time.
1899  */
1900 void
1901 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1902 {
1903         (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
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);
2013 }