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 */ 68 if (strcmp(cifname, ifname) == 0 && 69 (ifap->ifa_flags & IFF_UP)) { 70 return (B_FALSE); 71 } 72 } 73 /* We did not find any IFF_UP addresses. */ 74 return (B_TRUE); 75 } 76 77 /* 78 * Retrieves the information for the interface `ifname' from active 79 * config if `ifname' is specified and returns the result in the list `if_info'. 80 * Otherwise, it retrieves the information for all the interfaces in 81 * the active config and returns the result in the list `if_info'. 82 */ 83 static ipadm_status_t 84 i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname, 85 ipadm_if_info_t **if_info, int64_t lifc_flags) 86 { 87 struct lifreq *buf; 88 struct lifreq *lifrp; 89 struct lifreq lifrl; 90 ipadm_if_info_t *last = NULL; 91 ipadm_if_info_t *ifp; 92 int s; 93 int n; 94 int numifs; 95 ipadm_status_t status; 96 97 *if_info = NULL; 98 /* 99 * Get information for all interfaces. 100 */ 101 if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0) 102 return (ipadm_errno2status(errno)); 103 104 lifrp = buf; 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; 255 256 /* 257 * Retrive the information for the requested `ifname' or all 258 * interfaces from active configuration. 259 */ 260 retry: 261 status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags); 262 if (status != IPADM_SUCCESS) 263 return (status); 264 /* Get the interface state for each interface in `aifinfo'. */ 265 if (aifinfo != NULL) { 266 /* We need all addresses to get the interface state */ 267 if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY| 268 LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) { 269 status = ipadm_errno2status(errno); 270 goto fail; 271 } 272 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { 273 /* 274 * Find the `ifaddrs' structure from `ifa' 275 * for this interface. We need the IFF_* flags 276 * to find the interface state. 277 */ 278 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 279 if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0) 280 break; 281 } 282 if (ifap == NULL) { 283 /* 284 * The interface might have been removed 285 * from kernel. Retry getting all the active 286 * interfaces. 287 */ 288 freeifaddrs(ifa); 289 ipadm_free_if_info(aifinfo); 290 aifinfo = NULL; 291 goto retry; 292 } 293 if (!(ifap->ifa_flags & IFF_RUNNING) || 294 (ifap->ifa_flags & IFF_FAILED)) 295 aifp->ifi_state = IFIS_FAILED; 296 else if (ifap->ifa_flags & IFF_OFFLINE) 297 aifp->ifi_state = IFIS_OFFLINE; 298 else if (i_ipadm_is_if_down(aifp->ifi_name, ifa)) 299 aifp->ifi_state = IFIS_DOWN; 300 else 301 aifp->ifi_state = IFIS_OK; 302 if (aifp->ifi_next == NULL) 303 last = aifp; 304 } 305 freeifaddrs(ifa); 306 } 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)); 417 418 /* 419 * Pop off all undesired modules (note that the user may have 420 * configured autopush to add modules above udp), and push the 421 * arp module onto the resulting stream. This is used to make 422 * IP+ARP be able to atomically track the muxid for the I_PLINKed 423 * STREAMS, thus it isn't related to ARP running the ARP protocol. 424 */ 425 while (ioctl(*fd, I_POP, 0) != -1) 426 ; 427 if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1) 428 return (IPADM_SUCCESS); 429 err = errno; 430 (void) close(*fd); 431 432 return (ipadm_errno2status(err)); 433 } 434 435 /* 436 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an 437 * underlying interface in an ipmp group G is plumbed for an address family, 438 * but the meta-interface for the other address family `af' does not exist 439 * yet for the group G. If `af' is IPv6, we need to bring up the 440 * link-local address. 441 */ 442 static ipadm_status_t 443 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af, 444 const char *grname, uint32_t ipadm_flags) 445 { 446 ipadm_status_t status; 447 struct lifreq lifr; 448 int sock; 449 int err; 450 451 assert(ipadm_flags & IPADM_OPT_IPMP); 452 453 /* Create the ipmp underlying interface */ 454 status = i_ipadm_create_if(iph, ifname, af, ipadm_flags); 455 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) 456 return (status); 457 458 /* 459 * To preserve backward-compatibility, always bring up the link-local 460 * address for implicitly-created IPv6 IPMP interfaces. 461 */ 462 if (af == AF_INET6) 463 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0); 464 465 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 466 /* 467 * If the caller requested a different group name, issue a 468 * SIOCSLIFGROUPNAME on the new IPMP interface. 469 */ 470 bzero(&lifr, sizeof (lifr)); 471 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 472 if (strcmp(lifr.lifr_name, grname) != 0) { 473 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ); 474 if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) { 475 err = errno; 476 /* Remove the interface we created. */ 477 if (status == IPADM_SUCCESS) { 478 (void) i_ipadm_delete_if(iph, ifname, af, 479 ipadm_flags); 480 } 481 return (ipadm_errno2status(err)); 482 } 483 } 484 485 return (IPADM_SUCCESS); 486 } 487 488 /* 489 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address 490 * family. If so, create a matching IPMP group for address family `af'. 491 */ 492 static ipadm_status_t 493 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af) 494 { 495 lifgroupinfo_t lifgr; 496 ipadm_status_t status = IPADM_SUCCESS; 497 struct lifreq lifr; 498 int other_af_sock; 499 500 assert(af == AF_INET || af == AF_INET6); 501 502 other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock); 503 504 /* 505 * iph is the handle for the interface that we are trying to plumb. 506 * other_af_sock is the socket for the "other" address family. 507 */ 508 bzero(&lifr, sizeof (lifr)); 509 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 510 if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0) 511 return (IPADM_SUCCESS); 512 513 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ); 514 if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0) 515 return (IPADM_SUCCESS); 516 517 /* 518 * If `ifname' *is* the IPMP group interface, or if the relevant 519 * address family is already configured, then there's nothing to do. 520 */ 521 if (strcmp(lifgr.gi_grifname, ifname) == 0 || 522 (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) { 523 return (IPADM_SUCCESS); 524 } 525 526 status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af, 527 lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP); 528 return (status); 529 } 530 531 /* 532 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd. 533 */ 534 static ipadm_status_t 535 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd) 536 { 537 struct lifreq lifr; 538 ifspec_t ifsp; 539 540 bzero(&lifr, sizeof (lifr)); 541 (void) ifparse_ifspec(ifname, &ifsp); 542 lifr.lifr_ppa = ifsp.ifsp_ppa; 543 lifr.lifr_flags = flags; 544 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 545 /* 546 * Tell ARP the name and unit number for this interface. 547 * Note that arp has no support for transparent ioctls. 548 */ 549 if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr, 550 sizeof (lifr)) == -1) { 551 return (ipadm_errno2status(errno)); 552 } 553 return (IPADM_SUCCESS); 554 } 555 556 /* 557 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in 558 * `ipadm_flags', then a ppa will be generated. `newif' will be updated 559 * with the generated ppa. 560 */ 561 static ipadm_status_t 562 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags, 563 int fd, uint32_t ipadm_flags) 564 { 565 struct lifreq lifr; 566 ipadm_status_t status = IPADM_SUCCESS; 567 int err = 0; 568 sa_family_t af; 569 int ppa; 570 ifspec_t ifsp; 571 boolean_t valid_if; 572 573 bzero(&lifr, sizeof (lifr)); 574 if (ipadm_flags & IPADM_OPT_GENPPA) { 575 /* 576 * We'd like to just set lifr_ppa to UINT_MAX and have the 577 * kernel pick a PPA. Unfortunately, that would mishandle 578 * two cases: 579 * 580 * 1. If the PPA is available but the groupname is taken 581 * (e.g., the "ipmp2" IP interface name is available 582 * but the "ipmp2" groupname is taken) then the 583 * auto-assignment by the kernel will fail. 584 * 585 * 2. If we're creating (e.g.) an IPv6-only IPMP 586 * interface, and there's already an IPv4-only IPMP 587 * interface, the kernel will allow us to accidentally 588 * reuse the IPv6 IPMP interface name (since 589 * SIOCSLIFNAME uniqueness is per-interface-type). 590 * This will cause administrative confusion. 591 * 592 * Thus, we instead take a brute-force approach of checking 593 * whether the IPv4 or IPv6 name is already in-use before 594 * attempting the SIOCSLIFNAME. As per (1) above, the 595 * SIOCSLIFNAME may still fail, in which case we just proceed 596 * to the next one. If this approach becomes too slow, we 597 * can add a new SIOC* to handle this case in the kernel. 598 */ 599 for (ppa = 0; ppa < UINT_MAX; ppa++) { 600 (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d", 601 ifname, ppa); 602 603 if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 || 604 errno != ENXIO) 605 continue; 606 607 if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 || 608 errno != ENXIO) 609 continue; 610 611 lifr.lifr_ppa = ppa; 612 lifr.lifr_flags = flags; 613 614 err = ioctl(fd, SIOCSLIFNAME, &lifr); 615 if (err != -1 || errno != EEXIST) 616 break; 617 } 618 if (err == -1) { 619 status = ipadm_errno2status(errno); 620 } else { 621 /* 622 * PPA has been successfully established. 623 * Update `newif' with the ppa. 624 */ 625 assert(newif != NULL); 626 if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname, 627 ppa) >= LIFNAMSIZ) 628 return (IPADM_INVALID_ARG); 629 } 630 } else { 631 /* We should have already validated the interface name. */ 632 valid_if = ifparse_ifspec(ifname, &ifsp); 633 assert(valid_if); 634 635 /* 636 * Before we call SIOCSLIFNAME, ensure that the IPMP group 637 * interface for this address family exists. Otherwise, the 638 * kernel will kick the interface out of the group when we do 639 * the SIOCSLIFNAME. 640 * 641 * Example: suppose bge0 is plumbed for IPv4 and in group "a". 642 * If we're now plumbing bge0 for IPv6, but the IPMP group 643 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME 644 * will kick bge0 out of group "a", which is undesired. 645 */ 646 if (flags & IFF_IPV4) 647 af = AF_INET; 648 else 649 af = AF_INET6; 650 status = i_ipadm_create_ipmp_peer(iph, ifname, af); 651 if (status != IPADM_SUCCESS) 652 return (status); 653 lifr.lifr_ppa = ifsp.ifsp_ppa; 654 lifr.lifr_flags = flags; 655 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 656 if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1) 657 status = ipadm_errno2status(errno); 658 } 659 660 return (status); 661 } 662 663 /* 664 * Plumbs the interface `ifname' for the address family `af'. It also persists 665 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'. 666 */ 667 ipadm_status_t 668 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 669 uint32_t ipadm_flags) 670 { 671 int ip_muxid; 672 int mux_fd = -1, ip_fd, arp_fd; 673 char *udp_dev_name; 674 dlpi_handle_t dh_arp = NULL, dh_ip; 675 uint64_t ifflags; 676 struct lifreq lifr; 677 uint_t dlpi_flags; 678 ipadm_status_t status = IPADM_SUCCESS; 679 char *linkname; 680 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 681 zoneid_t zoneid; 682 char newif[LIFNAMSIZ]; 683 char lifname[LIFNAMSIZ]; 684 datalink_id_t linkid; 685 int sock; 686 boolean_t islo; 687 boolean_t is_persistent = 688 ((ipadm_flags & IPADM_OPT_PERSIST) != 0); 689 uint32_t dlflags; 690 dladm_status_t dlstatus; 691 692 if (iph->iph_dlh != NULL) { 693 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, 694 &dlflags, NULL, NULL); 695 } 696 /* 697 * If we're in the global zone and we're plumbing a datalink, make 698 * sure that the datalink is not assigned to a non-global zone. Note 699 * that the non-global zones don't need this check, because zoneadm 700 * has taken care of this when the zones boot. 701 */ 702 if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) { 703 zoneid = ALL_ZONES; 704 if (zone_check_datalink(&zoneid, linkid) == 0) { 705 /* interface is in use by a non-global zone. */ 706 return (IPADM_IF_INUSE); 707 } 708 } 709 710 /* loopback interfaces are just added as logical interface */ 711 bzero(&lifr, sizeof (lifr)); 712 islo = i_ipadm_is_loopback(ifname); 713 if (islo || i_ipadm_get_lnum(ifname) != 0) { 714 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 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"; 756 } else { 757 /* 758 * Verify that the user is not creating a persistent 759 * IP interface on a non-persistent data-link. 760 */ 761 if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK && 762 is_persistent && !(dlflags & DLADM_OPT_PERSIST)) { 763 return (IPADM_TEMPORARY_OBJ); 764 } 765 linkname = ifname; 766 } 767 768 /* 769 * We use DLPI_NOATTACH because the ip module will do the attach 770 * itself for DLPI style-2 devices. 771 */ 772 if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS) 773 return (IPADM_DLPI_FAILURE); 774 ip_fd = dlpi_fd(dh_ip); 775 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) { 776 status = ipadm_errno2status(errno); 777 goto done; 778 } 779 780 /* 781 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications 782 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL. 783 */ 784 ifflags = 0; 785 786 /* Set the name string and the IFF_IPV* flag */ 787 if (af == AF_INET) { 788 ifflags = IFF_IPV4; 789 } else { 790 ifflags = IFF_IPV6; 791 /* 792 * With the legacy method, the link-local address should be 793 * configured as part of the interface plumb, using the default 794 * token. If IPH_LEGACY is not specified, we want to set :: as 795 * the address and require the admin to explicitly call 796 * ipadm_create_addr() with the address object type set to 797 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address 798 * as well as the autoconfigured addresses. 799 */ 800 if (!legacy && !i_ipadm_is_6to4(iph, ifname)) 801 ifflags |= IFF_NOLINKLOCAL; 802 } 803 (void) strlcpy(newif, ifname, sizeof (newif)); 804 status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd, 805 ipadm_flags); 806 if (status != IPADM_SUCCESS) 807 goto done; 808 809 /* Get the full set of existing flags for this stream */ 810 status = i_ipadm_get_flags(iph, newif, af, &ifflags); 811 if (status != IPADM_SUCCESS) 812 goto done; 813 814 udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME); 815 status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 816 if (status != IPADM_SUCCESS) 817 goto done; 818 819 /* Check if arp is not needed */ 820 if (ifflags & (IFF_NOARP|IFF_IPV6)) { 821 /* 822 * PLINK the interface stream so that the application can exit 823 * without tearing down the stream. 824 */ 825 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 826 status = ipadm_errno2status(errno); 827 goto done; 828 } 829 830 /* 831 * This interface does use ARP, so set up a separate stream 832 * from the interface to ARP. 833 * 834 * We use DLPI_NOATTACH because the arp module will do the attach 835 * itself for DLPI style-2 devices. 836 */ 837 if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) { 838 status = IPADM_DLPI_FAILURE; 839 goto done; 840 } 841 842 arp_fd = dlpi_fd(dh_arp); 843 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) { 844 status = ipadm_errno2status(errno); 845 goto done; 846 } 847 848 status = i_ipadm_slifname_arp(newif, ifflags, arp_fd); 849 if (status != IPADM_SUCCESS) 850 goto done; 851 /* 852 * PLINK the IP and ARP streams so that ifconfig can exit 853 * without tearing down the stream. 854 */ 855 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 856 status = ipadm_errno2status(errno); 857 goto done; 858 } 859 860 if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) { 861 status = ipadm_errno2status(errno); 862 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 863 } 864 865 done: 866 dlpi_close(dh_ip); 867 if (dh_arp != NULL) 868 dlpi_close(dh_arp); 869 870 if (mux_fd != -1) 871 (void) close(mux_fd); 872 873 if (status == IPADM_SUCCESS) { 874 /* copy back new ifname */ 875 (void) strlcpy(ifname, newif, LIFNAMSIZ); 876 /* 877 * If it is a 6to4 tunnel, create a default 878 * addrobj name for the default address on the 0'th 879 * logical interface and set IFF_UP in the interface flags. 880 */ 881 if (i_ipadm_is_6to4(iph, ifname)) { 882 struct ipadm_addrobj_s addr; 883 884 i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC); 885 addr.ipadm_af = af; 886 status = i_ipadm_lookupadd_addrobj(iph, &addr); 887 if (status != IPADM_SUCCESS) 888 return (status); 889 status = ipadm_add_aobjname(iph, ifname, 890 af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0); 891 if (status != IPADM_SUCCESS) 892 return (status); 893 addr.ipadm_lifnum = 0; 894 i_ipadm_addrobj2lifname(&addr, lifname, 895 sizeof (lifname)); 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; 937 char *udp_dev_name; 938 uint64_t flags; 939 boolean_t changed_arp_muxid = B_FALSE; 940 int save_errno; 941 struct lifreq lifr; 942 ipadm_status_t ret = IPADM_SUCCESS; 943 int sock; 944 lifgroupinfo_t lifgr; 945 ifaddrlistx_t *ifaddrs, *ifaddrp; 946 boolean_t v6 = (af == AF_INET6); 947 948 /* Just do SIOCLIFREMOVEIF on loopback interfaces */ 949 bzero(&lifr, sizeof (lifr)); 950 if (i_ipadm_is_loopback(ifname) || 951 (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) { 952 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 953 if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6, 954 SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 955 return (ipadm_errno2status(errno)); 956 } 957 return (IPADM_SUCCESS); 958 } 959 960 /* 961 * We used /dev/udp or udp6 to set up the mux. So we have to use 962 * the same now for PUNLINK also. 963 */ 964 if (v6) { 965 udp_dev_name = UDP6_DEV_NAME; 966 sock = iph->iph_sock6; 967 } else { 968 udp_dev_name = UDP_DEV_NAME; 969 sock = iph->iph_sock; 970 } 971 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) { 972 ret = ipadm_errno2status(errno); 973 goto done; 974 } 975 ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 976 if (ret != IPADM_SUCCESS) 977 goto done; 978 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 979 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 980 ret = ipadm_errno2status(errno); 981 goto done; 982 } 983 flags = lifr.lifr_flags; 984 again: 985 if (flags & IFF_IPMP) { 986 /* 987 * There are two reasons the I_PUNLINK can fail with EBUSY: 988 * (1) if IP interfaces are in the group, or (2) if IPMP data 989 * addresses are administratively up. For case (1), we fail 990 * here with a specific error message. For case (2), we bring 991 * down the addresses prior to doing the I_PUNLINK. If the 992 * I_PUNLINK still fails with EBUSY then the configuration 993 * must have changed after our checks, in which case we branch 994 * back up to `again' and rerun this logic. The net effect is 995 * that unplumbing an IPMP interface will only fail with EBUSY 996 * if IP interfaces are in the group. 997 */ 998 if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) { 999 ret = ipadm_errno2status(errno); 1000 goto done; 1001 } 1002 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, 1003 LIFGRNAMSIZ); 1004 if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) { 1005 ret = ipadm_errno2status(errno); 1006 goto done; 1007 } 1008 if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) { 1009 ret = IPADM_GRP_NOTEMPTY; 1010 goto done; 1011 } 1012 1013 /* 1014 * The kernel will fail the I_PUNLINK if the IPMP interface 1015 * has administratively up addresses; bring them down. 1016 */ 1017 if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE, 1018 0, &ifaddrs) == -1) { 1019 ret = ipadm_errno2status(errno); 1020 goto done; 1021 } 1022 ifaddrp = ifaddrs; 1023 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 1024 int sock = (ifaddrp->ia_flags & IFF_IPV4) ? 1025 iph->iph_sock : iph->iph_sock6; 1026 struct lifreq lifrl; 1027 1028 if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) || 1029 (!(ifaddrp->ia_flags & IFF_IPV6) && v6)) 1030 continue; 1031 1032 bzero(&lifrl, sizeof (lifrl)); 1033 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name, 1034 sizeof (lifrl.lifr_name)); 1035 if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) { 1036 ret = ipadm_errno2status(errno); 1037 ifaddrlistx_free(ifaddrs); 1038 goto done; 1039 } 1040 if (lifrl.lifr_flags & IFF_UP) { 1041 ret = i_ipadm_set_flags(iph, lifrl.lifr_name, 1042 ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET : 1043 AF_INET6), 0, IFF_UP); 1044 if (ret != IPADM_SUCCESS) { 1045 ifaddrlistx_free(ifaddrs); 1046 goto done; 1047 } 1048 } else if (lifrl.lifr_flags & IFF_DUPLICATE) { 1049 if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 || 1050 ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) { 1051 ret = ipadm_errno2status(errno); 1052 ifaddrlistx_free(ifaddrs); 1053 goto done; 1054 } 1055 } 1056 } 1057 ifaddrlistx_free(ifaddrs); 1058 } 1059 1060 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 1061 ret = ipadm_errno2status(errno); 1062 goto done; 1063 } 1064 arp_muxid = lifr.lifr_arp_muxid; 1065 ip_muxid = lifr.lifr_ip_muxid; 1066 1067 /* 1068 * We don't have a good way of knowing whether the arp stream is 1069 * plumbed. We can't rely on IFF_NOARP because someone could 1070 * have turned it off later using "ifconfig xxx -arp". 1071 */ 1072 if (arp_muxid != 0) { 1073 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 1074 /* 1075 * See the comment before the SIOCGLIFGROUPNAME call. 1076 */ 1077 if (errno == EBUSY && (flags & IFF_IPMP)) 1078 goto again; 1079 1080 if ((errno == EINVAL) && 1081 (flags & (IFF_NOARP | IFF_IPV6))) { 1082 /* 1083 * Some plumbing utilities set the muxid to 1084 * -1 or some invalid value to signify that 1085 * there is no arp stream. Set the muxid to 0 1086 * before trying to unplumb the IP stream. 1087 * IP does not allow the IP stream to be 1088 * unplumbed if it sees a non-null arp muxid, 1089 * for consistency of IP-ARP streams. 1090 */ 1091 lifr.lifr_arp_muxid = 0; 1092 (void) ioctl(muxid_fd, SIOCSLIFMUXID, 1093 (caddr_t)&lifr); 1094 changed_arp_muxid = B_TRUE; 1095 } 1096 /* 1097 * In case of any other error, we continue with 1098 * the unplumb. 1099 */ 1100 } 1101 } 1102 1103 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 1104 if (changed_arp_muxid) { 1105 /* 1106 * Some error occurred, and we need to restore 1107 * everything back to what it was. 1108 */ 1109 save_errno = errno; 1110 lifr.lifr_arp_muxid = arp_muxid; 1111 lifr.lifr_ip_muxid = ip_muxid; 1112 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 1113 errno = save_errno; 1114 } 1115 /* 1116 * See the comment before the SIOCGLIFGROUPNAME call. 1117 */ 1118 if (errno == EBUSY && (flags & IFF_IPMP)) 1119 goto again; 1120 1121 ret = ipadm_errno2status(errno); 1122 } 1123 done: 1124 if (muxid_fd != -1) 1125 (void) close(muxid_fd); 1126 if (mux_fd != -1) 1127 (void) close(mux_fd); 1128 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 = 1176 (ipadm_flags & IPADM_OPT_PERSIST); 1177 1178 ret = i_ipadm_unplumb_if(iph, ifname, af); 1179 if (ret != IPADM_SUCCESS) 1180 goto done; 1181 1182 cp = strrchr(ifname, IPADM_LOGICAL_SEP); 1183 if (cp != NULL) { 1184 assert(iph->iph_flags & IPH_LEGACY); 1185 /* 1186 * This is a non-zero logical interface. 1187 * Find the addrobj and remove it from the daemon's memory. 1188 */ 1189 (void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname)); 1190 tmp_ifname[cp - ifname] = '\0'; 1191 *cp++ = '\0'; 1192 ipaddr.ipadm_lifnum = atoi(cp); 1193 (void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname, 1194 sizeof (ipaddr.ipadm_ifname)); 1195 ipaddr.ipadm_af = af; 1196 ret = i_ipadm_get_lif2addrobj(iph, &ipaddr); 1197 if (ret == IPADM_SUCCESS) { 1198 ret = i_ipadm_delete_addrobj(iph, &ipaddr, 1199 IPADM_OPT_ACTIVE); 1200 } else if (ret == IPADM_NOTFOUND) { 1201 ret = IPADM_SUCCESS; 1202 } 1203 return (ret); 1204 } 1205 done: 1206 /* 1207 * Even if interface does not exist, remove all its addresses and 1208 * properties from the persistent store. If interface does not 1209 * exist both in kernel and the persistent store, return IPADM_ENXIO. 1210 */ 1211 if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) { 1212 db_status = i_ipadm_delete_ifobj(iph, ifname, af, 1213 is_persistent); 1214 if (db_status == IPADM_SUCCESS) 1215 ret = IPADM_SUCCESS; 1216 } 1217 1218 return (ret); 1219 } 1220 1221 /* 1222 * Resets all addresses on interface `ifname' with address family `af' 1223 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties 1224 * and address objects of `ifname' for `af' are also removed from the 1225 * persistent DB. 1226 */ 1227 ipadm_status_t 1228 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1229 boolean_t is_persistent) 1230 { 1231 ipmgmt_if_arg_t ifarg; 1232 int err; 1233 1234 ifarg.ia_cmd = IPMGMT_CMD_RESETIF; 1235 ifarg.ia_flags = IPMGMT_ACTIVE; 1236 if (is_persistent) 1237 ifarg.ia_flags |= IPMGMT_PERSIST; 1238 ifarg.ia_family = af; 1239 (void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ); 1240 1241 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1242 return (ipadm_errno2status(err)); 1243 } 1244 1245 /* 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, 1299 uint32_t flags) 1300 { 1301 ipadm_status_t status; 1302 boolean_t created_v4 = B_FALSE; 1303 char newifname[LIFNAMSIZ]; 1304 1305 /* Check for the required authorization */ 1306 if (!ipadm_check_auth()) 1307 return (IPADM_EAUTH); 1308 1309 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) && 1310 !(flags & IPADM_OPT_ACTIVE)) || 1311 (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP | 1312 IPADM_OPT_GENPPA))) { 1313 return (IPADM_INVALID_ARG); 1314 } 1315 if (flags & IPADM_OPT_GENPPA) { 1316 if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >= 1317 LIFNAMSIZ) 1318 return (IPADM_INVALID_ARG); 1319 } else { 1320 if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ) 1321 return (IPADM_INVALID_ARG); 1322 } 1323 1324 if (!i_ipadm_validate_ifname(iph, newifname)) 1325 return (IPADM_INVALID_ARG); 1326 1327 if ((af == AF_INET || af == AF_UNSPEC) && 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 1369 if (af == AF_INET || af == AF_UNSPEC) 1370 status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags); 1371 if (af == AF_INET6 || af == AF_UNSPEC) 1372 status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags); 1373 /* 1374 * If the family has been uniquely identified, we return the 1375 * associated status, even if that is ENXIO. Calls from ifconfig 1376 * which can only unplumb one of IPv4/IPv6 at any time fall under 1377 * this category. 1378 */ 1379 if (af == AF_INET) 1380 return (status1); 1381 else if (af == AF_INET6) 1382 return (status2); 1383 else if (af != AF_UNSPEC) 1384 return (IPADM_INVALID_ARG); 1385 1386 /* 1387 * If af is AF_UNSPEC, then we return the following: 1388 * status1, if status1 == status2 1389 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS 1390 * and the other status is ENXIO 1391 * IPADM_ENXIO, if both status1 and status2 are ENXIO 1392 * IPADM_FAILURE otherwise. 1393 */ 1394 if (status1 == status2) { 1395 /* covers the case when both status1 and status2 are ENXIO */ 1396 return (status1); 1397 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1398 if (status1 == IPADM_SUCCESS) 1399 other = status2; 1400 else 1401 other = status1; 1402 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1403 } else { 1404 return (IPADM_FAILURE); 1405 } 1406 } 1407 1408 /* 1409 * Returns information about all interfaces in both active and persistent 1410 * configuration. If `ifname' is not NULL, it returns only the interface 1411 * identified by `ifname'. 1412 * 1413 * Return values: 1414 * On success: IPADM_SUCCESS. 1415 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE. 1416 */ 1417 ipadm_status_t 1418 ipadm_if_info(ipadm_handle_t iph, const char *ifname, 1419 ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags) 1420 { 1421 ipadm_status_t status; 1422 ifspec_t ifsp; 1423 1424 if (if_info == NULL || iph == NULL || flags != 0) 1425 return (IPADM_INVALID_ARG); 1426 1427 if (ifname != NULL && 1428 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) { 1429 return (IPADM_INVALID_ARG); 1430 } 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 1505 nvlist_free(ifnvl); 1506 return (status); 1507 } 1508 1509 /* 1510 * Disable the interface `ifname' by removing it from the active configuration. 1511 * Error code return values follow the model in ipadm_delete_if() 1512 */ 1513 ipadm_status_t 1514 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1515 { 1516 ipadm_status_t status1, status2, other; 1517 ifspec_t ifsp; 1518 1519 /* Check for the required authorization */ 1520 if (!ipadm_check_auth()) 1521 return (IPADM_EAUTH); 1522 1523 /* Check for logical interfaces. */ 1524 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1525 return (IPADM_INVALID_ARG); 1526 1527 /* Disabling an interface persistently is not supported. */ 1528 if (flags & IPADM_OPT_PERSIST) 1529 return (IPADM_NOTSUP); 1530 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 } 1566