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