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