213 * Retrieves the static address (IPv4 or IPv6) for the given address object
214 * in `ipaddr' from persistent DB.
215 */
216 static ipadm_status_t
217 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
218 {
219 ipadm_status_t status;
220 nvlist_t *onvl;
221 nvlist_t *anvl = NULL;
222 nvlist_t *nvladdr;
223 nvpair_t *nvp;
224 char *name;
225 char *aobjname = ipaddr->ipadm_aobjname;
226 char *sname;
227 sa_family_t af = AF_UNSPEC;
228
229 /*
230 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
231 */
232 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
233 if (status != IPADM_SUCCESS)
234 return (status);
235 /*
236 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
237 * or the IPADM_NVP_IPV6ADDR name-value pair.
238 */
239 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
240 nvp = nvlist_next_nvpair(onvl, NULL)) {
241 if (nvpair_value_nvlist(nvp, &anvl) != 0)
242 continue;
243 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
244 nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
245 break;
246 }
247 if (nvp == NULL)
248 goto fail;
249 for (nvp = nvlist_next_nvpair(anvl, NULL);
250 nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
251 name = nvpair_name(nvp);
252 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
253 af = AF_INET;
254 break;
255 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
256 af = AF_INET6;
257 break;
258 }
259 }
260 assert(af != AF_UNSPEC);
261 if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
262 nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
263 ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
264 goto fail;
265 }
266 nvlist_free(onvl);
267 return (IPADM_SUCCESS);
268 fail:
269 nvlist_free(onvl);
270 return (IPADM_NOTFOUND);
271 }
272
273 /*
274 * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
275 * fills in the address objname, the address type and the ipadm_flags.
276 */
277 ipadm_status_t
278 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
279 {
280 ipmgmt_aobjop_arg_t larg;
281 ipmgmt_aobjop_rval_t rval, *rvalp;
282 int err;
283
284 larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
1496 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1497 (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1498 return (IPADM_INVALID_ARG);
1499 }
1500
1501 /*
1502 * For the given aobjname, get the addrobj it represents and
1503 * set the property value for that object.
1504 */
1505 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1506 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1507 return (status);
1508
1509 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1510 return (IPADM_OP_DISABLE_OBJ);
1511
1512 /* Persistent operation not allowed on a temporary object. */
1513 if ((pflags & IPADM_OPT_PERSIST) &&
1514 !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1515 return (IPADM_TEMPORARY_OBJ);
1516
1517 /*
1518 * Currently, setting an address property on an address object of type
1519 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1520 * in.ndpd retrieving the address properties from ipmgmtd for given
1521 * address object and then setting them on auto-configured addresses,
1522 * whenever in.ndpd gets a new prefix. This will be supported in
1523 * future releases.
1524 */
1525 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1526 return (IPADM_NOTSUP);
1527
1528 /*
1529 * Setting an address property on an address object that is
1530 * not present in active configuration is not supported.
1531 */
1532 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1533 return (IPADM_NOTSUP);
1534
1535 af = ipaddr.ipadm_af;
1536 if (reset) {
2015 err = nvpair_value_string(nvp, &sname);
2016 else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
2017 err = nvpair_value_string(nvp, &dname);
2018 if (err != 0)
2019 return (ipadm_errno2status(err));
2020 }
2021
2022 if (strcmp(upstr, "yes") == 0)
2023 flags |= IPADM_OPT_UP;
2024
2025 /* build the address object from the above information */
2026 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
2027 if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
2028 if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
2029 return (IPADM_NO_MEMORY);
2030 status = ipadm_set_addr(&ipaddr, cidraddr, af);
2031 free(cidraddr);
2032 } else {
2033 status = ipadm_set_addr(&ipaddr, sname, af);
2034 }
2035 if (status != IPADM_SUCCESS)
2036 return (status);
2037
2038 if (dname != NULL) {
2039 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2040 if (status != IPADM_SUCCESS)
2041 return (status);
2042 }
2043 return (i_ipadm_create_addr(iph, &ipaddr, flags));
2044 }
2045
2046 /*
2047 * Creates a dhcp address on the interface `ifname' based on the
2048 * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2049 */
2050 ipadm_status_t
2051 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2052 {
2053 int32_t wait;
2054 boolean_t primary;
2055 nvlist_t *nvdhcp;
2056 nvpair_t *nvp;
2161 ipadm_addrobj_t newaddr;
2162 ipadm_status_t status;
2163 char *aname, *cp;
2164 char ifname[IPADM_AOBJSIZ];
2165 ifspec_t ifsp;
2166
2167 if (ipaddr == NULL)
2168 return (IPADM_INVALID_ARG);
2169 *ipaddr = NULL;
2170
2171 if (aobjname == NULL || aobjname[0] == '\0')
2172 return (IPADM_INVALID_ARG);
2173
2174 if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2175 return (IPADM_INVALID_ARG);
2176
2177 if ((aname = strchr(ifname, '/')) != NULL)
2178 *aname++ = '\0';
2179
2180 /* Check if the interface name is valid. */
2181 if (!ifparse_ifspec(ifname, &ifsp))
2182 return (IPADM_INVALID_ARG);
2183
2184 /* Check if the given addrobj name is valid. */
2185 if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2186 return (IPADM_INVALID_ARG);
2187
2188 if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2189 return (IPADM_NO_MEMORY);
2190
2191 /*
2192 * If the ifname has logical interface number, extract it and assign
2193 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2194 * this today. We will check for the validity later in
2195 * i_ipadm_validate_create_addr().
2196 */
2197 if (ifsp.ifsp_lunvalid) {
2198 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2199 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2200 *cp = '\0';
2201 }
2202 (void) strlcpy(newaddr->ipadm_ifname, ifname,
2203 sizeof (newaddr->ipadm_ifname));
2204
2205 if (aname != NULL) {
2206 (void) snprintf(newaddr->ipadm_aobjname,
2207 sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
2349 iph->iph_sock6);
2350 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2351 return (ipadm_errno2status(errno));
2352 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2353 }
2354 return (IPADM_SUCCESS);
2355 }
2356
2357 /*
2358 * Reads all the address lines from the persistent DB into the nvlist `onvl',
2359 * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2360 * it returns all the addresses for the given interface `ifname'.
2361 * If an `aobjname' is specified, then the address line corresponding to
2362 * that name will be returned.
2363 */
2364 static ipadm_status_t
2365 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2366 const char *aobjname, nvlist_t **onvl)
2367 {
2368 ipmgmt_getaddr_arg_t garg;
2369 ipmgmt_get_rval_t *rvalp;
2370 int err;
2371 size_t nvlsize;
2372 char *nvlbuf;
2373
2374 /* Populate the door_call argument structure */
2375 bzero(&garg, sizeof (garg));
2376 garg.ia_cmd = IPMGMT_CMD_GETADDR;
2377 if (aobjname != NULL)
2378 (void) strlcpy(garg.ia_aobjname, aobjname,
2379 sizeof (garg.ia_aobjname));
2380 if (ifname != NULL)
2381 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2382
2383 rvalp = malloc(sizeof (ipmgmt_get_rval_t));
2384 err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
2385 sizeof (*rvalp), B_TRUE);
2386 if (err == 0) {
2387 nvlsize = rvalp->ir_nvlsize;
2388 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
2389 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
2390 }
2391 free(rvalp);
2392 return (ipadm_errno2status(err));
2393 }
2394
2395 /*
2396 * Adds the IP address contained in the 'ipaddr' argument to the physical
2397 * interface represented by 'ifname' after doing the required validation.
2398 * If the interface does not exist, it is created before the address is
2399 * added.
2400 *
2401 * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2402 * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2403 * if provided, will be ignored and replaced with the newly generated name.
2404 * The interface name provided has to be a logical interface name that
2405 * already exists. No new logical interface will be added in this function.
2406 *
2407 * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2408 * are plumbed (if they haven't been already). Otherwise, just the interface
2409 * specified in `addr' is plumbed.
2410 */
2411 ipadm_status_t
2412 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2415 sa_family_t af;
2416 sa_family_t daf;
2417 sa_family_t other_af;
2418 boolean_t created_af = B_FALSE;
2419 boolean_t created_other_af = B_FALSE;
2420 ipadm_addr_type_t type;
2421 char *ifname = addr->ipadm_ifname;
2422 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2423 boolean_t aobjfound;
2424 boolean_t is_6to4;
2425 struct lifreq lifr;
2426 uint64_t ifflags;
2427 boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD);
2428
2429 /* check for solaris.network.interface.config authorization */
2430 if (!ipadm_check_auth())
2431 return (IPADM_EAUTH);
2432
2433 /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2434 status = i_ipadm_validate_create_addr(iph, addr, flags);
2435 if (status != IPADM_SUCCESS)
2436 return (status);
2437
2438 /*
2439 * For Legacy case, check if an addrobj already exists for the
2440 * given logical interface name. If one does not exist,
2441 * a default name will be generated and added to the daemon's
2442 * aobjmap.
2443 */
2444 if (legacy) {
2445 struct ipadm_addrobj_s ipaddr;
2446
2447 ipaddr = *addr;
2448 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2449 if (status == IPADM_SUCCESS) {
2450 aobjfound = B_TRUE;
2451 /*
2452 * With IPH_LEGACY, modifying an address that is not
2453 * a static address will return with an error.
2454 */
2455 if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2456 return (IPADM_NOTSUP);
2457 /*
2464 aobjfound = B_FALSE;
2465 } else {
2466 return (status);
2467 }
2468 }
2469
2470 af = addr->ipadm_af;
2471 /*
2472 * Create a placeholder for this address object in the daemon.
2473 * Skip this step if we are booting a zone (and therefore being called
2474 * from ipmgmtd itself), and, for IPH_LEGACY case if the
2475 * addrobj already exists.
2476 *
2477 * Note that the placeholder is not needed in the NGZ boot case,
2478 * when zoneadmd has itself applied the "allowed-ips" property to clamp
2479 * down any interface configuration, so the namespace for the interface
2480 * is fully controlled by the GZ.
2481 */
2482 if (!is_boot && (!legacy || !aobjfound)) {
2483 status = i_ipadm_lookupadd_addrobj(iph, addr);
2484 if (status != IPADM_SUCCESS)
2485 return (status);
2486 }
2487
2488 is_6to4 = i_ipadm_is_6to4(iph, ifname);
2489 /* Plumb the IP interfaces if necessary */
2490 status = i_ipadm_create_if(iph, ifname, af, flags);
2491 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2492 (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
2493 return (status);
2494 }
2495 if (status == IPADM_SUCCESS)
2496 created_af = B_TRUE;
2497 if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
2498 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
2499 status = i_ipadm_create_if(iph, ifname, other_af, flags);
2500 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2501 (void) i_ipadm_delete_if(iph, ifname, af, flags);
2502 return (status);
2503 }
2504 if (status == IPADM_SUCCESS)
2505 created_other_af = B_TRUE;
2506 }
2614 }
2615 }
2616
2617 return (status);
2618 }
2619
2620 /*
2621 * Creates the static address in `ipaddr' in kernel. After successfully
2622 * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
2623 * interface information.
2624 */
2625 static ipadm_status_t
2626 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
2627 {
2628 struct lifreq lifr;
2629 ipadm_status_t status = IPADM_SUCCESS;
2630 int sock;
2631 struct sockaddr_storage m, *mask = &m;
2632 const struct sockaddr_storage *addr = &ipaddr->ipadm_static_addr;
2633 const struct sockaddr_storage *daddr = &ipaddr->ipadm_static_dst_addr;
2634 sa_family_t af;
2635 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2636 struct ipadm_addrobj_s legacy_addr;
2637 boolean_t default_prefixlen = B_FALSE;
2638 boolean_t is_boot;
2639
2640 is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
2641 af = ipaddr->ipadm_af;
2642 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2643
2644 /* If prefixlen was not provided, get default prefixlen */
2645 if (ipaddr->ipadm_static_prefixlen == 0) {
2646 /* prefixlen was not provided, get default prefixlen */
2647 status = i_ipadm_get_default_prefixlen(
2648 &ipaddr->ipadm_static_addr,
2649 &ipaddr->ipadm_static_prefixlen);
2650 if (status != IPADM_SUCCESS)
2651 return (status);
2652 default_prefixlen = B_TRUE;
2653 }
2683 lifr.lifr_addr = *mask;
2684 if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2685 status = ipadm_errno2status(errno);
2686 goto ret;
2687 }
2688 lifr.lifr_addr = *addr;
2689 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2690 status = ipadm_errno2status(errno);
2691 goto ret;
2692 }
2693 /* Set the destination address, if one is given. */
2694 if (daddr->ss_family != AF_UNSPEC) {
2695 lifr.lifr_addr = *daddr;
2696 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2697 status = ipadm_errno2status(errno);
2698 goto ret;
2699 }
2700 }
2701
2702 if (flags & IPADM_OPT_UP) {
2703 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
2704
2705 /*
2706 * IPADM_DAD_FOUND is a soft-error for create-addr.
2707 * No need to tear down the address.
2708 */
2709 if (status == IPADM_DAD_FOUND)
2710 status = IPADM_SUCCESS;
2711 }
2712
2713 if (status == IPADM_SUCCESS && !is_boot) {
2714 /*
2715 * For IPH_LEGACY, we might be modifying the address on
2716 * an address object that already exists e.g. by doing
2717 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2718 * So, we need to store the object only if it does not
2719 * already exist in ipmgmtd.
2720 */
2721 if (legacy) {
2722 bzero(&legacy_addr, sizeof (legacy_addr));
2723 (void) strlcpy(legacy_addr.ipadm_aobjname,
3186 ipadm_status_t status;
3187 char lifname[LIFNAMSIZ];
3188
3189 /* check for solaris.network.interface.config authorization */
3190 if (!ipadm_check_auth())
3191 return (IPADM_EAUTH);
3192
3193 /* validate input */
3194 if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3195 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3196 return (IPADM_INVALID_ARG);
3197 }
3198
3199 /* Retrieve the address object information. */
3200 status = i_ipadm_get_addrobj(iph, ipaddr);
3201 if (status != IPADM_SUCCESS)
3202 return (status);
3203
3204 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3205 return (IPADM_OP_DISABLE_OBJ);
3206 if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3207 !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3208 return (IPADM_TEMPORARY_OBJ);
3209 if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3210 (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3211 (ipadm_flags & IPADM_OPT_PERSIST)))
3212 return (IPADM_NOTSUP);
3213
3214 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3215 return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3216 }
3217
3218 /*
3219 * Marks the address in the address object `aobjname' up. This operation is
3220 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3221 * For an address object of type IPADM_ADDR_DHCP, this operation can
3222 * only be temporary and no updates will be made to the persistent DB.
3223 */
3224 ipadm_status_t
3225 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3226 {
3227 struct ipadm_addrobj_s ipaddr;
3228 ipadm_status_t status;
3229 uint64_t flags;
3230 char lifname[LIFNAMSIZ];
3231
3232 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3233 &flags);
3234 if (status != IPADM_SUCCESS)
3406 uint64_t ifflags = 0;
3407 boolean_t p_exists;
3408 boolean_t af_exists, other_af_exists, a_exists;
3409
3410 if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3411 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3412 return (IPADM_INVALID_ARG);
3413 }
3414
3415 if (ipaddr->ipadm_af == AF_UNSPEC)
3416 return (IPADM_BAD_ADDR);
3417
3418 if (!legacy && ipaddr->ipadm_lifnum != 0)
3419 return (IPADM_INVALID_ARG);
3420
3421 if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3422 return (IPADM_NOTSUP);
3423
3424 ifname = ipaddr->ipadm_ifname;
3425
3426 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
3427 return (IPADM_NOTSUP);
3428
3429 af = ipaddr->ipadm_af;
3430 af_exists = ipadm_if_enabled(iph, ifname, af);
3431 /*
3432 * For legacy case, interfaces are not implicitly plumbed. We need to
3433 * check if the interface exists in the active configuration.
3434 */
3435 if (legacy && !af_exists)
3436 return (IPADM_ENXIO);
3437
3438 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3439 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3440 /*
3441 * Check if one of the v4 or the v6 interfaces exists in the
3442 * active configuration. An interface is considered disabled only
3443 * if both v4 and v6 are not active.
3444 */
3445 a_exists = (af_exists || other_af_exists);
3446
3447 /* Check if interface exists in the persistent configuration. */
3448 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3449 if (status != IPADM_SUCCESS)
3450 return (status);
3451 if (!a_exists && p_exists)
3452 return (IPADM_OP_DISABLE_OBJ);
3453 if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
3454 /*
3455 * If address has to be created persistently,
3456 * and the interface does not exist in the persistent
3457 * store but in active config, fail.
3458 */
3459 return (IPADM_TEMPORARY_OBJ);
3460 }
3461 if (af_exists) {
3462 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3463 if (status != IPADM_SUCCESS)
3464 return (status);
3465 }
3466
3467 /* Perform validation steps (4) and (5) */
3468 islo = i_ipadm_is_loopback(ifname);
3469 isvni = i_ipadm_is_vni(ifname);
3470 switch (ipaddr->ipadm_atype) {
3471 case IPADM_ADDR_STATIC:
3472 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3473 return (IPADM_INVALID_ARG);
3474 /* Check for a valid src address */
3475 if (!legacy && sockaddrunspec(
3476 (struct sockaddr *)&ipaddr->ipadm_static_addr))
3477 return (IPADM_BAD_ADDR);
3478 break;
3479 case IPADM_ADDR_DHCP:
3480 if (islo || (ifflags & IFF_VRRP))
|
213 * Retrieves the static address (IPv4 or IPv6) for the given address object
214 * in `ipaddr' from persistent DB.
215 */
216 static ipadm_status_t
217 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
218 {
219 ipadm_status_t status;
220 nvlist_t *onvl;
221 nvlist_t *anvl = NULL;
222 nvlist_t *nvladdr;
223 nvpair_t *nvp;
224 char *name;
225 char *aobjname = ipaddr->ipadm_aobjname;
226 char *sname;
227 sa_family_t af = AF_UNSPEC;
228
229 /*
230 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
231 */
232 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
233 if (status != IPADM_SUCCESS) {
234 return (status);
235 }
236 /*
237 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
238 * or the IPADM_NVP_IPV6ADDR name-value pair.
239 */
240 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
241 nvp = nvlist_next_nvpair(onvl, NULL)) {
242 if (nvpair_value_nvlist(nvp, &anvl) != 0)
243 continue;
244 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
245 nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
246 break;
247 }
248 if (nvp == NULL)
249 goto fail;
250 for (nvp = nvlist_next_nvpair(anvl, NULL);
251 nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
252 name = nvpair_name(nvp);
253 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
254 af = AF_INET;
255 break;
256 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
257 af = AF_INET6;
258 break;
259 }
260 }
261 assert(af != AF_UNSPEC);
262 if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
263 nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0)
264 goto fail;
265
266 if (ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
267 goto fail;
268 }
269 nvlist_free(onvl);
270 return (IPADM_SUCCESS);
271 fail:
272 nvlist_free(onvl);
273 return (IPADM_NOTFOUND);
274 }
275
276 /*
277 * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
278 * fills in the address objname, the address type and the ipadm_flags.
279 */
280 ipadm_status_t
281 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
282 {
283 ipmgmt_aobjop_arg_t larg;
284 ipmgmt_aobjop_rval_t rval, *rvalp;
285 int err;
286
287 larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
1499 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1500 (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1501 return (IPADM_INVALID_ARG);
1502 }
1503
1504 /*
1505 * For the given aobjname, get the addrobj it represents and
1506 * set the property value for that object.
1507 */
1508 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1509 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1510 return (status);
1511
1512 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1513 return (IPADM_OP_DISABLE_OBJ);
1514
1515 /* Persistent operation not allowed on a temporary object. */
1516 if ((pflags & IPADM_OPT_PERSIST) &&
1517 !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1518 return (IPADM_TEMPORARY_OBJ);
1519 /*
1520 * Currently, setting an address property on an address object of type
1521 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1522 * in.ndpd retrieving the address properties from ipmgmtd for given
1523 * address object and then setting them on auto-configured addresses,
1524 * whenever in.ndpd gets a new prefix. This will be supported in
1525 * future releases.
1526 */
1527 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1528 return (IPADM_NOTSUP);
1529
1530 /*
1531 * Setting an address property on an address object that is
1532 * not present in active configuration is not supported.
1533 */
1534 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1535 return (IPADM_NOTSUP);
1536
1537 af = ipaddr.ipadm_af;
1538 if (reset) {
2017 err = nvpair_value_string(nvp, &sname);
2018 else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
2019 err = nvpair_value_string(nvp, &dname);
2020 if (err != 0)
2021 return (ipadm_errno2status(err));
2022 }
2023
2024 if (strcmp(upstr, "yes") == 0)
2025 flags |= IPADM_OPT_UP;
2026
2027 /* build the address object from the above information */
2028 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
2029 if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
2030 if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
2031 return (IPADM_NO_MEMORY);
2032 status = ipadm_set_addr(&ipaddr, cidraddr, af);
2033 free(cidraddr);
2034 } else {
2035 status = ipadm_set_addr(&ipaddr, sname, af);
2036 }
2037 // if (status != IPADM_SUCCESS)
2038 // return (status);
2039
2040 if (dname != NULL) {
2041 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2042 if (status != IPADM_SUCCESS)
2043 return (status);
2044 }
2045 return (i_ipadm_create_addr(iph, &ipaddr, flags));
2046 }
2047
2048 /*
2049 * Creates a dhcp address on the interface `ifname' based on the
2050 * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2051 */
2052 ipadm_status_t
2053 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2054 {
2055 int32_t wait;
2056 boolean_t primary;
2057 nvlist_t *nvdhcp;
2058 nvpair_t *nvp;
2163 ipadm_addrobj_t newaddr;
2164 ipadm_status_t status;
2165 char *aname, *cp;
2166 char ifname[IPADM_AOBJSIZ];
2167 ifspec_t ifsp;
2168
2169 if (ipaddr == NULL)
2170 return (IPADM_INVALID_ARG);
2171 *ipaddr = NULL;
2172
2173 if (aobjname == NULL || aobjname[0] == '\0')
2174 return (IPADM_INVALID_ARG);
2175
2176 if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2177 return (IPADM_INVALID_ARG);
2178
2179 if ((aname = strchr(ifname, '/')) != NULL)
2180 *aname++ = '\0';
2181
2182 /* Check if the interface name is valid. */
2183 if (!ifparse_ifspec(ifname, &ifsp)) {
2184 return (IPADM_INVALID_ARG);
2185 }
2186 /* Check if the given addrobj name is valid. */
2187 if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname)) {
2188 return (IPADM_INVALID_ARG);
2189 }
2190 if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2191 return (IPADM_NO_MEMORY);
2192
2193 /*
2194 * If the ifname has logical interface number, extract it and assign
2195 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2196 * this today. We will check for the validity later in
2197 * i_ipadm_validate_create_addr().
2198 */
2199 if (ifsp.ifsp_lunvalid) {
2200 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2201 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2202 *cp = '\0';
2203 }
2204 (void) strlcpy(newaddr->ipadm_ifname, ifname,
2205 sizeof (newaddr->ipadm_ifname));
2206
2207 if (aname != NULL) {
2208 (void) snprintf(newaddr->ipadm_aobjname,
2209 sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
2351 iph->iph_sock6);
2352 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2353 return (ipadm_errno2status(errno));
2354 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2355 }
2356 return (IPADM_SUCCESS);
2357 }
2358
2359 /*
2360 * Reads all the address lines from the persistent DB into the nvlist `onvl',
2361 * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2362 * it returns all the addresses for the given interface `ifname'.
2363 * If an `aobjname' is specified, then the address line corresponding to
2364 * that name will be returned.
2365 */
2366 static ipadm_status_t
2367 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2368 const char *aobjname, nvlist_t **onvl)
2369 {
2370 ipmgmt_getaddr_arg_t garg;
2371
2372 /* Populate the door_call argument structure */
2373 bzero(&garg, sizeof (garg));
2374 garg.ia_cmd = IPMGMT_CMD_GETADDR;
2375 if (aobjname != NULL)
2376 (void) strlcpy(garg.ia_aobjname, aobjname,
2377 sizeof (garg.ia_aobjname));
2378 if (ifname != NULL)
2379 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2380
2381 return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
2382 }
2383
2384 /*
2385 * Adds the IP address contained in the 'ipaddr' argument to the physical
2386 * interface represented by 'ifname' after doing the required validation.
2387 * If the interface does not exist, it is created before the address is
2388 * added.
2389 *
2390 * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2391 * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2392 * if provided, will be ignored and replaced with the newly generated name.
2393 * The interface name provided has to be a logical interface name that
2394 * already exists. No new logical interface will be added in this function.
2395 *
2396 * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2397 * are plumbed (if they haven't been already). Otherwise, just the interface
2398 * specified in `addr' is plumbed.
2399 */
2400 ipadm_status_t
2401 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2404 sa_family_t af;
2405 sa_family_t daf;
2406 sa_family_t other_af;
2407 boolean_t created_af = B_FALSE;
2408 boolean_t created_other_af = B_FALSE;
2409 ipadm_addr_type_t type;
2410 char *ifname = addr->ipadm_ifname;
2411 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2412 boolean_t aobjfound;
2413 boolean_t is_6to4;
2414 struct lifreq lifr;
2415 uint64_t ifflags;
2416 boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD);
2417
2418 /* check for solaris.network.interface.config authorization */
2419 if (!ipadm_check_auth())
2420 return (IPADM_EAUTH);
2421
2422 /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2423 status = i_ipadm_validate_create_addr(iph, addr, flags);
2424 if (status != IPADM_SUCCESS) {
2425 return (status);
2426 }
2427 /*
2428 * For Legacy case, check if an addrobj already exists for the
2429 * given logical interface name. If one does not exist,
2430 * a default name will be generated and added to the daemon's
2431 * aobjmap.
2432 */
2433 if (legacy) {
2434 struct ipadm_addrobj_s ipaddr;
2435
2436 ipaddr = *addr;
2437 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2438 if (status == IPADM_SUCCESS) {
2439 aobjfound = B_TRUE;
2440 /*
2441 * With IPH_LEGACY, modifying an address that is not
2442 * a static address will return with an error.
2443 */
2444 if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2445 return (IPADM_NOTSUP);
2446 /*
2453 aobjfound = B_FALSE;
2454 } else {
2455 return (status);
2456 }
2457 }
2458
2459 af = addr->ipadm_af;
2460 /*
2461 * Create a placeholder for this address object in the daemon.
2462 * Skip this step if we are booting a zone (and therefore being called
2463 * from ipmgmtd itself), and, for IPH_LEGACY case if the
2464 * addrobj already exists.
2465 *
2466 * Note that the placeholder is not needed in the NGZ boot case,
2467 * when zoneadmd has itself applied the "allowed-ips" property to clamp
2468 * down any interface configuration, so the namespace for the interface
2469 * is fully controlled by the GZ.
2470 */
2471 if (!is_boot && (!legacy || !aobjfound)) {
2472 status = i_ipadm_lookupadd_addrobj(iph, addr);
2473 if (status != IPADM_SUCCESS) {
2474 return (status);
2475 }
2476 }
2477
2478 is_6to4 = i_ipadm_is_6to4(iph, ifname);
2479 /* Plumb the IP interfaces if necessary */
2480 status = i_ipadm_create_if(iph, ifname, af, flags);
2481 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2482 (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
2483 return (status);
2484 }
2485 if (status == IPADM_SUCCESS)
2486 created_af = B_TRUE;
2487 if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
2488 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
2489 status = i_ipadm_create_if(iph, ifname, other_af, flags);
2490 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2491 (void) i_ipadm_delete_if(iph, ifname, af, flags);
2492 return (status);
2493 }
2494 if (status == IPADM_SUCCESS)
2495 created_other_af = B_TRUE;
2496 }
2604 }
2605 }
2606
2607 return (status);
2608 }
2609
2610 /*
2611 * Creates the static address in `ipaddr' in kernel. After successfully
2612 * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
2613 * interface information.
2614 */
2615 static ipadm_status_t
2616 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
2617 {
2618 struct lifreq lifr;
2619 ipadm_status_t status = IPADM_SUCCESS;
2620 int sock;
2621 struct sockaddr_storage m, *mask = &m;
2622 const struct sockaddr_storage *addr = &ipaddr->ipadm_static_addr;
2623 const struct sockaddr_storage *daddr = &ipaddr->ipadm_static_dst_addr;
2624 uint32_t iff_flags = IFF_UP;
2625 sa_family_t af;
2626 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2627 struct ipadm_addrobj_s legacy_addr;
2628 boolean_t default_prefixlen = B_FALSE;
2629 boolean_t is_boot;
2630
2631 is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
2632 af = ipaddr->ipadm_af;
2633 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2634
2635 /* If prefixlen was not provided, get default prefixlen */
2636 if (ipaddr->ipadm_static_prefixlen == 0) {
2637 /* prefixlen was not provided, get default prefixlen */
2638 status = i_ipadm_get_default_prefixlen(
2639 &ipaddr->ipadm_static_addr,
2640 &ipaddr->ipadm_static_prefixlen);
2641 if (status != IPADM_SUCCESS)
2642 return (status);
2643 default_prefixlen = B_TRUE;
2644 }
2674 lifr.lifr_addr = *mask;
2675 if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2676 status = ipadm_errno2status(errno);
2677 goto ret;
2678 }
2679 lifr.lifr_addr = *addr;
2680 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2681 status = ipadm_errno2status(errno);
2682 goto ret;
2683 }
2684 /* Set the destination address, if one is given. */
2685 if (daddr->ss_family != AF_UNSPEC) {
2686 lifr.lifr_addr = *daddr;
2687 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2688 status = ipadm_errno2status(errno);
2689 goto ret;
2690 }
2691 }
2692
2693 if (flags & IPADM_OPT_UP) {
2694 if (i_ipadm_is_under_ipmp(iph, lifr.lifr_name)) {
2695 iff_flags |= IFF_NOFAILOVER;
2696 }
2697 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, iff_flags, 0);
2698
2699 /*
2700 * IPADM_DAD_FOUND is a soft-error for create-addr.
2701 * No need to tear down the address.
2702 */
2703 if (status == IPADM_DAD_FOUND)
2704 status = IPADM_SUCCESS;
2705 }
2706
2707 if (status == IPADM_SUCCESS && !is_boot) {
2708 /*
2709 * For IPH_LEGACY, we might be modifying the address on
2710 * an address object that already exists e.g. by doing
2711 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2712 * So, we need to store the object only if it does not
2713 * already exist in ipmgmtd.
2714 */
2715 if (legacy) {
2716 bzero(&legacy_addr, sizeof (legacy_addr));
2717 (void) strlcpy(legacy_addr.ipadm_aobjname,
3180 ipadm_status_t status;
3181 char lifname[LIFNAMSIZ];
3182
3183 /* check for solaris.network.interface.config authorization */
3184 if (!ipadm_check_auth())
3185 return (IPADM_EAUTH);
3186
3187 /* validate input */
3188 if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3189 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3190 return (IPADM_INVALID_ARG);
3191 }
3192
3193 /* Retrieve the address object information. */
3194 status = i_ipadm_get_addrobj(iph, ipaddr);
3195 if (status != IPADM_SUCCESS)
3196 return (status);
3197
3198 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3199 return (IPADM_OP_DISABLE_OBJ);
3200
3201 if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3202 !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3203 return (IPADM_TEMPORARY_OBJ);
3204
3205 if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3206 (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3207 (ipadm_flags & IPADM_OPT_PERSIST)))
3208 return (IPADM_NOTSUP);
3209
3210 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3211
3212 return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3213 }
3214
3215 /*
3216 * Marks the address in the address object `aobjname' up. This operation is
3217 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3218 * For an address object of type IPADM_ADDR_DHCP, this operation can
3219 * only be temporary and no updates will be made to the persistent DB.
3220 */
3221 ipadm_status_t
3222 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3223 {
3224 struct ipadm_addrobj_s ipaddr;
3225 ipadm_status_t status;
3226 uint64_t flags;
3227 char lifname[LIFNAMSIZ];
3228
3229 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3230 &flags);
3231 if (status != IPADM_SUCCESS)
3403 uint64_t ifflags = 0;
3404 boolean_t p_exists;
3405 boolean_t af_exists, other_af_exists, a_exists;
3406
3407 if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3408 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3409 return (IPADM_INVALID_ARG);
3410 }
3411
3412 if (ipaddr->ipadm_af == AF_UNSPEC)
3413 return (IPADM_BAD_ADDR);
3414
3415 if (!legacy && ipaddr->ipadm_lifnum != 0)
3416 return (IPADM_INVALID_ARG);
3417
3418 if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3419 return (IPADM_NOTSUP);
3420
3421 ifname = ipaddr->ipadm_ifname;
3422
3423 /*
3424 * do not go furhter when we are under ipmp.
3425 * The interface is plumbed up and we are going to add
3426 * NOFAILOVER address to make in.mpathd happy.
3427 */
3428 if (i_ipadm_is_under_ipmp(iph, ifname))
3429 return (IPADM_SUCCESS);
3430
3431 af = ipaddr->ipadm_af;
3432 af_exists = ipadm_if_enabled(iph, ifname, af);
3433 /*
3434 * For legacy case, interfaces are not implicitly plumbed. We need to
3435 * check if the interface exists in the active configuration.
3436 */
3437 if (legacy && !af_exists)
3438 return (IPADM_ENXIO);
3439
3440 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3441 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3442 /*
3443 * Check if one of the v4 or the v6 interfaces exists in the
3444 * active configuration. An interface is considered disabled only
3445 * if both v4 and v6 are not active.
3446 */
3447 a_exists = (af_exists || other_af_exists);
3448
3449 /* Check if interface exists in the persistent configuration. */
3450 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3451 if (status != IPADM_SUCCESS)
3452 return (status);
3453
3454 if (!a_exists && p_exists)
3455 return (IPADM_OP_DISABLE_OBJ);
3456
3457 if (af_exists) {
3458 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3459 if (status != IPADM_SUCCESS)
3460 return (status);
3461 }
3462
3463 /* Perform validation steps (4) and (5) */
3464 islo = i_ipadm_is_loopback(ifname);
3465 isvni = i_ipadm_is_vni(ifname);
3466 switch (ipaddr->ipadm_atype) {
3467 case IPADM_ADDR_STATIC:
3468 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3469 return (IPADM_INVALID_ARG);
3470 /* Check for a valid src address */
3471 if (!legacy && sockaddrunspec(
3472 (struct sockaddr *)&ipaddr->ipadm_static_addr))
3473 return (IPADM_BAD_ADDR);
3474 break;
3475 case IPADM_ADDR_DHCP:
3476 if (islo || (ifflags & IFF_VRRP))
|