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 (ifap->ifa_addr->sa_family == AF_LINK) 280 continue; 281 if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0) 282 break; 283 } 284 if (ifap == NULL) { 285 /* 286 * The interface might have been removed 287 * from kernel. Retry getting all the active 288 * interfaces. 289 */ 290 freeifaddrs(ifa); 291 ipadm_free_if_info(aifinfo); 292 aifinfo = NULL; 293 goto retry; 294 } 295 if (!(ifap->ifa_flags & IFF_RUNNING) || 296 (ifap->ifa_flags & IFF_FAILED)) 297 aifp->ifi_state = IFIS_FAILED; 298 else if (ifap->ifa_flags & IFF_OFFLINE) 299 aifp->ifi_state = IFIS_OFFLINE; 300 else if (i_ipadm_is_if_down(aifp->ifi_name, ifa)) 301 aifp->ifi_state = IFIS_DOWN; 302 else 303 aifp->ifi_state = IFIS_OK; 304 if (aifp->ifi_next == NULL) 305 last = aifp; 306 } 307 freeifaddrs(ifa); 308 } 309 /* 310 * Get the persistent interface information in `pifinfo'. 311 */ 312 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo); 313 if (status == IPADM_NOTFOUND) { 314 *if_info = aifinfo; 315 return (IPADM_SUCCESS); 316 } 317 if (status != IPADM_SUCCESS) 318 goto fail; 319 /* 320 * If a persistent interface is also found in `aifinfo', update 321 * its entry in `aifinfo' with the persistent information from 322 * `pifinfo'. If an interface is found in `pifinfo', but not in 323 * `aifinfo', it means that this interface was disabled. We should 324 * add this interface to `aifinfo' and set it state to IFIF_DISABLED. 325 */ 326 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) { 327 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { 328 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) { 329 aifp->ifi_pflags = pifp->ifi_pflags; 330 break; 331 } 332 } 333 if (aifp == NULL) { 334 aifp = malloc(sizeof (ipadm_if_info_t)); 335 if (aifp == NULL) { 336 status = ipadm_errno2status(errno); 337 goto fail; 338 } 339 *aifp = *pifp; 340 aifp->ifi_next = NULL; 341 aifp->ifi_state = IFIS_DISABLED; 342 if (last != NULL) 343 last->ifi_next = aifp; 344 else 345 aifinfo = aifp; 346 last = aifp; 347 } 348 } 349 *if_info = aifinfo; 350 ipadm_free_if_info(pifinfo); 351 return (IPADM_SUCCESS); 352 fail: 353 *if_info = NULL; 354 ipadm_free_if_info(aifinfo); 355 ipadm_free_if_info(pifinfo); 356 return (status); 357 } 358 359 int 360 i_ipadm_get_lnum(const char *ifname) 361 { 362 char *num = strrchr(ifname, IPADM_LOGICAL_SEP); 363 364 if (num == NULL) 365 return (0); 366 367 return (atoi(++num)); 368 } 369 370 /* 371 * Sets the output argument `exists' to true or false based on whether 372 * any persistent configuration is available for `ifname' and returns 373 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved, 374 * `exists' is unmodified and an error status is returned. 375 */ 376 ipadm_status_t 377 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af, 378 boolean_t *exists) 379 { 380 ipadm_if_info_t *ifinfo; 381 ipadm_status_t status; 382 383 /* 384 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already 385 * knows about persistent configuration in the first place, so we 386 * just return success. 387 */ 388 if (iph->iph_flags & IPH_IPMGMTD) { 389 *exists = B_FALSE; 390 return (IPADM_SUCCESS); 391 } 392 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo); 393 if (status == IPADM_SUCCESS) { 394 *exists = ((af == AF_INET && 395 (ifinfo->ifi_pflags & IFIF_IPV4)) || 396 (af == AF_INET6 && 397 (ifinfo->ifi_pflags & IFIF_IPV6))); 398 free(ifinfo); 399 } else if (status == IPADM_NOTFOUND) { 400 status = IPADM_SUCCESS; 401 *exists = B_FALSE; 402 } 403 return (status); 404 } 405 406 /* 407 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream 408 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let 409 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at 410 * the bottom of the stream for tunneling interfaces. 411 */ 412 ipadm_status_t 413 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd) 414 { 415 int err; 416 417 if ((*fd = open(udp_dev_name, O_RDWR)) == -1) 418 return (ipadm_errno2status(errno)); 419 420 /* 421 * Pop off all undesired modules (note that the user may have 422 * configured autopush to add modules above udp), and push the 423 * arp module onto the resulting stream. This is used to make 424 * IP+ARP be able to atomically track the muxid for the I_PLINKed 425 * STREAMS, thus it isn't related to ARP running the ARP protocol. 426 */ 427 while (ioctl(*fd, I_POP, 0) != -1) 428 ; 429 if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1) 430 return (IPADM_SUCCESS); 431 err = errno; 432 (void) close(*fd); 433 434 return (ipadm_errno2status(err)); 435 } 436 437 /* 438 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an 439 * underlying interface in an ipmp group G is plumbed for an address family, 440 * but the meta-interface for the other address family `af' does not exist 441 * yet for the group G. If `af' is IPv6, we need to bring up the 442 * link-local address. 443 */ 444 static ipadm_status_t 445 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af, 446 const char *grname, uint32_t ipadm_flags) 447 { 448 ipadm_status_t status; 449 struct lifreq lifr; 450 int sock; 451 int err; 452 453 assert(ipadm_flags & IPADM_OPT_IPMP); 454 455 /* Create the ipmp underlying interface */ 456 status = i_ipadm_create_if(iph, ifname, af, ipadm_flags); 457 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) 458 return (status); 459 460 /* 461 * To preserve backward-compatibility, always bring up the link-local 462 * address for implicitly-created IPv6 IPMP interfaces. 463 */ 464 if (af == AF_INET6) 465 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0); 466 467 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 468 /* 469 * If the caller requested a different group name, issue a 470 * SIOCSLIFGROUPNAME on the new IPMP interface. 471 */ 472 bzero(&lifr, sizeof (lifr)); 473 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 474 if (strcmp(lifr.lifr_name, grname) != 0) { 475 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ); 476 if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) { 477 err = errno; 478 /* Remove the interface we created. */ 479 if (status == IPADM_SUCCESS) { 480 (void) i_ipadm_delete_if(iph, ifname, af, 481 ipadm_flags); 482 } 483 return (ipadm_errno2status(err)); 484 } 485 } 486 487 return (IPADM_SUCCESS); 488 } 489 490 /* 491 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address 492 * family. If so, create a matching IPMP group for address family `af'. 493 */ 494 static ipadm_status_t 495 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af) 496 { 497 lifgroupinfo_t lifgr; 498 ipadm_status_t status = IPADM_SUCCESS; 499 struct lifreq lifr; 500 int other_af_sock; 501 502 assert(af == AF_INET || af == AF_INET6); 503 504 other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock); 505 506 /* 507 * iph is the handle for the interface that we are trying to plumb. 508 * other_af_sock is the socket for the "other" address family. 509 */ 510 bzero(&lifr, sizeof (lifr)); 511 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 512 if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0) 513 return (IPADM_SUCCESS); 514 515 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ); 516 if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0) 517 return (IPADM_SUCCESS); 518 519 /* 520 * If `ifname' *is* the IPMP group interface, or if the relevant 521 * address family is already configured, then there's nothing to do. 522 */ 523 if (strcmp(lifgr.gi_grifname, ifname) == 0 || 524 (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) { 525 return (IPADM_SUCCESS); 526 } 527 528 status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af, 529 lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP); 530 return (status); 531 } 532 533 /* 534 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd. 535 */ 536 static ipadm_status_t 537 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd) 538 { 539 struct lifreq lifr; 540 ifspec_t ifsp; 541 542 bzero(&lifr, sizeof (lifr)); 543 (void) ifparse_ifspec(ifname, &ifsp); 544 lifr.lifr_ppa = ifsp.ifsp_ppa; 545 lifr.lifr_flags = flags; 546 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 547 /* 548 * Tell ARP the name and unit number for this interface. 549 * Note that arp has no support for transparent ioctls. 550 */ 551 if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr, 552 sizeof (lifr)) == -1) { 553 return (ipadm_errno2status(errno)); 554 } 555 return (IPADM_SUCCESS); 556 } 557 558 /* 559 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in 560 * `ipadm_flags', then a ppa will be generated. `newif' will be updated 561 * with the generated ppa. 562 */ 563 static ipadm_status_t 564 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags, 565 int fd, uint32_t ipadm_flags) 566 { 567 struct lifreq lifr; 568 ipadm_status_t status = IPADM_SUCCESS; 569 int err = 0; 570 sa_family_t af; 571 int ppa; 572 ifspec_t ifsp; 573 boolean_t valid_if; 574 575 bzero(&lifr, sizeof (lifr)); 576 if (ipadm_flags & IPADM_OPT_GENPPA) { 577 /* 578 * We'd like to just set lifr_ppa to UINT_MAX and have the 579 * kernel pick a PPA. Unfortunately, that would mishandle 580 * two cases: 581 * 582 * 1. If the PPA is available but the groupname is taken 583 * (e.g., the "ipmp2" IP interface name is available 584 * but the "ipmp2" groupname is taken) then the 585 * auto-assignment by the kernel will fail. 586 * 587 * 2. If we're creating (e.g.) an IPv6-only IPMP 588 * interface, and there's already an IPv4-only IPMP 589 * interface, the kernel will allow us to accidentally 590 * reuse the IPv6 IPMP interface name (since 591 * SIOCSLIFNAME uniqueness is per-interface-type). 592 * This will cause administrative confusion. 593 * 594 * Thus, we instead take a brute-force approach of checking 595 * whether the IPv4 or IPv6 name is already in-use before 596 * attempting the SIOCSLIFNAME. As per (1) above, the 597 * SIOCSLIFNAME may still fail, in which case we just proceed 598 * to the next one. If this approach becomes too slow, we 599 * can add a new SIOC* to handle this case in the kernel. 600 */ 601 for (ppa = 0; ppa < UINT_MAX; ppa++) { 602 (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d", 603 ifname, ppa); 604 605 if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 || 606 errno != ENXIO) 607 continue; 608 609 if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 || 610 errno != ENXIO) 611 continue; 612 613 lifr.lifr_ppa = ppa; 614 lifr.lifr_flags = flags; 615 616 err = ioctl(fd, SIOCSLIFNAME, &lifr); 617 if (err != -1 || errno != EEXIST) 618 break; 619 } 620 if (err == -1) { 621 status = ipadm_errno2status(errno); 622 } else { 623 /* 624 * PPA has been successfully established. 625 * Update `newif' with the ppa. 626 */ 627 assert(newif != NULL); 628 if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname, 629 ppa) >= LIFNAMSIZ) 630 return (IPADM_INVALID_ARG); 631 } 632 } else { 633 /* We should have already validated the interface name. */ 634 valid_if = ifparse_ifspec(ifname, &ifsp); 635 assert(valid_if); 636 637 /* 638 * Before we call SIOCSLIFNAME, ensure that the IPMP group 639 * interface for this address family exists. Otherwise, the 640 * kernel will kick the interface out of the group when we do 641 * the SIOCSLIFNAME. 642 * 643 * Example: suppose bge0 is plumbed for IPv4 and in group "a". 644 * If we're now plumbing bge0 for IPv6, but the IPMP group 645 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME 646 * will kick bge0 out of group "a", which is undesired. 647 */ 648 if (flags & IFF_IPV4) 649 af = AF_INET; 650 else 651 af = AF_INET6; 652 status = i_ipadm_create_ipmp_peer(iph, ifname, af); 653 if (status != IPADM_SUCCESS) 654 return (status); 655 lifr.lifr_ppa = ifsp.ifsp_ppa; 656 lifr.lifr_flags = flags; 657 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 658 if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1) 659 status = ipadm_errno2status(errno); 660 } 661 662 return (status); 663 } 664 665 /* 666 * Plumbs the interface `ifname' for the address family `af'. It also persists 667 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'. 668 */ 669 ipadm_status_t 670 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 671 uint32_t ipadm_flags) 672 { 673 int ip_muxid; 674 int mux_fd = -1, ip_fd, arp_fd; 675 char *udp_dev_name; 676 dlpi_handle_t dh_arp = NULL, dh_ip; 677 uint64_t ifflags; 678 struct lifreq lifr; 679 uint_t dlpi_flags; 680 ipadm_status_t status = IPADM_SUCCESS; 681 char *linkname; 682 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 683 zoneid_t zoneid; 684 char newif[LIFNAMSIZ]; 685 char lifname[LIFNAMSIZ]; 686 datalink_id_t linkid; 687 int sock; 688 boolean_t islo; 689 boolean_t is_persistent = 690 ((ipadm_flags & IPADM_OPT_PERSIST) != 0); 691 uint32_t dlflags; 692 dladm_status_t dlstatus; 693 694 if (iph->iph_dlh != NULL) { 695 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, 696 &dlflags, NULL, NULL); 697 } 698 /* 699 * If we're in the global zone and we're plumbing a datalink, make 700 * sure that the datalink is not assigned to a non-global zone. Note 701 * that the non-global zones don't need this check, because zoneadm 702 * has taken care of this when the zones boot. 703 */ 704 if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) { 705 zoneid = ALL_ZONES; 706 if (zone_check_datalink(&zoneid, linkid) == 0) { 707 /* interface is in use by a non-global zone. */ 708 return (IPADM_IF_INUSE); 709 } 710 } 711 712 /* loopback interfaces are just added as logical interface */ 713 bzero(&lifr, sizeof (lifr)); 714 islo = i_ipadm_is_loopback(ifname); 715 if (islo || i_ipadm_get_lnum(ifname) != 0) { 716 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 717 if (af == AF_INET) 718 sock = iph->iph_sock; 719 else 720 sock = iph->iph_sock6; 721 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) 722 return (IPADM_IF_EXISTS); 723 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 724 return (ipadm_errno2status(errno)); 725 726 /* 727 * By default, kernel configures 127.0.0.1 on the loopback 728 * interface. Replace this with 0.0.0.0 to be consistent 729 * with interface creation on other physical interfaces. 730 */ 731 if (islo && !legacy) { 732 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); 733 lifr.lifr_addr.ss_family = af; 734 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 735 return (ipadm_errno2status(errno)); 736 if (is_persistent) { 737 status = i_ipadm_persist_if(iph, ifname, af); 738 if (status != IPADM_SUCCESS) { 739 (void) i_ipadm_delete_if(iph, ifname, 740 af, IPADM_OPT_ACTIVE); 741 } 742 } 743 } 744 return (status); 745 } 746 747 dlpi_flags = DLPI_NOATTACH; 748 749 /* 750 * If IPADM_OPT_IPMP is specified, then this is a request 751 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply 752 * pass "ipmpstub0" as devname since an admin *could* have a normal 753 * vanity-named link named "ipmpstub0" that they'd like to plumb.) 754 */ 755 if (ipadm_flags & IPADM_OPT_IPMP) { 756 dlpi_flags |= DLPI_DEVONLY; 757 linkname = "ipmpstub0"; 758 } else { 759 /* 760 * Verify that the user is not creating a persistent 761 * IP interface on a non-persistent data-link. 762 */ 763 if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK && 764 is_persistent && !(dlflags & DLADM_OPT_PERSIST)) { 765 return (IPADM_TEMPORARY_OBJ); 766 } 767 linkname = ifname; 768 } 769 770 /* 771 * We use DLPI_NOATTACH because the ip module will do the attach 772 * itself for DLPI style-2 devices. 773 */ 774 if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS) 775 return (IPADM_DLPI_FAILURE); 776 ip_fd = dlpi_fd(dh_ip); 777 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) { 778 status = ipadm_errno2status(errno); 779 goto done; 780 } 781 782 /* 783 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications 784 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL. 785 */ 786 ifflags = 0; 787 788 /* Set the name string and the IFF_IPV* flag */ 789 if (af == AF_INET) { 790 ifflags = IFF_IPV4; 791 } else { 792 ifflags = IFF_IPV6; 793 /* 794 * With the legacy method, the link-local address should be 795 * configured as part of the interface plumb, using the default 796 * token. If IPH_LEGACY is not specified, we want to set :: as 797 * the address and require the admin to explicitly call 798 * ipadm_create_addr() with the address object type set to 799 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address 800 * as well as the autoconfigured addresses. 801 */ 802 if (!legacy && !i_ipadm_is_6to4(iph, ifname)) 803 ifflags |= IFF_NOLINKLOCAL; 804 } 805 (void) strlcpy(newif, ifname, sizeof (newif)); 806 status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd, 807 ipadm_flags); 808 if (status != IPADM_SUCCESS) 809 goto done; 810 811 /* Get the full set of existing flags for this stream */ 812 status = i_ipadm_get_flags(iph, newif, af, &ifflags); 813 if (status != IPADM_SUCCESS) 814 goto done; 815 816 udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME); 817 status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 818 if (status != IPADM_SUCCESS) 819 goto done; 820 821 /* Check if arp is not needed */ 822 if (ifflags & (IFF_NOARP|IFF_IPV6)) { 823 /* 824 * PLINK the interface stream so that the application can exit 825 * without tearing down the stream. 826 */ 827 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 828 status = ipadm_errno2status(errno); 829 goto done; 830 } 831 832 /* 833 * This interface does use ARP, so set up a separate stream 834 * from the interface to ARP. 835 * 836 * We use DLPI_NOATTACH because the arp module will do the attach 837 * itself for DLPI style-2 devices. 838 */ 839 if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) { 840 status = IPADM_DLPI_FAILURE; 841 goto done; 842 } 843 844 arp_fd = dlpi_fd(dh_arp); 845 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) { 846 status = ipadm_errno2status(errno); 847 goto done; 848 } 849 850 status = i_ipadm_slifname_arp(newif, ifflags, arp_fd); 851 if (status != IPADM_SUCCESS) 852 goto done; 853 /* 854 * PLINK the IP and ARP streams so that ifconfig can exit 855 * without tearing down the stream. 856 */ 857 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 858 status = ipadm_errno2status(errno); 859 goto done; 860 } 861 862 if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) { 863 status = ipadm_errno2status(errno); 864 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 865 } 866 867 done: 868 dlpi_close(dh_ip); 869 if (dh_arp != NULL) 870 dlpi_close(dh_arp); 871 872 if (mux_fd != -1) 873 (void) close(mux_fd); 874 875 if (status == IPADM_SUCCESS) { 876 /* copy back new ifname */ 877 (void) strlcpy(ifname, newif, LIFNAMSIZ); 878 /* 879 * If it is a 6to4 tunnel, create a default 880 * addrobj name for the default address on the 0'th 881 * logical interface and set IFF_UP in the interface flags. 882 */ 883 if (i_ipadm_is_6to4(iph, ifname)) { 884 struct ipadm_addrobj_s addr; 885 886 i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC); 887 addr.ipadm_af = af; 888 status = i_ipadm_lookupadd_addrobj(iph, &addr); 889 if (status != IPADM_SUCCESS) 890 return (status); 891 status = ipadm_add_aobjname(iph, ifname, 892 af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0); 893 if (status != IPADM_SUCCESS) 894 return (status); 895 addr.ipadm_lifnum = 0; 896 i_ipadm_addrobj2lifname(&addr, lifname, 897 sizeof (lifname)); 898 status = i_ipadm_set_flags(iph, lifname, af, 899 IFF_UP, 0); 900 if (status != IPADM_SUCCESS) 901 return (status); 902 } else { 903 /* 904 * Prevent static IPv6 addresses from triggering 905 * autoconf. This does not have to be done for 906 * 6to4 tunnel interfaces, since in.ndpd will 907 * not autoconfigure those interfaces. 908 */ 909 if (af == AF_INET6 && !legacy) 910 (void) i_ipadm_disable_autoconf(newif); 911 } 912 913 /* 914 * If IPADM_OPT_PERSIST was set in flags, store the 915 * interface in persistent DB. 916 */ 917 if (is_persistent) { 918 status = i_ipadm_persist_if(iph, newif, af); 919 if (status != IPADM_SUCCESS) { 920 (void) i_ipadm_delete_if(iph, newif, af, 921 IPADM_OPT_ACTIVE); 922 } 923 } 924 } 925 if (status == IPADM_EXISTS) 926 status = IPADM_IF_EXISTS; 927 return (status); 928 } 929 930 /* 931 * Unplumbs the interface in `ifname' of family `af'. 932 */ 933 ipadm_status_t 934 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af) 935 { 936 int ip_muxid, arp_muxid; 937 int mux_fd = -1; 938 int muxid_fd = -1; 939 char *udp_dev_name; 940 uint64_t flags; 941 boolean_t changed_arp_muxid = B_FALSE; 942 int save_errno; 943 struct lifreq lifr; 944 ipadm_status_t ret = IPADM_SUCCESS; 945 int sock; 946 lifgroupinfo_t lifgr; 947 ifaddrlistx_t *ifaddrs, *ifaddrp; 948 boolean_t v6 = (af == AF_INET6); 949 950 /* Just do SIOCLIFREMOVEIF on loopback interfaces */ 951 bzero(&lifr, sizeof (lifr)); 952 if (i_ipadm_is_loopback(ifname) || 953 (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) { 954 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 955 if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6, 956 SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 957 return (ipadm_errno2status(errno)); 958 } 959 return (IPADM_SUCCESS); 960 } 961 962 /* 963 * We used /dev/udp or udp6 to set up the mux. So we have to use 964 * the same now for PUNLINK also. 965 */ 966 if (v6) { 967 udp_dev_name = UDP6_DEV_NAME; 968 sock = iph->iph_sock6; 969 } else { 970 udp_dev_name = UDP_DEV_NAME; 971 sock = iph->iph_sock; 972 } 973 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) { 974 ret = ipadm_errno2status(errno); 975 goto done; 976 } 977 ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 978 if (ret != IPADM_SUCCESS) 979 goto done; 980 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 981 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 982 ret = ipadm_errno2status(errno); 983 goto done; 984 } 985 flags = lifr.lifr_flags; 986 again: 987 if (flags & IFF_IPMP) { 988 /* 989 * There are two reasons the I_PUNLINK can fail with EBUSY: 990 * (1) if IP interfaces are in the group, or (2) if IPMP data 991 * addresses are administratively up. For case (1), we fail 992 * here with a specific error message. For case (2), we bring 993 * down the addresses prior to doing the I_PUNLINK. If the 994 * I_PUNLINK still fails with EBUSY then the configuration 995 * must have changed after our checks, in which case we branch 996 * back up to `again' and rerun this logic. The net effect is 997 * that unplumbing an IPMP interface will only fail with EBUSY 998 * if IP interfaces are in the group. 999 */ 1000 if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) { 1001 ret = ipadm_errno2status(errno); 1002 goto done; 1003 } 1004 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, 1005 LIFGRNAMSIZ); 1006 if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) { 1007 ret = ipadm_errno2status(errno); 1008 goto done; 1009 } 1010 if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) { 1011 ret = IPADM_GRP_NOTEMPTY; 1012 goto done; 1013 } 1014 1015 /* 1016 * The kernel will fail the I_PUNLINK if the IPMP interface 1017 * has administratively up addresses; bring them down. 1018 */ 1019 if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE, 1020 0, &ifaddrs) == -1) { 1021 ret = ipadm_errno2status(errno); 1022 goto done; 1023 } 1024 ifaddrp = ifaddrs; 1025 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 1026 int sock = (ifaddrp->ia_flags & IFF_IPV4) ? 1027 iph->iph_sock : iph->iph_sock6; 1028 struct lifreq lifrl; 1029 1030 if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) || 1031 (!(ifaddrp->ia_flags & IFF_IPV6) && v6)) 1032 continue; 1033 1034 bzero(&lifrl, sizeof (lifrl)); 1035 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name, 1036 sizeof (lifrl.lifr_name)); 1037 if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) { 1038 ret = ipadm_errno2status(errno); 1039 ifaddrlistx_free(ifaddrs); 1040 goto done; 1041 } 1042 if (lifrl.lifr_flags & IFF_UP) { 1043 ret = i_ipadm_set_flags(iph, lifrl.lifr_name, 1044 ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET : 1045 AF_INET6), 0, IFF_UP); 1046 if (ret != IPADM_SUCCESS) { 1047 ifaddrlistx_free(ifaddrs); 1048 goto done; 1049 } 1050 } else if (lifrl.lifr_flags & IFF_DUPLICATE) { 1051 if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 || 1052 ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) { 1053 ret = ipadm_errno2status(errno); 1054 ifaddrlistx_free(ifaddrs); 1055 goto done; 1056 } 1057 } 1058 } 1059 ifaddrlistx_free(ifaddrs); 1060 } 1061 1062 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 1063 ret = ipadm_errno2status(errno); 1064 goto done; 1065 } 1066 arp_muxid = lifr.lifr_arp_muxid; 1067 ip_muxid = lifr.lifr_ip_muxid; 1068 1069 /* 1070 * We don't have a good way of knowing whether the arp stream is 1071 * plumbed. We can't rely on IFF_NOARP because someone could 1072 * have turned it off later using "ifconfig xxx -arp". 1073 */ 1074 if (arp_muxid != 0) { 1075 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 1076 /* 1077 * See the comment before the SIOCGLIFGROUPNAME call. 1078 */ 1079 if (errno == EBUSY && (flags & IFF_IPMP)) 1080 goto again; 1081 1082 if ((errno == EINVAL) && 1083 (flags & (IFF_NOARP | IFF_IPV6))) { 1084 /* 1085 * Some plumbing utilities set the muxid to 1086 * -1 or some invalid value to signify that 1087 * there is no arp stream. Set the muxid to 0 1088 * before trying to unplumb the IP stream. 1089 * IP does not allow the IP stream to be 1090 * unplumbed if it sees a non-null arp muxid, 1091 * for consistency of IP-ARP streams. 1092 */ 1093 lifr.lifr_arp_muxid = 0; 1094 (void) ioctl(muxid_fd, SIOCSLIFMUXID, 1095 (caddr_t)&lifr); 1096 changed_arp_muxid = B_TRUE; 1097 } 1098 /* 1099 * In case of any other error, we continue with 1100 * the unplumb. 1101 */ 1102 } 1103 } 1104 1105 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 1106 if (changed_arp_muxid) { 1107 /* 1108 * Some error occurred, and we need to restore 1109 * everything back to what it was. 1110 */ 1111 save_errno = errno; 1112 lifr.lifr_arp_muxid = arp_muxid; 1113 lifr.lifr_ip_muxid = ip_muxid; 1114 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 1115 errno = save_errno; 1116 } 1117 /* 1118 * See the comment before the SIOCGLIFGROUPNAME call. 1119 */ 1120 if (errno == EBUSY && (flags & IFF_IPMP)) 1121 goto again; 1122 1123 ret = ipadm_errno2status(errno); 1124 } 1125 done: 1126 if (muxid_fd != -1) 1127 (void) close(muxid_fd); 1128 if (mux_fd != -1) 1129 (void) close(mux_fd); 1130 1131 if (af == AF_INET6 && ret == IPADM_SUCCESS) { 1132 /* 1133 * in.ndpd maintains the phyints in its memory even after 1134 * the interface is plumbed, so that it can be reused when 1135 * the interface gets plumbed again. The default behavior 1136 * of in.ndpd is to start autoconfiguration for an interface 1137 * that gets plumbed. We need to send the 1138 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this 1139 * default behavior on replumb. 1140 */ 1141 (void) i_ipadm_enable_autoconf(ifname); 1142 } 1143 return (ret); 1144 } 1145 1146 /* 1147 * Saves the given interface name `ifname' with address family `af' in 1148 * persistent DB. 1149 */ 1150 static ipadm_status_t 1151 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af) 1152 { 1153 ipmgmt_if_arg_t ifarg; 1154 int err; 1155 1156 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname)); 1157 ifarg.ia_family = af; 1158 ifarg.ia_cmd = IPMGMT_CMD_SETIF; 1159 ifarg.ia_flags = IPMGMT_PERSIST; 1160 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1161 return (ipadm_errno2status(err)); 1162 } 1163 1164 /* 1165 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST 1166 * is set in `ipadm_flags', it is also removed from persistent configuration. 1167 */ 1168 ipadm_status_t 1169 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1170 uint32_t ipadm_flags) 1171 { 1172 ipadm_status_t ret = IPADM_SUCCESS; 1173 ipadm_status_t db_status; 1174 char tmp_ifname[LIFNAMSIZ]; 1175 char *cp; 1176 struct ipadm_addrobj_s ipaddr; 1177 boolean_t is_persistent = 1178 (ipadm_flags & IPADM_OPT_PERSIST); 1179 1180 ret = i_ipadm_unplumb_if(iph, ifname, af); 1181 if (ret != IPADM_SUCCESS) 1182 goto done; 1183 1184 cp = strrchr(ifname, IPADM_LOGICAL_SEP); 1185 if (cp != NULL) { 1186 assert(iph->iph_flags & IPH_LEGACY); 1187 /* 1188 * This is a non-zero logical interface. 1189 * Find the addrobj and remove it from the daemon's memory. 1190 */ 1191 (void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname)); 1192 tmp_ifname[cp - ifname] = '\0'; 1193 *cp++ = '\0'; 1194 ipaddr.ipadm_lifnum = atoi(cp); 1195 (void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname, 1196 sizeof (ipaddr.ipadm_ifname)); 1197 ipaddr.ipadm_af = af; 1198 ret = i_ipadm_get_lif2addrobj(iph, &ipaddr); 1199 if (ret == IPADM_SUCCESS) { 1200 ret = i_ipadm_delete_addrobj(iph, &ipaddr, 1201 IPADM_OPT_ACTIVE); 1202 } else if (ret == IPADM_NOTFOUND) { 1203 ret = IPADM_SUCCESS; 1204 } 1205 return (ret); 1206 } 1207 done: 1208 /* 1209 * Even if interface does not exist, remove all its addresses and 1210 * properties from the persistent store. If interface does not 1211 * exist both in kernel and the persistent store, return IPADM_ENXIO. 1212 */ 1213 if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) { 1214 db_status = i_ipadm_delete_ifobj(iph, ifname, af, 1215 is_persistent); 1216 if (db_status == IPADM_SUCCESS) 1217 ret = IPADM_SUCCESS; 1218 } 1219 1220 return (ret); 1221 } 1222 1223 /* 1224 * Resets all addresses on interface `ifname' with address family `af' 1225 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties 1226 * and address objects of `ifname' for `af' are also removed from the 1227 * persistent DB. 1228 */ 1229 ipadm_status_t 1230 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1231 boolean_t is_persistent) 1232 { 1233 ipmgmt_if_arg_t ifarg; 1234 int err; 1235 1236 ifarg.ia_cmd = IPMGMT_CMD_RESETIF; 1237 ifarg.ia_flags = IPMGMT_ACTIVE; 1238 if (is_persistent) 1239 ifarg.ia_flags |= IPMGMT_PERSIST; 1240 ifarg.ia_family = af; 1241 (void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ); 1242 1243 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1244 return (ipadm_errno2status(err)); 1245 } 1246 1247 /* 1248 * Create the interface by plumbing it for IP. 1249 * This function will check if there is saved configuration information 1250 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space 1251 * for `ifname' is taken. 1252 */ 1253 ipadm_status_t 1254 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 1255 uint32_t ipadm_flags) 1256 { 1257 ipadm_status_t status; 1258 boolean_t p_exists; 1259 sa_family_t other_af; 1260 1261 /* 1262 * Return error, if the interface already exists in either the active 1263 * or the persistent configuration. 1264 */ 1265 if (ipadm_if_enabled(iph, ifname, af)) 1266 return (IPADM_IF_EXISTS); 1267 1268 if (!(iph->iph_flags & IPH_LEGACY)) { 1269 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 1270 if (status != IPADM_SUCCESS) 1271 return (status); 1272 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 1273 if (p_exists) { 1274 if (!ipadm_if_enabled(iph, ifname, other_af)) 1275 return (IPADM_OP_DISABLE_OBJ); 1276 else 1277 ipadm_flags &= ~IPADM_OPT_PERSIST; 1278 } 1279 } 1280 1281 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags)); 1282 } 1283 1284 /* 1285 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by 1286 * default, unless a value in `af' is specified. The interface may be plumbed 1287 * only if there is no previously saved persistent configuration information 1288 * for the interface (in which case the ipadm_enable_if() function must 1289 * be used to enable the interface). 1290 * 1291 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS, 1292 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE, 1293 * or appropriate ipadm_status_t corresponding to the errno. 1294 * 1295 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may 1296 * be over-written with the actual interface name when a PPA has to be 1297 * internally generated by the library. 1298 */ 1299 ipadm_status_t 1300 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 1301 uint32_t flags) 1302 { 1303 ipadm_status_t status; 1304 boolean_t created_v4 = B_FALSE; 1305 char newifname[LIFNAMSIZ]; 1306 1307 /* Check for the required authorization */ 1308 if (!ipadm_check_auth()) 1309 return (IPADM_EAUTH); 1310 1311 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) && 1312 !(flags & IPADM_OPT_ACTIVE)) || 1313 (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP | 1314 IPADM_OPT_GENPPA))) { 1315 return (IPADM_INVALID_ARG); 1316 } 1317 if (flags & IPADM_OPT_GENPPA) { 1318 if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >= 1319 LIFNAMSIZ) 1320 return (IPADM_INVALID_ARG); 1321 } else { 1322 if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ) 1323 return (IPADM_INVALID_ARG); 1324 } 1325 1326 if (!i_ipadm_validate_ifname(iph, newifname)) 1327 return (IPADM_INVALID_ARG); 1328 1329 if ((af == AF_INET || af == AF_UNSPEC) && 1330 !i_ipadm_is_6to4(iph, ifname)) { 1331 status = i_ipadm_create_if(iph, ifname, AF_INET, flags); 1332 if (status != IPADM_SUCCESS) 1333 return (status); 1334 created_v4 = B_TRUE; 1335 } 1336 if (af == AF_INET6 || af == AF_UNSPEC) { 1337 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags); 1338 if (status != IPADM_SUCCESS) { 1339 if (created_v4) { 1340 (void) i_ipadm_delete_if(iph, ifname, AF_INET, 1341 IPADM_OPT_ACTIVE); 1342 } 1343 return (status); 1344 } 1345 } 1346 1347 return (IPADM_SUCCESS); 1348 } 1349 1350 /* 1351 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces 1352 * when `af' = AF_UNSPEC. 1353 */ 1354 ipadm_status_t 1355 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1356 uint32_t flags) 1357 { 1358 ipadm_status_t status1 = IPADM_SUCCESS; 1359 ipadm_status_t status2 = IPADM_SUCCESS; 1360 ipadm_status_t other; 1361 1362 /* Check for the required authorization */ 1363 if (!ipadm_check_auth()) 1364 return (IPADM_EAUTH); 1365 1366 /* Validate the `ifname' for any logical interface. */ 1367 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) || 1368 !i_ipadm_validate_ifname(iph, ifname)) 1369 return (IPADM_INVALID_ARG); 1370 1371 if (af == AF_INET || af == AF_UNSPEC) 1372 status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags); 1373 if (af == AF_INET6 || af == AF_UNSPEC) 1374 status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags); 1375 /* 1376 * If the family has been uniquely identified, we return the 1377 * associated status, even if that is ENXIO. Calls from ifconfig 1378 * which can only unplumb one of IPv4/IPv6 at any time fall under 1379 * this category. 1380 */ 1381 if (af == AF_INET) 1382 return (status1); 1383 else if (af == AF_INET6) 1384 return (status2); 1385 else if (af != AF_UNSPEC) 1386 return (IPADM_INVALID_ARG); 1387 1388 /* 1389 * If af is AF_UNSPEC, then we return the following: 1390 * status1, if status1 == status2 1391 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS 1392 * and the other status is ENXIO 1393 * IPADM_ENXIO, if both status1 and status2 are ENXIO 1394 * IPADM_FAILURE otherwise. 1395 */ 1396 if (status1 == status2) { 1397 /* covers the case when both status1 and status2 are ENXIO */ 1398 return (status1); 1399 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1400 if (status1 == IPADM_SUCCESS) 1401 other = status2; 1402 else 1403 other = status1; 1404 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1405 } else { 1406 return (IPADM_FAILURE); 1407 } 1408 } 1409 1410 /* 1411 * Returns information about all interfaces in both active and persistent 1412 * configuration. If `ifname' is not NULL, it returns only the interface 1413 * identified by `ifname'. 1414 * 1415 * Return values: 1416 * On success: IPADM_SUCCESS. 1417 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE. 1418 */ 1419 ipadm_status_t 1420 ipadm_if_info(ipadm_handle_t iph, const char *ifname, 1421 ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags) 1422 { 1423 ipadm_status_t status; 1424 ifspec_t ifsp; 1425 1426 if (if_info == NULL || iph == NULL || flags != 0) 1427 return (IPADM_INVALID_ARG); 1428 1429 if (ifname != NULL && 1430 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) { 1431 return (IPADM_INVALID_ARG); 1432 } 1433 1434 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags); 1435 if (status != IPADM_SUCCESS) 1436 return (status); 1437 if (ifname != NULL && *if_info == NULL) 1438 return (IPADM_ENXIO); 1439 1440 return (IPADM_SUCCESS); 1441 } 1442 1443 /* 1444 * Frees the linked list allocated by ipadm_if_info(). 1445 */ 1446 void 1447 ipadm_free_if_info(ipadm_if_info_t *ifinfo) 1448 { 1449 ipadm_if_info_t *ifinfo_next; 1450 1451 for (; ifinfo != NULL; ifinfo = ifinfo_next) { 1452 ifinfo_next = ifinfo->ifi_next; 1453 free(ifinfo); 1454 } 1455 } 1456 1457 /* 1458 * Re-enable the interface `ifname' based on the saved configuration 1459 * for `ifname'. 1460 */ 1461 ipadm_status_t 1462 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1463 { 1464 nvlist_t *ifnvl; 1465 ipadm_status_t status; 1466 ifspec_t ifsp; 1467 1468 /* Check for the required authorization */ 1469 if (!ipadm_check_auth()) 1470 return (IPADM_EAUTH); 1471 1472 /* Check for logical interfaces. */ 1473 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1474 return (IPADM_INVALID_ARG); 1475 1476 /* Enabling an interface persistently is not supported. */ 1477 if (flags & IPADM_OPT_PERSIST) 1478 return (IPADM_NOTSUP); 1479 1480 /* 1481 * Return early by checking if the interface is already enabled. 1482 */ 1483 if (ipadm_if_enabled(iph, ifname, AF_INET) && 1484 ipadm_if_enabled(iph, ifname, AF_INET6)) { 1485 return (IPADM_IF_EXISTS); 1486 } 1487 /* 1488 * Enable the interface and restore all its interface properties 1489 * and address objects. 1490 */ 1491 status = i_ipadm_init_ifs(iph, ifname, &ifnvl); 1492 if (status != IPADM_SUCCESS) 1493 return (status); 1494 1495 assert(ifnvl != NULL); 1496 /* 1497 * ipadm_enable_if() does exactly what ipadm_init_ifs() does, 1498 * but only for one interface. We need to set IPH_INIT because 1499 * ipmgmtd daemon does not have to write the interface to persistent 1500 * db. The interface is already available in persistent db 1501 * and we are here to re-enable the persistent configuration. 1502 */ 1503 iph->iph_flags |= IPH_INIT; 1504 status = i_ipadm_init_ifobj(iph, ifname, ifnvl); 1505 iph->iph_flags &= ~IPH_INIT; 1506 1507 nvlist_free(ifnvl); 1508 return (status); 1509 } 1510 1511 /* 1512 * Disable the interface `ifname' by removing it from the active configuration. 1513 * Error code return values follow the model in ipadm_delete_if() 1514 */ 1515 ipadm_status_t 1516 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1517 { 1518 ipadm_status_t status1, status2, other; 1519 ifspec_t ifsp; 1520 1521 /* Check for the required authorization */ 1522 if (!ipadm_check_auth()) 1523 return (IPADM_EAUTH); 1524 1525 /* Check for logical interfaces. */ 1526 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1527 return (IPADM_INVALID_ARG); 1528 1529 /* Disabling an interface persistently is not supported. */ 1530 if (flags & IPADM_OPT_PERSIST) 1531 return (IPADM_NOTSUP); 1532 1533 status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6); 1534 if (status1 == IPADM_SUCCESS) 1535 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE); 1536 status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET); 1537 if (status2 == IPADM_SUCCESS) 1538 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE); 1539 if (status1 == status2) { 1540 return (status2); 1541 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1542 if (status1 == IPADM_SUCCESS) 1543 other = status2; 1544 else 1545 other = status1; 1546 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1547 } else { 1548 return (IPADM_FAILURE); 1549 } 1550 } 1551 1552 /* 1553 * This workaround is until libipadm supports IPMP and is required whenever an 1554 * interface is moved into an IPMP group. Since libipadm doesn't support IPMP 1555 * yet, we will have to update the daemon's in-memory mapping of 1556 * `aobjname' to 'lifnum'. 1557 * 1558 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if 1559 * door_call(3C) fails. Also, there is no use in returning error because 1560 * `ifname' would have been successfuly moved into IPMP group, by this time. 1561 */ 1562 void 1563 ipadm_if_move(ipadm_handle_t iph, const char *ifname) 1564 { 1565 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE); 1566 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE); 1567 } 1568