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