Print this page
Commit IPMP changes


   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 =


1246  * Create the interface by plumbing it for IP.
1247  * This function will check if there is saved configuration information
1248  * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1249  * for `ifname' is taken.
1250  */
1251 ipadm_status_t
1252 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1253     uint32_t ipadm_flags)
1254 {
1255         ipadm_status_t  status;
1256         boolean_t       p_exists;
1257         sa_family_t     other_af;
1258 
1259         /*
1260          * Return error, if the interface already exists in either the active
1261          * or the persistent configuration.
1262          */
1263         if (ipadm_if_enabled(iph, ifname, af))
1264                 return (IPADM_IF_EXISTS);
1265 

1266         if (!(iph->iph_flags & IPH_LEGACY)) {
1267                 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1268                 if (status != IPADM_SUCCESS)
1269                         return (status);
1270                 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1271                 if (p_exists) {
1272                         if (!ipadm_if_enabled(iph, ifname, other_af))
1273                                 return (IPADM_OP_DISABLE_OBJ);
1274                         else
1275                                 ipadm_flags &= ~IPADM_OPT_PERSIST;
1276                 }
1277         }
1278 
1279         return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1280 }
1281 
1282 /*
1283  * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1284  * default, unless a value in `af' is specified. The interface may be plumbed
1285  * only if there is no previously saved persistent configuration information
1286  * for the interface (in which case the ipadm_enable_if() function must
1287  * be used to enable the interface).
1288  *
1289  * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1290  * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1291  * or appropriate ipadm_status_t corresponding to the errno.
1292  *
1293  * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1294  * be over-written with the actual interface name when a PPA has to be
1295  * internally generated by the library.
1296  */
1297 ipadm_status_t
1298 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,


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. */


1543         } else {
1544                 return (IPADM_FAILURE);
1545         }
1546 }
1547 
1548 /*
1549  * This workaround is until libipadm supports IPMP and is required whenever an
1550  * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1551  * yet, we will have to update the daemon's in-memory mapping of
1552  * `aobjname' to 'lifnum'.
1553  *
1554  * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1555  * door_call(3C) fails. Also, there is no use in returning error because
1556  * `ifname' would have been successfuly moved into IPMP group, by this time.
1557  */
1558 void
1559 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1560 {
1561         (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1562         (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);













































































1563 }


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


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

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


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



 233 





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


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

 471                                 break;
 472                         }
 473                 }
 474 
 475                 if (aifp == NULL) {
 476                         if ((status =
 477                             i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)

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


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


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


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


1472  * Create the interface by plumbing it for IP.
1473  * This function will check if there is saved configuration information
1474  * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1475  * for `ifname' is taken.
1476  */
1477 ipadm_status_t
1478 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1479     uint32_t ipadm_flags)
1480 {
1481         ipadm_status_t  status;
1482         boolean_t       p_exists;
1483         sa_family_t     other_af;
1484 
1485         /*
1486          * Return error, if the interface already exists in either the active
1487          * or the persistent configuration.
1488          */
1489         if (ipadm_if_enabled(iph, ifname, af))
1490                 return (IPADM_IF_EXISTS);
1491 
1492 #if 0
1493         if (!(iph->iph_flags & IPH_LEGACY)) {
1494                 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1495                 if (status != IPADM_SUCCESS)
1496                         return (status);
1497                 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1498                 if (p_exists) {
1499                         if (!ipadm_if_enabled(iph, ifname, other_af))
1500                                 return (IPADM_OP_DISABLE_OBJ);
1501                         else
1502                                 ipadm_flags &= ~IPADM_OPT_PERSIST;
1503                 }
1504         }
1505 #endif
1506         return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1507 }
1508 
1509 /*
1510  * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1511  * default, unless a value in `af' is specified. The interface may be plumbed
1512  * only if there is no previously saved persistent configuration information
1513  * for the interface (in which case the ipadm_enable_if() function must
1514  * be used to enable the interface).
1515  *
1516  * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1517  * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1518  * or appropriate ipadm_status_t corresponding to the errno.
1519  *
1520  * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1521  * be over-written with the actual interface name when a PPA has to be
1522  * internally generated by the library.
1523  */
1524 ipadm_status_t
1525 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,


1555             !i_ipadm_is_6to4(iph, ifname)) {
1556                 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1557                 if (status != IPADM_SUCCESS)
1558                         return (status);
1559                 created_v4 = B_TRUE;
1560         }
1561         if (af == AF_INET6 || af == AF_UNSPEC) {
1562                 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1563                 if (status != IPADM_SUCCESS) {
1564                         if (created_v4) {
1565                                 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1566                                     IPADM_OPT_ACTIVE);
1567                         }
1568                         return (status);
1569                 }
1570         }
1571 
1572         return (IPADM_SUCCESS);
1573 }
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 
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 /*
1705  * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1706  * when `af' = AF_UNSPEC.
1707  */
1708 ipadm_status_t
1709 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1710     uint32_t flags)
1711 {
1712         ipadm_status_t status1 = IPADM_SUCCESS;
1713         ipadm_status_t status2 = IPADM_SUCCESS;
1714         ipadm_status_t other;
1715 
1716         /* Check for the required authorization */
1717         if (!ipadm_check_auth())
1718                 return (IPADM_EAUTH);
1719 
1720         /* Validate the `ifname' for any logical interface. */
1721         if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1722             !i_ipadm_validate_ifname(iph, ifname))
1723                 return (IPADM_INVALID_ARG);
1724 


1787 
1788         status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1789         if (status != IPADM_SUCCESS)
1790                 return (status);
1791         if (ifname != NULL && *if_info == NULL)
1792                 return (IPADM_ENXIO);
1793 
1794         return (IPADM_SUCCESS);
1795 }
1796 
1797 /*
1798  * Frees the linked list allocated by ipadm_if_info().
1799  */
1800 void
1801 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1802 {
1803         ipadm_if_info_t *ifinfo_next;
1804 
1805         for (; ifinfo != NULL; ifinfo = ifinfo_next) {
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);
1809                 free(ifinfo);
1810         }
1811 }
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 
1824 /*
1825  * Re-enable the interface `ifname' based on the saved configuration
1826  * for `ifname'.
1827  */
1828 ipadm_status_t
1829 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1830 {
1831         nvlist_t        *ifnvl;
1832         ipadm_status_t  status;
1833         ifspec_t        ifsp;
1834 
1835         /* Check for the required authorization */
1836         if (!ipadm_check_auth())
1837                 return (IPADM_EAUTH);
1838 
1839         /* Check for logical interfaces. */
1840         if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1841                 return (IPADM_INVALID_ARG);
1842 
1843         /* Enabling an interface persistently is not supported. */


1912         } else {
1913                 return (IPADM_FAILURE);
1914         }
1915 }
1916 
1917 /*
1918  * This workaround is until libipadm supports IPMP and is required whenever an
1919  * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1920  * yet, we will have to update the daemon's in-memory mapping of
1921  * `aobjname' to 'lifnum'.
1922  *
1923  * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1924  * door_call(3C) fails. Also, there is no use in returning error because
1925  * `ifname' would have been successfuly moved into IPMP group, by this time.
1926  */
1927 void
1928 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1929 {
1930         (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
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);
2009 }