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 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 25 */ 26 27 #include <errno.h> 28 #include <sys/sockio.h> 29 #include <sys/list.h> 30 #include <string.h> 31 #include <assert.h> 32 #include <unistd.h> 33 #include <stropts.h> 34 #include <strings.h> 35 #include <libdlpi.h> 36 #include <libdllink.h> 37 #include <libinetutil.h> 38 #include <inet/ip.h> 39 #include <limits.h> 40 #include <zone.h> 41 #include <ipadm_ndpd.h> 42 #include <ipmp_query.h> 43 #include "libipadm_impl.h" 44 45 static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int); 46 static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *, 47 uint64_t, int, uint32_t); 48 static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *, 49 sa_family_t); 50 static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *, 51 sa_family_t, uint32_t); 52 static ipadm_status_t i_ipadm_allocate_ifinfo(ipadm_if_info_t **); 53 static ipadm_status_t i_ipadm_get_db_if(ipadm_handle_t, const char *, 54 nvlist_t **); 55 static ipadm_status_t i_ipadm_nvl2ifinfo(nvlist_t *, ipadm_if_info_t **); 56 static ipadm_status_t i_ipadm_fill_cmembers(char *, ipadm_ipmp_members_t *); 57 static ipadm_status_t i_ipadm_fill_pmembers(nvlist_t *, ipadm_ipmp_members_t *); 58 static ipadm_status_t i_ipadm_add_persistent_if_info(ipadm_if_info_t *, 59 ipadm_if_info_t *); 60 static void i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *); 61 static ipadm_status_t i_ipadm_persist_update_ipmp(ipadm_handle_t, const char *, 62 const char *, 63 ipadm_ipmp_op_t); 64 static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *, 65 const char *, uint32_t, 66 ipadm_ipmp_op_t); 67 68 /* 69 * Returns B_FALSE if the interface in `ifname' has at least one address that is 70 * IFF_UP in the addresses in `ifa'. 71 */ 72 static boolean_t 73 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa) 74 { 75 struct ifaddrs *ifap; 76 char cifname[LIFNAMSIZ]; 77 char *sep; 78 79 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 80 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname)); 81 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL) 82 *sep = '\0'; 83 /* 84 * If this condition is true, there is at least one 85 * address that is IFF_UP. So, we need to return B_FALSE. 86 */ 87 if (strcmp(cifname, ifname) == 0 && 88 (ifap->ifa_flags & IFF_UP)) { 89 return (B_FALSE); 90 } 91 } 92 /* We did not find any IFF_UP addresses. */ 93 return (B_TRUE); 94 } 95 96 /* 97 * Retrieves the information for the interface `ifname' from active 98 * config if `ifname' is specified and returns the result in the list `if_info'. 99 * Otherwise, it retrieves the information for all the interfaces in 100 * the active config and returns the result in the list `if_info'. 101 */ 102 static ipadm_status_t 103 i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname, 104 ipadm_if_info_t **if_info, int64_t lifc_flags) 105 { 106 struct lifreq *buf; 107 struct lifreq *lifrp; 108 struct lifreq lifrl; 109 ipadm_if_info_t *last = NULL; 110 ipadm_if_info_t *ifp; 111 int s; 112 int n; 113 int numifs; 114 ipadm_status_t status = IPADM_SUCCESS; 115 116 *if_info = NULL; 117 /* 118 * Get information for all interfaces. 119 */ 120 if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0) 121 return (ipadm_errno2status(errno)); 122 123 lifrp = buf; 124 for (n = 0; n < numifs; n++, lifrp++) { 125 /* Skip interfaces with logical num != 0 */ 126 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0) 127 continue; 128 /* 129 * Skip the current interface if a specific `ifname' has 130 * been requested and current interface does not match 131 * `ifname'. 132 */ 133 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0) 134 continue; 135 /* 136 * Check if the interface already exists in our list. 137 * If it already exists, we need to update its flags. 138 */ 139 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) { 140 if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0) 141 break; 142 } 143 if (ifp == NULL) { 144 if ((status = 145 i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS) 146 break; 147 148 (void) strlcpy(ifp->ifi_name, lifrp->lifr_name, 149 sizeof (ifp->ifi_name)); 150 /* Update the `ifi_next' pointer for this new node */ 151 if (*if_info == NULL) 152 *if_info = ifp; 153 else 154 last->ifi_next = ifp; 155 last = ifp; 156 } 157 158 /* 159 * Retrieve the flags for the interface by doing a 160 * SIOCGLIFFLAGS to populate the `ifi_cflags' field. 161 */ 162 (void) strlcpy(lifrl.lifr_name, 163 lifrp->lifr_name, sizeof (lifrl.lifr_name)); 164 s = (lifrp->lifr_addr.ss_family == AF_INET) ? 165 iph->iph_sock : iph->iph_sock6; 166 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) 167 continue; 168 169 /* a regular interface by default */ 170 ifp->ifi_class = IPADM_IF_CLASS_REGULAR; 171 172 if (lifrl.lifr_flags & IFF_BROADCAST) 173 ifp->ifi_cflags |= IFIF_BROADCAST; 174 if (lifrl.lifr_flags & IFF_MULTICAST) 175 ifp->ifi_cflags |= IFIF_MULTICAST; 176 if (lifrl.lifr_flags & IFF_POINTOPOINT) 177 ifp->ifi_cflags |= IFIF_POINTOPOINT; 178 if (lifrl.lifr_flags & IFF_VIRTUAL) { 179 ifp->ifi_cflags |= IFIF_VIRTUAL; 180 ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL; 181 } 182 if (lifrl.lifr_flags & IFF_IPMP) { 183 ifp->ifi_cflags |= IFIF_IPMP; 184 ifp->ifi_class = IPADM_IF_CLASS_IPMP; 185 } 186 if (lifrl.lifr_flags & IFF_STANDBY) 187 ifp->ifi_cflags |= IFIF_STANDBY; 188 if (lifrl.lifr_flags & IFF_INACTIVE) 189 ifp->ifi_cflags |= IFIF_INACTIVE; 190 if (lifrl.lifr_flags & IFF_VRRP) 191 ifp->ifi_cflags |= IFIF_VRRP; 192 if (lifrl.lifr_flags & IFF_NOACCEPT) 193 ifp->ifi_cflags |= IFIF_NOACCEPT; 194 if (lifrl.lifr_flags & IFF_IPV4) 195 ifp->ifi_cflags |= IFIF_IPV4; 196 if (lifrl.lifr_flags & IFF_IPV6) 197 ifp->ifi_cflags |= IFIF_IPV6; 198 if (lifrl.lifr_flags & IFF_L3PROTECT) 199 ifp->ifi_cflags |= IFIF_L3PROTECT; 200 201 /* 202 * Retrieve active IPMP members. This may fail in in.mpathd if 203 * the IPMP interface has just been created with no members. 204 * Hence, ignore errors, cmembers will just be empty. 205 */ 206 if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) { 207 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifrl) == 0) { 208 (void) i_ipadm_fill_cmembers( 209 lifrl.lifr_groupname, 210 &ifp->ifi_ipmp_cmembers); 211 } 212 } 213 } 214 free(buf); 215 if (status != IPADM_SUCCESS) { 216 ipadm_free_if_info(*if_info); 217 *if_info = NULL; 218 } 219 return (status); 220 } 221 222 /* 223 * Returns the interface information for `ifname' in `if_info' from persistent 224 * config if `ifname' is non-null. Otherwise, it returns all the interfaces 225 * from persistent config in `if_info'. 226 */ 227 static ipadm_status_t 228 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname, 229 ipadm_if_info_t **if_info) 230 { 231 ipadm_status_t status = IPADM_SUCCESS; 232 nvlist_t *ifs_info_nvl; 233 234 *if_info = NULL; 235 236 if ((status = i_ipadm_get_db_if(iph, 237 ifname, &ifs_info_nvl)) != IPADM_SUCCESS) 238 return (status); 239 240 assert(ifs_info_nvl != NULL); 241 242 return (i_ipadm_nvl2ifinfo(ifs_info_nvl, if_info)); 243 } 244 245 static ipadm_status_t 246 i_ipadm_nvl2ifinfo(nvlist_t *ifs_info_nvl, ipadm_if_info_t **if_info) 247 { 248 ipadm_if_info_t *ific = NULL, *ifil = NULL; 249 nvlist_t *if_info_nvl; 250 nvpair_t *nvp; 251 char *strval; 252 ipadm_status_t status = IPADM_SUCCESS; 253 uint16_t *families; 254 uint_t nelem = 0; 255 256 for (nvp = nvlist_next_nvpair(ifs_info_nvl, NULL); nvp != NULL; 257 nvp = nvlist_next_nvpair(ifs_info_nvl, nvp)) { 258 if (nvpair_value_nvlist(nvp, &if_info_nvl) != 0) 259 continue; 260 261 status = i_ipadm_allocate_ifinfo(&ific); 262 if (status != IPADM_SUCCESS) { 263 ipadm_free_if_info(*if_info); 264 break; 265 } 266 if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_IFNAME, 267 &strval) != 0) { 268 ipadm_free_if_info(ific); 269 ific = NULL; 270 continue; 271 } 272 (void) strlcpy(ific->ifi_name, strval, 273 sizeof (ific->ifi_name)); 274 275 if (nvlist_lookup_uint16_array(if_info_nvl, 276 IPADM_NVP_FAMILIES, &families, &nelem) == 0) { 277 while (nelem-- > 0) { 278 if (families[nelem] == AF_INET) 279 ific->ifi_pflags |= IFIF_IPV4; 280 else if (families[nelem] == AF_INET6) 281 ific->ifi_pflags |= IFIF_IPV6; 282 } 283 } 284 285 if (nvlist_lookup_string(if_info_nvl, 286 IPADM_NVP_IFCLASS, &strval) == 0) 287 ific->ifi_class = atoi(strval); 288 else 289 ific->ifi_class = IPADM_IF_CLASS_REGULAR; 290 291 if (ific->ifi_class == IPADM_IF_CLASS_IPMP) 292 /* do not expect any failures there */ 293 (void) i_ipadm_fill_pmembers(if_info_nvl, 294 &ific->ifi_ipmp_pmembers); 295 296 if (*if_info == NULL) 297 *if_info = ific; 298 else 299 ifil->ifi_next = ific; 300 ifil = ific; 301 } 302 303 nvlist_free(ifs_info_nvl); 304 return (status); 305 } 306 307 /* 308 * Fill the ipadm_if_info_t->ifi_ipmp_pmembers by info from 309 * ipadm DB 310 */ 311 static ipadm_status_t 312 i_ipadm_fill_pmembers(nvlist_t *if_info_nvl, ipadm_ipmp_members_t *pmembers) 313 { 314 uint_t nelem = 0; 315 char **members; 316 ipadm_ipmp_member_t *ipmp_member; 317 318 if (nvlist_lookup_string_array(if_info_nvl, IPADM_NVP_MIFNAMES, 319 &members, &nelem) != 0) 320 return (IPADM_SUCCESS); 321 322 while (nelem-- > 0) { 323 if ((ipmp_member = calloc(1, 324 sizeof (ipadm_ipmp_member_t))) == NULL) 325 return (ipadm_errno2status(errno)); 326 327 (void) strlcpy(ipmp_member->if_name, members[nelem], 328 sizeof (ipmp_member->if_name)); 329 list_insert_tail(pmembers, ipmp_member); 330 } 331 return (IPADM_SUCCESS); 332 } 333 334 /* 335 * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from 336 * kernel (libipmp is used to retrieve the required info) 337 */ 338 static ipadm_status_t 339 i_ipadm_fill_cmembers(char *grname, ipadm_ipmp_members_t *cmembers) 340 { 341 ipmp_handle_t ipmp_handle; 342 ipmp_groupinfo_t *grinfo; 343 ipmp_iflist_t *iflistp; 344 ipadm_ipmp_member_t *ipmp_member; 345 ipadm_status_t ipadm_status = IPADM_SUCCESS; 346 int i; 347 348 if (ipmp_open(&ipmp_handle) != IPMP_SUCCESS) 349 return (IPADM_FAILURE); 350 351 if (ipmp_getgroupinfo(ipmp_handle, grname, &grinfo) != IPMP_SUCCESS) { 352 ipadm_status = IPADM_FAILURE; 353 goto fail2; 354 } 355 356 iflistp = grinfo->gr_iflistp; 357 for (i = 0; i < iflistp->il_nif; i++) { 358 if ((ipmp_member = calloc(1, 359 sizeof (ipadm_ipmp_member_t))) == NULL) { 360 ipadm_status = ipadm_errno2status(errno); 361 goto fail1; 362 } 363 (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i], 364 sizeof (ipmp_member->if_name)); 365 list_insert_tail(cmembers, ipmp_member); 366 } 367 368 fail1: 369 ipmp_freegroupinfo(grinfo); 370 fail2: 371 ipmp_close(ipmp_handle); 372 return (ipadm_status); 373 } 374 375 /* 376 * Collects information for `ifname' if one is specified from both 377 * active and persistent config in `if_info'. If no `ifname' is specified, 378 * this returns all the interfaces in active and persistent config in 379 * `if_info'. 380 */ 381 ipadm_status_t 382 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname, 383 ipadm_if_info_t **if_info, int64_t lifc_flags) 384 { 385 ipadm_status_t status; 386 ipadm_if_info_t *aifinfo = NULL; 387 ipadm_if_info_t *pifinfo = NULL; 388 ipadm_if_info_t *aifp; 389 ipadm_if_info_t *pifp; 390 ipadm_if_info_t *last = NULL; 391 struct ifaddrs *ifa; 392 struct ifaddrs *ifap; 393 394 /* 395 * Retrive the information for the requested `ifname' or all 396 * interfaces from active configuration. 397 */ 398 retry: 399 status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags); 400 if (status != IPADM_SUCCESS) 401 return (status); 402 /* Get the interface state for each interface in `aifinfo'. */ 403 if (aifinfo != NULL) { 404 /* We need all addresses to get the interface state */ 405 if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY| 406 LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) { 407 status = ipadm_errno2status(errno); 408 goto fail; 409 } 410 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { 411 /* 412 * Find the `ifaddrs' structure from `ifa' 413 * for this interface. We need the IFF_* flags 414 * to find the interface state. 415 */ 416 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 417 if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0) 418 break; 419 } 420 if (ifap == NULL) { 421 /* 422 * The interface might have been removed 423 * from kernel. Retry getting all the active 424 * interfaces. 425 */ 426 freeifaddrs(ifa); 427 ipadm_free_if_info(aifinfo); 428 aifinfo = NULL; 429 goto retry; 430 } 431 if (!(ifap->ifa_flags & IFF_RUNNING) || 432 (ifap->ifa_flags & IFF_FAILED)) 433 aifp->ifi_state = IFIS_FAILED; 434 else if (ifap->ifa_flags & IFF_OFFLINE) 435 aifp->ifi_state = IFIS_OFFLINE; 436 else if (i_ipadm_is_if_down(aifp->ifi_name, ifa)) 437 aifp->ifi_state = IFIS_DOWN; 438 else 439 aifp->ifi_state = IFIS_OK; 440 if (aifp->ifi_next == NULL) 441 last = aifp; 442 } 443 freeifaddrs(ifa); 444 } 445 /* 446 * Get the persistent interface information in `pifinfo'. 447 */ 448 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo); 449 if (status == IPADM_NOTFOUND) { 450 *if_info = aifinfo; 451 return (IPADM_SUCCESS); 452 } 453 if (status != IPADM_SUCCESS) 454 goto fail; 455 456 /* 457 * Process the persistent interface information. 458 * 459 * First try to get the persistent "standby" property, as that isn't 460 * retrieved by i_ipadm_persist_if_info(). 461 * 462 * Next, if a persistent interface is also found in `aifinfo', update 463 * its entry in `aifinfo' with the persistent information from 464 * `pifinfo'. If an interface is found in `pifinfo', but not in 465 * `aifinfo', it means that this interface was disabled. We should 466 * add this interface to `aifinfo' and set it state to IFIF_DISABLED. 467 */ 468 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) { 469 char buf[10] = ""; 470 uint_t bufsize = sizeof (buf); 471 472 status = ipadm_get_ifprop(iph, pifp->ifi_name, "standby", buf, 473 &bufsize, MOD_PROTO_IP, IPADM_OPT_PERSIST); 474 475 if (status == IPADM_SUCCESS && strcmp(buf, "on") == 0) 476 pifp->ifi_pflags |= IFIF_STANDBY; 477 478 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { 479 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) { 480 break; 481 } 482 } 483 484 if (aifp == NULL) { 485 if ((status = 486 i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS) 487 goto fail; 488 489 (void) strlcpy(aifp->ifi_name, pifp->ifi_name, 490 sizeof (aifp->ifi_name)); 491 492 aifp->ifi_next = NULL; 493 aifp->ifi_state = IFIS_DISABLED; 494 if (last != NULL) 495 last->ifi_next = aifp; 496 else 497 aifinfo = aifp; 498 last = aifp; 499 } 500 501 if ((status = i_ipadm_add_persistent_if_info(aifp, 502 pifp)) != IPADM_SUCCESS) 503 goto fail; 504 } 505 *if_info = aifinfo; 506 ipadm_free_if_info(pifinfo); 507 return (IPADM_SUCCESS); 508 fail: 509 *if_info = NULL; 510 ipadm_free_if_info(aifinfo); 511 ipadm_free_if_info(pifinfo); 512 return (status); 513 } 514 515 /* 516 * Updates active if_info by data from persistent if_info 517 */ 518 static ipadm_status_t 519 i_ipadm_add_persistent_if_info(ipadm_if_info_t *aifp, ipadm_if_info_t *pifp) 520 { 521 ipadm_ipmp_member_t *pp_ipmp_member, *ap_ipmp_member; 522 523 ipadm_ipmp_members_t *apmembers = &aifp->ifi_ipmp_pmembers; 524 ipadm_ipmp_members_t *ppmembers = &pifp->ifi_ipmp_pmembers; 525 526 aifp->ifi_pflags = pifp->ifi_pflags; 527 aifp->ifi_class = pifp->ifi_class; 528 529 for (pp_ipmp_member = list_head(ppmembers); pp_ipmp_member; 530 pp_ipmp_member = list_next(ppmembers, pp_ipmp_member)) { 531 if ((ap_ipmp_member = calloc(1, 532 sizeof (ipadm_ipmp_member_t))) == NULL) 533 return (ipadm_errno2status(errno)); 534 535 (void) strlcpy(ap_ipmp_member->if_name, 536 pp_ipmp_member->if_name, 537 sizeof (ap_ipmp_member->if_name)); 538 539 list_insert_tail(apmembers, ap_ipmp_member); 540 } 541 return (IPADM_SUCCESS); 542 } 543 544 static ipadm_status_t 545 i_ipadm_allocate_ifinfo(ipadm_if_info_t **if_info) 546 { 547 *if_info = calloc(1, sizeof (ipadm_if_info_t)); 548 if (*if_info == NULL) 549 return (ipadm_errno2status(errno)); 550 551 /* List of active (current) members */ 552 list_create(&((*if_info)->ifi_ipmp_cmembers), 553 sizeof (ipadm_ipmp_member_t), 554 offsetof(ipadm_ipmp_member_t, node)); 555 556 /* List of persistent members */ 557 list_create(&((*if_info)->ifi_ipmp_pmembers), 558 sizeof (ipadm_ipmp_member_t), 559 offsetof(ipadm_ipmp_member_t, node)); 560 561 return (IPADM_SUCCESS); 562 } 563 564 /* 565 * Reads all the interface lines from the persistent DB into the nvlist `onvl', 566 * when `ifname' is NULL. 567 * If an `ifname' is specified, then the interface line corresponding to 568 * that name will be returned. 569 */ 570 static ipadm_status_t 571 i_ipadm_get_db_if(ipadm_handle_t iph, const char *ifname, nvlist_t **onvl) 572 { 573 ipmgmt_getif_arg_t garg; 574 575 /* Populate the door_call argument structure */ 576 bzero(&garg, sizeof (garg)); 577 garg.ia_cmd = IPMGMT_CMD_GETIF; 578 if (ifname != NULL) 579 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname)); 580 581 return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl)); 582 } 583 584 int 585 i_ipadm_get_lnum(const char *ifname) 586 { 587 char *num = strrchr(ifname, IPADM_LOGICAL_SEP); 588 589 if (num == NULL) 590 return (0); 591 592 return (atoi(++num)); 593 } 594 595 /* 596 * Sets the output argument `exists' to true or false based on whether 597 * any persistent configuration is available for `ifname' and returns 598 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved, 599 * `exists' is unmodified and an error status is returned. 600 */ 601 ipadm_status_t 602 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af, 603 boolean_t *exists) 604 { 605 ipadm_if_info_t *ifinfo; 606 ipadm_status_t status; 607 608 /* 609 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already 610 * knows about persistent configuration in the first place, so we 611 * just return success. 612 */ 613 if (iph->iph_flags & IPH_IPMGMTD) { 614 *exists = B_FALSE; 615 return (IPADM_SUCCESS); 616 } 617 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo); 618 if (status == IPADM_SUCCESS) { 619 *exists = ((af == AF_INET && 620 (ifinfo->ifi_pflags & IFIF_IPV4)) || 621 (af == AF_INET6 && 622 (ifinfo->ifi_pflags & IFIF_IPV6))); 623 ipadm_free_if_info(ifinfo); 624 } else if (status == IPADM_NOTFOUND) { 625 status = IPADM_SUCCESS; 626 *exists = B_FALSE; 627 } 628 return (status); 629 } 630 631 /* 632 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream 633 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let 634 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at 635 * the bottom of the stream for tunneling interfaces. 636 */ 637 ipadm_status_t 638 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd) 639 { 640 int err; 641 642 if ((*fd = open(udp_dev_name, O_RDWR)) == -1) 643 return (ipadm_errno2status(errno)); 644 645 /* 646 * Pop off all undesired modules (note that the user may have 647 * configured autopush to add modules above udp), and push the 648 * arp module onto the resulting stream. This is used to make 649 * IP+ARP be able to atomically track the muxid for the I_PLINKed 650 * STREAMS, thus it isn't related to ARP running the ARP protocol. 651 */ 652 while (ioctl(*fd, I_POP, 0) != -1) 653 ; 654 if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1) 655 return (IPADM_SUCCESS); 656 err = errno; 657 (void) close(*fd); 658 659 return (ipadm_errno2status(err)); 660 } 661 662 /* 663 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an 664 * underlying interface in an ipmp group G is plumbed for an address family, 665 * but the meta-interface for the other address family `af' does not exist 666 * yet for the group G. If `af' is IPv6, we need to bring up the 667 * link-local address. 668 */ 669 static ipadm_status_t 670 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af, 671 const char *grname, uint32_t ipadm_flags) 672 { 673 ipadm_status_t status; 674 struct lifreq lifr; 675 int sock; 676 int err; 677 678 assert(ipadm_flags & IPADM_OPT_IPMP); 679 680 /* Create the ipmp underlying interface */ 681 status = i_ipadm_create_if(iph, ifname, af, ipadm_flags); 682 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) 683 return (status); 684 685 /* 686 * To preserve backward-compatibility, always bring up the link-local 687 * address for implicitly-created IPv6 IPMP interfaces. 688 */ 689 if (af == AF_INET6) 690 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0); 691 692 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 693 /* 694 * If the caller requested a different group name, issue a 695 * SIOCSLIFGROUPNAME on the new IPMP interface. 696 */ 697 bzero(&lifr, sizeof (lifr)); 698 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 699 if (strcmp(lifr.lifr_name, grname) != 0) { 700 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ); 701 if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) { 702 err = errno; 703 /* Remove the interface we created. */ 704 if (status == IPADM_SUCCESS) { 705 (void) i_ipadm_delete_if(iph, ifname, af, 706 ipadm_flags); 707 } 708 return (ipadm_errno2status(err)); 709 } 710 } 711 712 return (IPADM_SUCCESS); 713 } 714 715 /* 716 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address 717 * family. If so, create a matching IPMP group for address family `af'. 718 */ 719 static ipadm_status_t 720 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af) 721 { 722 lifgroupinfo_t lifgr; 723 ipadm_status_t status = IPADM_SUCCESS; 724 struct lifreq lifr; 725 int other_af_sock; 726 727 assert(af == AF_INET || af == AF_INET6); 728 729 other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock); 730 731 /* 732 * iph is the handle for the interface that we are trying to plumb. 733 * other_af_sock is the socket for the "other" address family. 734 */ 735 bzero(&lifr, sizeof (lifr)); 736 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 737 if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0) 738 return (IPADM_SUCCESS); 739 740 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ); 741 if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0) 742 return (IPADM_SUCCESS); 743 744 /* 745 * If `ifname' *is* the IPMP group interface, or if the relevant 746 * address family is already configured, then there's nothing to do. 747 */ 748 if (strcmp(lifgr.gi_grifname, ifname) == 0 || 749 (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) { 750 return (IPADM_SUCCESS); 751 } 752 753 status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af, 754 lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP); 755 return (status); 756 } 757 758 /* 759 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd. 760 */ 761 static ipadm_status_t 762 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd) 763 { 764 struct lifreq lifr; 765 ifspec_t ifsp; 766 767 bzero(&lifr, sizeof (lifr)); 768 (void) ifparse_ifspec(ifname, &ifsp); 769 lifr.lifr_ppa = ifsp.ifsp_ppa; 770 lifr.lifr_flags = flags; 771 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 772 /* 773 * Tell ARP the name and unit number for this interface. 774 * Note that arp has no support for transparent ioctls. 775 */ 776 if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr, 777 sizeof (lifr)) == -1) { 778 return (ipadm_errno2status(errno)); 779 } 780 return (IPADM_SUCCESS); 781 } 782 783 /* 784 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in 785 * `ipadm_flags', then a ppa will be generated. `newif' will be updated 786 * with the generated ppa. 787 */ 788 static ipadm_status_t 789 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags, 790 int fd, uint32_t ipadm_flags) 791 { 792 struct lifreq lifr; 793 ipadm_status_t status = IPADM_SUCCESS; 794 int err = 0; 795 sa_family_t af; 796 int ppa; 797 ifspec_t ifsp; 798 boolean_t valid_if; 799 800 bzero(&lifr, sizeof (lifr)); 801 if (ipadm_flags & IPADM_OPT_GENPPA) { 802 /* 803 * We'd like to just set lifr_ppa to UINT_MAX and have the 804 * kernel pick a PPA. Unfortunately, that would mishandle 805 * two cases: 806 * 807 * 1. If the PPA is available but the groupname is taken 808 * (e.g., the "ipmp2" IP interface name is available 809 * but the "ipmp2" groupname is taken) then the 810 * auto-assignment by the kernel will fail. 811 * 812 * 2. If we're creating (e.g.) an IPv6-only IPMP 813 * interface, and there's already an IPv4-only IPMP 814 * interface, the kernel will allow us to accidentally 815 * reuse the IPv6 IPMP interface name (since 816 * SIOCSLIFNAME uniqueness is per-interface-type). 817 * This will cause administrative confusion. 818 * 819 * Thus, we instead take a brute-force approach of checking 820 * whether the IPv4 or IPv6 name is already in-use before 821 * attempting the SIOCSLIFNAME. As per (1) above, the 822 * SIOCSLIFNAME may still fail, in which case we just proceed 823 * to the next one. If this approach becomes too slow, we 824 * can add a new SIOC* to handle this case in the kernel. 825 */ 826 for (ppa = 0; ppa < UINT_MAX; ppa++) { 827 (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d", 828 ifname, ppa); 829 830 if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 || 831 errno != ENXIO) 832 continue; 833 834 if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 || 835 errno != ENXIO) 836 continue; 837 838 lifr.lifr_ppa = ppa; 839 lifr.lifr_flags = flags; 840 841 err = ioctl(fd, SIOCSLIFNAME, &lifr); 842 if (err != -1 || errno != EEXIST) 843 break; 844 } 845 if (err == -1) { 846 status = ipadm_errno2status(errno); 847 } else { 848 /* 849 * PPA has been successfully established. 850 * Update `newif' with the ppa. 851 */ 852 assert(newif != NULL); 853 if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname, 854 ppa) >= LIFNAMSIZ) 855 return (IPADM_INVALID_ARG); 856 } 857 } else { 858 /* We should have already validated the interface name. */ 859 valid_if = ifparse_ifspec(ifname, &ifsp); 860 assert(valid_if); 861 862 /* 863 * Before we call SIOCSLIFNAME, ensure that the IPMP group 864 * interface for this address family exists. Otherwise, the 865 * kernel will kick the interface out of the group when we do 866 * the SIOCSLIFNAME. 867 * 868 * Example: suppose bge0 is plumbed for IPv4 and in group "a". 869 * If we're now plumbing bge0 for IPv6, but the IPMP group 870 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME 871 * will kick bge0 out of group "a", which is undesired. 872 */ 873 if (flags & IFF_IPV4) 874 af = AF_INET; 875 else 876 af = AF_INET6; 877 status = i_ipadm_create_ipmp_peer(iph, ifname, af); 878 if (status != IPADM_SUCCESS) 879 return (status); 880 lifr.lifr_ppa = ifsp.ifsp_ppa; 881 lifr.lifr_flags = flags; 882 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 883 if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1) 884 status = ipadm_errno2status(errno); 885 } 886 887 return (status); 888 } 889 890 /* 891 * Plumbs the interface `ifname' for the address family `af'. It also persists 892 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'. 893 */ 894 ipadm_status_t 895 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 896 uint32_t ipadm_flags) 897 { 898 int ip_muxid; 899 int mux_fd = -1, ip_fd, arp_fd; 900 char *udp_dev_name; 901 dlpi_handle_t dh_arp = NULL, dh_ip; 902 uint64_t ifflags; 903 struct lifreq lifr; 904 uint_t dlpi_flags; 905 ipadm_status_t status = IPADM_SUCCESS; 906 char *linkname; 907 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 908 zoneid_t zoneid; 909 char newif[LIFNAMSIZ]; 910 char lifname[LIFNAMSIZ]; 911 datalink_id_t linkid; 912 int sock; 913 boolean_t islo; 914 boolean_t is_persistent = 915 ((ipadm_flags & IPADM_OPT_PERSIST) != 0); 916 uint32_t dlflags; 917 dladm_status_t dlstatus; 918 919 if (iph->iph_dlh != NULL) { 920 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, 921 &dlflags, NULL, NULL); 922 } 923 /* 924 * If we're in the global zone and we're plumbing a datalink, make 925 * sure that the datalink is not assigned to a non-global zone. Note 926 * that the non-global zones don't need this check, because zoneadm 927 * has taken care of this when the zones boot. 928 */ 929 if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) { 930 zoneid = ALL_ZONES; 931 if (zone_check_datalink(&zoneid, linkid) == 0) { 932 /* interface is in use by a non-global zone. */ 933 return (IPADM_IF_INUSE); 934 } 935 } 936 937 /* loopback interfaces are just added as logical interface */ 938 bzero(&lifr, sizeof (lifr)); 939 islo = i_ipadm_is_loopback(ifname); 940 if (islo || i_ipadm_get_lnum(ifname) != 0) { 941 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 942 if (af == AF_INET) 943 sock = iph->iph_sock; 944 else 945 sock = iph->iph_sock6; 946 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) 947 return (IPADM_IF_EXISTS); 948 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 949 return (ipadm_errno2status(errno)); 950 951 /* 952 * By default, kernel configures 127.0.0.1 on the loopback 953 * interface. Replace this with 0.0.0.0 to be consistent 954 * with interface creation on other physical interfaces. 955 */ 956 if (islo && !legacy) { 957 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); 958 lifr.lifr_addr.ss_family = af; 959 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 960 return (ipadm_errno2status(errno)); 961 if (is_persistent) { 962 status = i_ipadm_persist_if(iph, 963 ifname, af, ipadm_flags); 964 if (status != IPADM_SUCCESS) { 965 (void) i_ipadm_delete_if(iph, ifname, 966 af, IPADM_OPT_ACTIVE); 967 } 968 } 969 } 970 return (status); 971 } 972 973 dlpi_flags = DLPI_NOATTACH; 974 975 /* 976 * If IPADM_OPT_IPMP is specified, then this is a request 977 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply 978 * pass "ipmpstub0" as devname since an admin *could* have a normal 979 * vanity-named link named "ipmpstub0" that they'd like to plumb.) 980 */ 981 if (ipadm_flags & IPADM_OPT_IPMP) { 982 dlpi_flags |= DLPI_DEVONLY; 983 linkname = "ipmpstub0"; 984 } else { 985 /* 986 * Verify that the user is not creating a persistent 987 * IP interface on a non-persistent data-link. 988 */ 989 if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK && 990 is_persistent && !(dlflags & DLADM_OPT_PERSIST)) { 991 return (IPADM_TEMPORARY_OBJ); 992 } 993 linkname = ifname; 994 } 995 996 /* 997 * We use DLPI_NOATTACH because the ip module will do the attach 998 * itself for DLPI style-2 devices. 999 */ 1000 if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS) 1001 return (IPADM_DLPI_FAILURE); 1002 ip_fd = dlpi_fd(dh_ip); 1003 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) { 1004 status = ipadm_errno2status(errno); 1005 goto done; 1006 } 1007 1008 /* 1009 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications 1010 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL. 1011 */ 1012 ifflags = 0; 1013 1014 /* Set the name string and the IFF_IPV* flag */ 1015 if (af == AF_INET) { 1016 ifflags = IFF_IPV4; 1017 } else { 1018 ifflags = IFF_IPV6; 1019 /* 1020 * With the legacy method, the link-local address should be 1021 * configured as part of the interface plumb, using the default 1022 * token. If IPH_LEGACY is not specified, we want to set :: as 1023 * the address and require the admin to explicitly call 1024 * ipadm_create_addr() with the address object type set to 1025 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address 1026 * as well as the autoconfigured addresses. 1027 */ 1028 if (!legacy && !i_ipadm_is_6to4(iph, ifname)) 1029 ifflags |= IFF_NOLINKLOCAL; 1030 } 1031 (void) strlcpy(newif, ifname, sizeof (newif)); 1032 status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd, 1033 ipadm_flags); 1034 if (status != IPADM_SUCCESS) 1035 goto done; 1036 1037 /* Get the full set of existing flags for this stream */ 1038 status = i_ipadm_get_flags(iph, newif, af, &ifflags); 1039 if (status != IPADM_SUCCESS) 1040 goto done; 1041 1042 udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME); 1043 status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 1044 if (status != IPADM_SUCCESS) 1045 goto done; 1046 1047 /* Check if arp is not needed */ 1048 if (ifflags & (IFF_NOARP|IFF_IPV6)) { 1049 /* 1050 * PLINK the interface stream so that the application can exit 1051 * without tearing down the stream. 1052 */ 1053 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 1054 status = ipadm_errno2status(errno); 1055 goto done; 1056 } 1057 1058 /* 1059 * This interface does use ARP, so set up a separate stream 1060 * from the interface to ARP. 1061 * 1062 * We use DLPI_NOATTACH because the arp module will do the attach 1063 * itself for DLPI style-2 devices. 1064 */ 1065 if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) { 1066 status = IPADM_DLPI_FAILURE; 1067 goto done; 1068 } 1069 1070 arp_fd = dlpi_fd(dh_arp); 1071 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) { 1072 status = ipadm_errno2status(errno); 1073 goto done; 1074 } 1075 1076 status = i_ipadm_slifname_arp(newif, ifflags, arp_fd); 1077 if (status != IPADM_SUCCESS) 1078 goto done; 1079 /* 1080 * PLINK the IP and ARP streams so that ifconfig can exit 1081 * without tearing down the stream. 1082 */ 1083 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 1084 status = ipadm_errno2status(errno); 1085 goto done; 1086 } 1087 1088 if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) { 1089 status = ipadm_errno2status(errno); 1090 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 1091 } 1092 1093 done: 1094 dlpi_close(dh_ip); 1095 if (dh_arp != NULL) 1096 dlpi_close(dh_arp); 1097 1098 if (mux_fd != -1) 1099 (void) close(mux_fd); 1100 1101 if (status == IPADM_SUCCESS) { 1102 /* copy back new ifname */ 1103 (void) strlcpy(ifname, newif, LIFNAMSIZ); 1104 /* 1105 * If it is a 6to4 tunnel, create a default 1106 * addrobj name for the default address on the 0'th 1107 * logical interface and set IFF_UP in the interface flags. 1108 */ 1109 if (i_ipadm_is_6to4(iph, ifname)) { 1110 struct ipadm_addrobj_s addr; 1111 1112 i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC); 1113 addr.ipadm_af = af; 1114 status = i_ipadm_lookupadd_addrobj(iph, &addr); 1115 if (status != IPADM_SUCCESS) 1116 return (status); 1117 status = ipadm_add_aobjname(iph, ifname, 1118 af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0); 1119 if (status != IPADM_SUCCESS) 1120 return (status); 1121 addr.ipadm_lifnum = 0; 1122 i_ipadm_addrobj2lifname(&addr, lifname, 1123 sizeof (lifname)); 1124 status = i_ipadm_set_flags(iph, lifname, af, 1125 IFF_UP, 0); 1126 if (status != IPADM_SUCCESS) 1127 return (status); 1128 } else { 1129 /* 1130 * Prevent static IPv6 addresses from triggering 1131 * autoconf. This does not have to be done for 1132 * 6to4 tunnel interfaces, since in.ndpd will 1133 * not autoconfigure those interfaces. 1134 */ 1135 if (af == AF_INET6 && !legacy) 1136 (void) i_ipadm_disable_autoconf(newif); 1137 } 1138 1139 /* 1140 * If IPADM_OPT_PERSIST was set in flags, store the 1141 * interface in persistent DB. 1142 */ 1143 if (is_persistent) { 1144 status = i_ipadm_persist_if(iph, 1145 newif, af, ipadm_flags); 1146 if (status != IPADM_SUCCESS) { 1147 (void) i_ipadm_delete_if(iph, newif, af, 1148 IPADM_OPT_ACTIVE); 1149 } 1150 } 1151 } 1152 if (status == IPADM_EXISTS) 1153 status = IPADM_IF_EXISTS; 1154 return (status); 1155 } 1156 1157 /* 1158 * Unplumbs the interface in `ifname' of family `af'. 1159 */ 1160 ipadm_status_t 1161 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af) 1162 { 1163 int ip_muxid, arp_muxid; 1164 int mux_fd = -1; 1165 int muxid_fd = -1; 1166 char *udp_dev_name; 1167 uint64_t flags; 1168 boolean_t changed_arp_muxid = B_FALSE; 1169 int save_errno; 1170 struct lifreq lifr; 1171 ipadm_status_t ret = IPADM_SUCCESS; 1172 int sock; 1173 lifgroupinfo_t lifgr; 1174 ifaddrlistx_t *ifaddrs, *ifaddrp; 1175 boolean_t v6 = (af == AF_INET6); 1176 1177 /* Just do SIOCLIFREMOVEIF on loopback interfaces */ 1178 bzero(&lifr, sizeof (lifr)); 1179 if (i_ipadm_is_loopback(ifname) || 1180 (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) { 1181 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 1182 if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6, 1183 SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 1184 return (ipadm_errno2status(errno)); 1185 } 1186 return (IPADM_SUCCESS); 1187 } 1188 1189 /* 1190 * We used /dev/udp or udp6 to set up the mux. So we have to use 1191 * the same now for PUNLINK also. 1192 */ 1193 if (v6) { 1194 udp_dev_name = UDP6_DEV_NAME; 1195 sock = iph->iph_sock6; 1196 } else { 1197 udp_dev_name = UDP_DEV_NAME; 1198 sock = iph->iph_sock; 1199 } 1200 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) { 1201 ret = ipadm_errno2status(errno); 1202 goto done; 1203 } 1204 ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 1205 if (ret != IPADM_SUCCESS) 1206 goto done; 1207 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 1208 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 1209 ret = ipadm_errno2status(errno); 1210 goto done; 1211 } 1212 flags = lifr.lifr_flags; 1213 again: 1214 if (flags & IFF_IPMP) { 1215 /* 1216 * There are two reasons the I_PUNLINK can fail with EBUSY: 1217 * (1) if IP interfaces are in the group, or (2) if IPMP data 1218 * addresses are administratively up. For case (1), we fail 1219 * here with a specific error message. For case (2), we bring 1220 * down the addresses prior to doing the I_PUNLINK. If the 1221 * I_PUNLINK still fails with EBUSY then the configuration 1222 * must have changed after our checks, in which case we branch 1223 * back up to `again' and rerun this logic. The net effect is 1224 * that unplumbing an IPMP interface will only fail with EBUSY 1225 * if IP interfaces are in the group. 1226 */ 1227 if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) { 1228 ret = ipadm_errno2status(errno); 1229 goto done; 1230 } 1231 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, 1232 LIFGRNAMSIZ); 1233 if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) { 1234 ret = ipadm_errno2status(errno); 1235 goto done; 1236 } 1237 if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) { 1238 ret = IPADM_GRP_NOTEMPTY; 1239 goto done; 1240 } 1241 1242 /* 1243 * The kernel will fail the I_PUNLINK if the IPMP interface 1244 * has administratively up addresses; bring them down. 1245 */ 1246 if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE, 1247 0, &ifaddrs) == -1) { 1248 ret = ipadm_errno2status(errno); 1249 goto done; 1250 } 1251 ifaddrp = ifaddrs; 1252 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 1253 int sock = (ifaddrp->ia_flags & IFF_IPV4) ? 1254 iph->iph_sock : iph->iph_sock6; 1255 struct lifreq lifrl; 1256 1257 if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) || 1258 (!(ifaddrp->ia_flags & IFF_IPV6) && v6)) 1259 continue; 1260 1261 bzero(&lifrl, sizeof (lifrl)); 1262 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name, 1263 sizeof (lifrl.lifr_name)); 1264 if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) { 1265 ret = ipadm_errno2status(errno); 1266 ifaddrlistx_free(ifaddrs); 1267 goto done; 1268 } 1269 if (lifrl.lifr_flags & IFF_UP) { 1270 ret = i_ipadm_set_flags(iph, lifrl.lifr_name, 1271 ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET : 1272 AF_INET6), 0, IFF_UP); 1273 if (ret != IPADM_SUCCESS) { 1274 ifaddrlistx_free(ifaddrs); 1275 goto done; 1276 } 1277 } else if (lifrl.lifr_flags & IFF_DUPLICATE) { 1278 if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 || 1279 ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) { 1280 ret = ipadm_errno2status(errno); 1281 ifaddrlistx_free(ifaddrs); 1282 goto done; 1283 } 1284 } 1285 } 1286 ifaddrlistx_free(ifaddrs); 1287 } 1288 1289 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 1290 ret = ipadm_errno2status(errno); 1291 goto done; 1292 } 1293 arp_muxid = lifr.lifr_arp_muxid; 1294 ip_muxid = lifr.lifr_ip_muxid; 1295 1296 /* 1297 * We don't have a good way of knowing whether the arp stream is 1298 * plumbed. We can't rely on IFF_NOARP because someone could 1299 * have turned it off later using "ifconfig xxx -arp". 1300 */ 1301 if (arp_muxid != 0) { 1302 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 1303 /* 1304 * See the comment before the SIOCGLIFGROUPNAME call. 1305 */ 1306 if (errno == EBUSY && (flags & IFF_IPMP)) 1307 goto again; 1308 1309 if ((errno == EINVAL) && 1310 (flags & (IFF_NOARP | IFF_IPV6))) { 1311 /* 1312 * Some plumbing utilities set the muxid to 1313 * -1 or some invalid value to signify that 1314 * there is no arp stream. Set the muxid to 0 1315 * before trying to unplumb the IP stream. 1316 * IP does not allow the IP stream to be 1317 * unplumbed if it sees a non-null arp muxid, 1318 * for consistency of IP-ARP streams. 1319 */ 1320 lifr.lifr_arp_muxid = 0; 1321 (void) ioctl(muxid_fd, SIOCSLIFMUXID, 1322 (caddr_t)&lifr); 1323 changed_arp_muxid = B_TRUE; 1324 } 1325 /* 1326 * In case of any other error, we continue with 1327 * the unplumb. 1328 */ 1329 } 1330 } 1331 1332 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 1333 if (changed_arp_muxid) { 1334 /* 1335 * Some error occurred, and we need to restore 1336 * everything back to what it was. 1337 */ 1338 save_errno = errno; 1339 lifr.lifr_arp_muxid = arp_muxid; 1340 lifr.lifr_ip_muxid = ip_muxid; 1341 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 1342 errno = save_errno; 1343 } 1344 /* 1345 * See the comment before the SIOCGLIFGROUPNAME call. 1346 */ 1347 if (errno == EBUSY && (flags & IFF_IPMP)) 1348 goto again; 1349 1350 ret = ipadm_errno2status(errno); 1351 } 1352 done: 1353 if (muxid_fd != -1) 1354 (void) close(muxid_fd); 1355 if (mux_fd != -1) 1356 (void) close(mux_fd); 1357 1358 if (af == AF_INET6 && ret == IPADM_SUCCESS) { 1359 /* 1360 * in.ndpd maintains the phyints in its memory even after 1361 * the interface is plumbed, so that it can be reused when 1362 * the interface gets plumbed again. The default behavior 1363 * of in.ndpd is to start autoconfiguration for an interface 1364 * that gets plumbed. We need to send the 1365 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this 1366 * default behavior on replumb. 1367 */ 1368 (void) i_ipadm_enable_autoconf(ifname); 1369 } 1370 return (ret); 1371 } 1372 1373 /* 1374 * Saves the given interface name `ifname' with address family `af' in 1375 * persistent DB. 1376 */ 1377 static ipadm_status_t 1378 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1379 uint32_t ipadm_flags) 1380 { 1381 ipmgmt_if_arg_t ifarg; 1382 int err; 1383 1384 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname)); 1385 ifarg.ia_family = af; 1386 if (ipadm_flags & IPADM_OPT_IPMP) 1387 ifarg.ia_ifclass = IPADM_IF_CLASS_IPMP; 1388 else 1389 ifarg.ia_ifclass = IPADM_IF_CLASS_REGULAR; 1390 1391 ifarg.ia_cmd = IPMGMT_CMD_SETIF; 1392 ifarg.ia_flags = IPMGMT_PERSIST; 1393 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1394 return (ipadm_errno2status(err)); 1395 } 1396 1397 /* 1398 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST 1399 * is set in `ipadm_flags', it is also removed from persistent configuration. 1400 */ 1401 ipadm_status_t 1402 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1403 uint32_t ipadm_flags) 1404 { 1405 ipadm_status_t ret = IPADM_SUCCESS; 1406 ipadm_status_t db_status; 1407 char tmp_ifname[LIFNAMSIZ]; 1408 char *cp; 1409 struct ipadm_addrobj_s ipaddr; 1410 boolean_t is_persistent = 1411 (ipadm_flags & IPADM_OPT_PERSIST); 1412 1413 ret = i_ipadm_unplumb_if(iph, ifname, af); 1414 if (ret != IPADM_SUCCESS) 1415 goto done; 1416 1417 cp = strrchr(ifname, IPADM_LOGICAL_SEP); 1418 if (cp != NULL) { 1419 assert(iph->iph_flags & IPH_LEGACY); 1420 /* 1421 * This is a non-zero logical interface. 1422 * Find the addrobj and remove it from the daemon's memory. 1423 */ 1424 (void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname)); 1425 tmp_ifname[cp - ifname] = '\0'; 1426 *cp++ = '\0'; 1427 ipaddr.ipadm_lifnum = atoi(cp); 1428 (void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname, 1429 sizeof (ipaddr.ipadm_ifname)); 1430 ipaddr.ipadm_af = af; 1431 ret = i_ipadm_get_lif2addrobj(iph, &ipaddr); 1432 if (ret == IPADM_SUCCESS) { 1433 ret = i_ipadm_delete_addrobj(iph, &ipaddr, 1434 IPADM_OPT_ACTIVE); 1435 } else if (ret == IPADM_NOTFOUND) { 1436 ret = IPADM_SUCCESS; 1437 } 1438 return (ret); 1439 } 1440 done: 1441 /* 1442 * Even if interface does not exist, remove all its addresses and 1443 * properties from the persistent store. If interface does not 1444 * exist both in kernel and the persistent store, return IPADM_ENXIO. 1445 */ 1446 if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) { 1447 db_status = i_ipadm_delete_ifobj(iph, ifname, af, 1448 is_persistent); 1449 if (db_status == IPADM_SUCCESS) 1450 ret = IPADM_SUCCESS; 1451 } 1452 1453 return (ret); 1454 } 1455 1456 /* 1457 * Resets all addresses on interface `ifname' with address family `af' 1458 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties 1459 * and address objects of `ifname' for `af' are also removed from the 1460 * persistent DB. 1461 */ 1462 ipadm_status_t 1463 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1464 boolean_t is_persistent) 1465 { 1466 ipmgmt_if_arg_t ifarg; 1467 int err; 1468 1469 ifarg.ia_cmd = IPMGMT_CMD_RESETIF; 1470 ifarg.ia_flags = IPMGMT_ACTIVE; 1471 if (is_persistent) 1472 ifarg.ia_flags |= IPMGMT_PERSIST; 1473 ifarg.ia_family = af; 1474 (void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ); 1475 1476 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1477 return (ipadm_errno2status(err)); 1478 } 1479 1480 /* 1481 * Create the interface by plumbing it for IP. 1482 * This function will check if there is saved configuration information 1483 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space 1484 * for `ifname' is taken. 1485 */ 1486 ipadm_status_t 1487 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 1488 uint32_t ipadm_flags) 1489 { 1490 ipadm_status_t status; 1491 boolean_t p_exists; 1492 sa_family_t other_af; 1493 1494 /* 1495 * Return error, if the interface already exists in either the active 1496 * or the persistent configuration. 1497 */ 1498 if (ipadm_if_enabled(iph, ifname, af)) 1499 return (IPADM_IF_EXISTS); 1500 1501 if (!(iph->iph_flags & IPH_LEGACY)) { 1502 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 1503 if (status != IPADM_SUCCESS) 1504 return (status); 1505 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 1506 if (p_exists) { 1507 if (!ipadm_if_enabled(iph, ifname, other_af)) 1508 return (IPADM_OP_DISABLE_OBJ); 1509 else 1510 ipadm_flags &= ~IPADM_OPT_PERSIST; 1511 } 1512 } 1513 1514 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags)); 1515 } 1516 1517 /* 1518 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by 1519 * default, unless a value in `af' is specified. The interface may be plumbed 1520 * only if there is no previously saved persistent configuration information 1521 * for the interface (in which case the ipadm_enable_if() function must 1522 * be used to enable the interface). 1523 * 1524 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS, 1525 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE, 1526 * or appropriate ipadm_status_t corresponding to the errno. 1527 * 1528 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may 1529 * be over-written with the actual interface name when a PPA has to be 1530 * internally generated by the library. 1531 */ 1532 ipadm_status_t 1533 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 1534 uint32_t flags) 1535 { 1536 ipadm_status_t status; 1537 boolean_t created_v4 = B_FALSE; 1538 char newifname[LIFNAMSIZ]; 1539 1540 /* Check for the required authorization */ 1541 if (!ipadm_check_auth()) 1542 return (IPADM_EAUTH); 1543 1544 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) && 1545 !(flags & IPADM_OPT_ACTIVE)) || 1546 (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP | 1547 IPADM_OPT_GENPPA))) { 1548 return (IPADM_INVALID_ARG); 1549 } 1550 if (flags & IPADM_OPT_GENPPA) { 1551 if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >= 1552 LIFNAMSIZ) 1553 return (IPADM_INVALID_ARG); 1554 } else { 1555 if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ) 1556 return (IPADM_INVALID_ARG); 1557 } 1558 1559 if (!i_ipadm_validate_ifname(iph, newifname)) 1560 return (IPADM_INVALID_ARG); 1561 1562 if ((af == AF_INET || af == AF_UNSPEC) && 1563 !i_ipadm_is_6to4(iph, ifname)) { 1564 status = i_ipadm_create_if(iph, ifname, AF_INET, flags); 1565 if (status != IPADM_SUCCESS) 1566 return (status); 1567 created_v4 = B_TRUE; 1568 } 1569 if (af == AF_INET6 || af == AF_UNSPEC) { 1570 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags); 1571 if (status != IPADM_SUCCESS) { 1572 if (created_v4) { 1573 (void) i_ipadm_delete_if(iph, ifname, AF_INET, 1574 IPADM_OPT_ACTIVE); 1575 } 1576 return (status); 1577 } 1578 } 1579 1580 return (IPADM_SUCCESS); 1581 } 1582 1583 ipadm_status_t 1584 ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname, 1585 const char *mifname, uint32_t ipadm_flags) 1586 { 1587 return (i_ipadm_update_ipmp(iph, gifname, mifname, 1588 ipadm_flags, IPADM_ADD_IPMP)); 1589 } 1590 1591 ipadm_status_t 1592 ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname, 1593 const char *mifname, uint32_t ipadm_flags) 1594 { 1595 return (i_ipadm_update_ipmp(iph, gifname, mifname, 1596 ipadm_flags, IPADM_REMOVE_IPMP)); 1597 } 1598 1599 /* 1600 * Updates active IPMP configuration according to the specified 1601 * command. It also persists the configuration if IPADM_OPT_PERSIST 1602 * is set in `ipadm_flags'. 1603 */ 1604 static ipadm_status_t 1605 i_ipadm_update_ipmp(ipadm_handle_t iph, const char *gifname, 1606 const char *mifname, uint32_t ipadm_flags, ipadm_ipmp_op_t op) 1607 { 1608 ipadm_status_t status; 1609 char groupname1[LIFGRNAMSIZ]; 1610 char groupname2[LIFGRNAMSIZ]; 1611 1612 /* Check for the required authorization */ 1613 if (!ipadm_check_auth()) 1614 return (IPADM_EAUTH); 1615 1616 if (!(ipadm_flags & IPADM_OPT_ACTIVE) || 1617 gifname == NULL || mifname == NULL) 1618 return (IPADM_INVALID_ARG); 1619 1620 if (!ipadm_if_enabled(iph, gifname, AF_UNSPEC) || 1621 !ipadm_if_enabled(iph, mifname, AF_UNSPEC)) 1622 return (IPADM_OP_DISABLE_OBJ); 1623 1624 if (!i_ipadm_is_ipmp(iph, gifname)) 1625 return (IPADM_INVALID_ARG); 1626 1627 if (op == IPADM_ADD_IPMP && i_ipadm_is_under_ipmp(iph, mifname)) 1628 return (IPADM_IF_INUSE); 1629 1630 if ((status = i_ipadm_get_groupname_active(iph, gifname, 1631 groupname2, sizeof (groupname2))) != IPADM_SUCCESS) 1632 return (status); 1633 1634 if (op == IPADM_REMOVE_IPMP) { 1635 if ((status = i_ipadm_get_groupname_active(iph, mifname, 1636 groupname1, sizeof (groupname1))) != IPADM_SUCCESS) 1637 return (status); 1638 1639 if (groupname1[0] == '\0' || 1640 strcmp(groupname1, groupname2) != 0) 1641 return (IPADM_INVALID_ARG); 1642 1643 groupname2[0] = '\0'; 1644 } 1645 1646 if ((ipadm_flags & IPADM_OPT_PERSIST) && 1647 (status = i_ipadm_persist_update_ipmp(iph, gifname, 1648 mifname, op)) != IPADM_SUCCESS) 1649 return (status); 1650 1651 return (i_ipadm_set_groupname_active(iph, mifname, groupname2)); 1652 } 1653 1654 /* 1655 * Call the ipmgmtd to update the IPMP configuration in ipadm DB. 1656 * After this call the DB will know that mifname is under gifname and 1657 * gifname has a member, which name is mifname. 1658 */ 1659 static ipadm_status_t 1660 i_ipadm_persist_update_ipmp(ipadm_handle_t iph, const char *gifname, 1661 const char *mifname, ipadm_ipmp_op_t op) 1662 { 1663 ipmgmt_ipmp_update_arg_t args; 1664 int err; 1665 1666 assert(op == IPADM_ADD_IPMP || op == IPADM_REMOVE_IPMP); 1667 1668 bzero(&args, sizeof (ipmgmt_ipmp_update_arg_t)); 1669 1670 args.ia_cmd = IPMGMT_CMD_IPMP_UPDATE; 1671 1672 (void) strlcpy(args.ia_gifname, gifname, sizeof (args.ia_gifname)); 1673 (void) strlcpy(args.ia_mifname, mifname, sizeof (args.ia_mifname)); 1674 1675 if (op == IPADM_ADD_IPMP) 1676 args.ia_flags = IPMGMT_APPEND; 1677 else 1678 args.ia_flags = IPMGMT_REMOVE; 1679 1680 args.ia_flags |= IPMGMT_PERSIST; 1681 1682 err = ipadm_door_call(iph, &args, sizeof (args), NULL, 0, B_FALSE); 1683 return (ipadm_errno2status(err)); 1684 } 1685 1686 /* 1687 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces 1688 * when `af' = AF_UNSPEC. 1689 */ 1690 ipadm_status_t 1691 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1692 uint32_t flags) 1693 { 1694 ipadm_status_t status1 = IPADM_SUCCESS; 1695 ipadm_status_t status2 = IPADM_SUCCESS; 1696 ipadm_status_t other; 1697 1698 /* Check for the required authorization */ 1699 if (!ipadm_check_auth()) 1700 return (IPADM_EAUTH); 1701 1702 /* Validate the `ifname' for any logical interface. */ 1703 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) || 1704 !i_ipadm_validate_ifname(iph, ifname)) 1705 return (IPADM_INVALID_ARG); 1706 1707 if (af == AF_INET || af == AF_UNSPEC) 1708 status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags); 1709 if (af == AF_INET6 || af == AF_UNSPEC) 1710 status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags); 1711 /* 1712 * If the family has been uniquely identified, we return the 1713 * associated status, even if that is ENXIO. Calls from ifconfig 1714 * which can only unplumb one of IPv4/IPv6 at any time fall under 1715 * this category. 1716 */ 1717 if (af == AF_INET) 1718 return (status1); 1719 else if (af == AF_INET6) 1720 return (status2); 1721 else if (af != AF_UNSPEC) 1722 return (IPADM_INVALID_ARG); 1723 1724 /* 1725 * If af is AF_UNSPEC, then we return the following: 1726 * status1, if status1 == status2 1727 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS 1728 * and the other status is ENXIO 1729 * IPADM_ENXIO, if both status1 and status2 are ENXIO 1730 * IPADM_FAILURE otherwise. 1731 */ 1732 if (status1 == status2) { 1733 /* covers the case when both status1 and status2 are ENXIO */ 1734 return (status1); 1735 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1736 if (status1 == IPADM_SUCCESS) 1737 other = status2; 1738 else 1739 other = status1; 1740 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1741 } else { 1742 return (IPADM_FAILURE); 1743 } 1744 } 1745 1746 /* 1747 * Returns information about all interfaces in both active and persistent 1748 * configuration. If `ifname' is not NULL, it returns only the interface 1749 * identified by `ifname'. 1750 * 1751 * Return values: 1752 * On success: IPADM_SUCCESS. 1753 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE. 1754 */ 1755 ipadm_status_t 1756 ipadm_if_info(ipadm_handle_t iph, const char *ifname, 1757 ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags) 1758 { 1759 ipadm_status_t status; 1760 ifspec_t ifsp; 1761 1762 if (if_info == NULL || iph == NULL || flags != 0) 1763 return (IPADM_INVALID_ARG); 1764 1765 if (ifname != NULL && 1766 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) { 1767 return (IPADM_INVALID_ARG); 1768 } 1769 1770 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags); 1771 if (status != IPADM_SUCCESS) 1772 return (status); 1773 if (ifname != NULL && *if_info == NULL) 1774 return (IPADM_ENXIO); 1775 1776 return (IPADM_SUCCESS); 1777 } 1778 1779 /* 1780 * Frees the linked list allocated by ipadm_if_info(). 1781 */ 1782 void 1783 ipadm_free_if_info(ipadm_if_info_t *ifinfo) 1784 { 1785 ipadm_if_info_t *ifinfo_next; 1786 1787 for (; ifinfo != NULL; ifinfo = ifinfo_next) { 1788 ifinfo_next = ifinfo->ifi_next; 1789 i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_cmembers); 1790 i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_pmembers); 1791 free(ifinfo); 1792 } 1793 } 1794 1795 static void 1796 i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *ipmp_members) 1797 { 1798 ipadm_ipmp_member_t *ipmp_member; 1799 1800 while ((ipmp_member = list_remove_head(ipmp_members)) != NULL) 1801 free(ipmp_member); 1802 1803 list_destroy(ipmp_members); 1804 } 1805 1806 /* 1807 * Re-enable the interface `ifname' based on the saved configuration 1808 * for `ifname'. 1809 */ 1810 ipadm_status_t 1811 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1812 { 1813 boolean_t set_init = B_FALSE; 1814 nvlist_t *ifnvl; 1815 ipadm_status_t status; 1816 ifspec_t ifsp; 1817 1818 /* Check for the required authorization */ 1819 if (!ipadm_check_auth()) 1820 return (IPADM_EAUTH); 1821 1822 /* Check for logical interfaces. */ 1823 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1824 return (IPADM_INVALID_ARG); 1825 1826 /* Enabling an interface persistently is not supported. */ 1827 if (flags & IPADM_OPT_PERSIST) 1828 return (IPADM_NOTSUP); 1829 1830 /* 1831 * Return early by checking if the interface is already enabled. 1832 */ 1833 if (ipadm_if_enabled(iph, ifname, AF_INET) && 1834 ipadm_if_enabled(iph, ifname, AF_INET6)) 1835 return (IPADM_IF_EXISTS); 1836 1837 /* 1838 * Enable the interface and restore all its interface properties 1839 * and address objects. 1840 */ 1841 status = i_ipadm_init_ifs(iph, ifname, &ifnvl); 1842 if (status != IPADM_SUCCESS) 1843 return (status); 1844 1845 assert(ifnvl != NULL); 1846 /* 1847 * ipadm_enable_if() does exactly what ipadm_init_ifs() does, 1848 * but only for one interface. We need to set IPH_INIT because 1849 * ipmgmtd daemon does not have to write the interface to the 1850 * persistent db. The interface is already available in the 1851 * persistent db and we are here to re-enable the persistent 1852 * configuration. 1853 * 1854 * But we need to make sure we're not accidentally clearing an 1855 * IPH_INIT flag that was already set when we were called. 1856 */ 1857 if ((iph->iph_flags & IPH_INIT) == 0) { 1858 iph->iph_flags |= IPH_INIT; 1859 set_init = B_TRUE; 1860 } 1861 1862 status = i_ipadm_init_ifobj(iph, ifname, ifnvl); 1863 1864 if (set_init) 1865 iph->iph_flags &= ~IPH_INIT; 1866 1867 nvlist_free(ifnvl); 1868 return (status); 1869 } 1870 1871 /* 1872 * Disable the interface `ifname' by removing it from the active configuration. 1873 * Error code return values follow the model in ipadm_delete_if() 1874 */ 1875 ipadm_status_t 1876 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1877 { 1878 ipadm_status_t status1, status2, other; 1879 ifspec_t ifsp; 1880 1881 /* Check for the required authorization */ 1882 if (!ipadm_check_auth()) 1883 return (IPADM_EAUTH); 1884 1885 /* Check for logical interfaces. */ 1886 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1887 return (IPADM_INVALID_ARG); 1888 1889 /* Disabling an interface persistently is not supported. */ 1890 if (flags & IPADM_OPT_PERSIST) 1891 return (IPADM_NOTSUP); 1892 1893 status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6); 1894 if (status1 == IPADM_SUCCESS) 1895 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE); 1896 status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET); 1897 if (status2 == IPADM_SUCCESS) 1898 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE); 1899 if (status1 == status2) { 1900 return (status2); 1901 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1902 if (status1 == IPADM_SUCCESS) 1903 other = status2; 1904 else 1905 other = status1; 1906 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1907 } else { 1908 return (IPADM_FAILURE); 1909 } 1910 } 1911 1912 /* 1913 * FIXME Remove this when ifconfig(1M) is updated to use IPMP support 1914 * in libipadm. 1915 */ 1916 /* 1917 * This workaround is required by ifconfig(1M) whenever an 1918 * interface is moved into an IPMP group to update the daemon's 1919 * in-memory mapping of `aobjname' to 'lifnum'. 1920 * 1921 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if 1922 * door_call(3C) fails. Also, there is no use in returning error because 1923 * `ifname' would have been successfuly moved into IPMP group, by this time. 1924 */ 1925 void 1926 ipadm_if_move(ipadm_handle_t iph, const char *ifname) 1927 { 1928 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE); 1929 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE); 1930 } 1931 1932 ipadm_status_t 1933 i_ipadm_set_groupname_active(ipadm_handle_t iph, const char *ifname, 1934 const char *groupname) 1935 { 1936 struct lifreq lifr; 1937 ipadm_addr_info_t *addrinfo, *ia; 1938 ipadm_status_t status = IPADM_SUCCESS; 1939 1940 (void) memset(&lifr, 0, sizeof (lifr)); 1941 1942 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 1943 (void) strlcpy(lifr.lifr_groupname, groupname, 1944 sizeof (lifr.lifr_groupname)); 1945 1946 /* Disable all addresses on the interface */ 1947 (void) i_ipadm_active_addr_info(iph, ifname, &addrinfo, 1948 IPADM_OPT_ACTIVE | IPADM_OPT_ZEROADDR, IFF_UP | IFF_DUPLICATE); 1949 1950 for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia)) { 1951 if (strlen(ia->ia_aobjname) > 0) { 1952 (void) ipadm_disable_addr(iph, ia->ia_aobjname, 0); 1953 } else { 1954 /* 1955 * There's an address on this interfaces with no 1956 * corresponding addrobj. Just clear IFF_UP. 1957 */ 1958 (void) i_ipadm_set_flags(iph, ifname, 1959 addrinfo->ia_ifa.ifa_addr->sa_family, 0, IFF_UP); 1960 } 1961 } 1962 1963 if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1 && 1964 ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1) 1965 status = ipadm_errno2status(errno); 1966 1967 /* Enable all addresses on the interface */ 1968 for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia)) { 1969 if (strlen(ia->ia_aobjname) > 0) { 1970 (void) ipadm_enable_addr(iph, ia->ia_aobjname, 0); 1971 } else { 1972 /* 1973 * There's an address on this interfaces with no 1974 * corresponding addrobj. Just set IFF_UP. 1975 */ 1976 (void) i_ipadm_set_flags(iph, ifname, 1977 addrinfo->ia_ifa.ifa_addr->sa_family, IFF_UP, 0); 1978 } 1979 } 1980 1981 if (status == IPADM_SUCCESS) { 1982 if (groupname[0] == '\0') { 1983 /* 1984 * If interface was removed from IPMP group, unset the 1985 * DEPRECATED and NOFAILOVER flags. 1986 */ 1987 (void) i_ipadm_set_flags(iph, ifname, AF_INET, 0, 1988 IFF_DEPRECATED | IFF_NOFAILOVER); 1989 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, 0, 1990 IFF_DEPRECATED | IFF_NOFAILOVER); 1991 } else if (addrinfo == NULL) { 1992 /* 1993 * If interface was added to IPMP group and there are no 1994 * active addresses, explicitly bring it up to be used 1995 * for link-based IPMP configuration. 1996 */ 1997 (void) i_ipadm_set_flags(iph, ifname, AF_INET, 1998 IFF_UP, 0); 1999 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, 2000 IFF_UP, 0); 2001 } 2002 } 2003 2004 ipadm_free_addr_info(addrinfo); 2005 2006 return (status); 2007 } 2008 2009 ipadm_status_t 2010 i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname, 2011 char *groupname, size_t size) 2012 { 2013 struct lifreq lifr; 2014 2015 (void) memset(&lifr, 0, sizeof (lifr)); 2016 2017 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2018 2019 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1 && 2020 ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1) 2021 return (ipadm_errno2status(errno)); 2022 2023 (void) strlcpy(groupname, lifr.lifr_groupname, size); 2024 2025 return (IPADM_SUCCESS); 2026 } 2027 2028 /* 2029 * Returns B_TRUE if `ifname' represents an IPMP underlying interface. 2030 */ 2031 boolean_t 2032 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname) 2033 { 2034 2035 char groupname[LIFGRNAMSIZ]; 2036 2037 if (i_ipadm_get_groupname_active(iph, ifname, groupname, 2038 sizeof (groupname)) != IPADM_SUCCESS || 2039 groupname[0] == '\0' || 2040 strcmp(ifname, groupname) == 0) 2041 return (B_FALSE); 2042 2043 return (B_TRUE); 2044 } 2045 2046 /* 2047 * Returns B_TRUE if `ifname' represents an IPMP group interface. 2048 */ 2049 boolean_t 2050 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname) 2051 { 2052 uint64_t flags; 2053 2054 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS && 2055 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS) 2056 return (B_FALSE); 2057 2058 return ((flags & IFF_IPMP) != 0); 2059 } 2060