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