Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-ipv6-addrconf-ensure-that-temporary-addresses-preferred-lifetimes-are-long-enough'

Alex Henrie says:

====================
net: ipv6/addrconf: ensure that temporary addresses' preferred lifetimes are long enough

v2 corrects and updates the documentation for these features.

Changes from v1:
- Update the typical minimum lifetime stated in the documentation, and
make it a range to emphasize the variability
- Fix spelling of "determine" in the documentation
- Mention RFC 8981's requirements in the documentation
- Arrange variables in "reverse Christmas tree"
- Update documentation of what happens if temp_prefered_lft is less
than the minimum required lifetime

Thanks to David, Paolo, and Dan for your feedback.
====================

Link: https://lore.kernel.org/r/20240214062711.608363-1-alexhenrie24@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+68 -19
+12 -2
Documentation/networking/ip-sysctl.rst
··· 2503 2503 2504 2504 temp_valid_lft - INTEGER 2505 2505 valid lifetime (in seconds) for temporary addresses. If less than the 2506 - minimum required lifetime (typically 5 seconds), temporary addresses 2506 + minimum required lifetime (typically 5-7 seconds), temporary addresses 2507 2507 will not be created. 2508 2508 2509 2509 Default: 172800 (2 days) ··· 2511 2511 temp_prefered_lft - INTEGER 2512 2512 Preferred lifetime (in seconds) for temporary addresses. If 2513 2513 temp_prefered_lft is less than the minimum required lifetime (typically 2514 - 5 seconds), temporary addresses will not be created. If 2514 + 5-7 seconds), the preferred lifetime is the minimum required. If 2515 2515 temp_prefered_lft is greater than temp_valid_lft, the preferred lifetime 2516 2516 is temp_valid_lft. 2517 2517 ··· 2534 2534 value is in seconds. 2535 2535 2536 2536 Default: 600 2537 + 2538 + regen_min_advance - INTEGER 2539 + How far in advance (in seconds), at minimum, to create a new temporary 2540 + address before the current one is deprecated. This value is added to 2541 + the amount of time that may be required for duplicate address detection 2542 + to determine when to create a new address. Linux permits setting this 2543 + value to less than the default of 2 seconds, but a value less than 2 2544 + does not conform to RFC 8981. 2545 + 2546 + Default: 2 2537 2547 2538 2548 regen_max_retry - INTEGER 2539 2549 Number of attempts before give up attempting to generate
+1
include/linux/ipv6.h
··· 27 27 __s32 use_tempaddr; 28 28 __s32 temp_valid_lft; 29 29 __s32 temp_prefered_lft; 30 + __s32 regen_min_advance; 30 31 __s32 regen_max_retry; 31 32 __s32 max_desync_factor; 32 33 __s32 max_addresses;
+3 -2
include/net/addrconf.h
··· 8 8 9 9 #define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ 10 10 11 - #define TEMP_VALID_LIFETIME (7*86400) 12 - #define TEMP_PREFERRED_LIFETIME (86400) 11 + #define TEMP_VALID_LIFETIME (7*86400) /* 1 week */ 12 + #define TEMP_PREFERRED_LIFETIME (86400) /* 24 hours */ 13 + #define REGEN_MIN_ADVANCE (2) /* 2 seconds */ 13 14 #define REGEN_MAX_RETRY (3) 14 15 #define MAX_DESYNC_FACTOR (600) 15 16
+52 -15
net/ipv6/addrconf.c
··· 195 195 .use_tempaddr = 0, 196 196 .temp_valid_lft = TEMP_VALID_LIFETIME, 197 197 .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, 198 + .regen_min_advance = REGEN_MIN_ADVANCE, 198 199 .regen_max_retry = REGEN_MAX_RETRY, 199 200 .max_desync_factor = MAX_DESYNC_FACTOR, 200 201 .max_addresses = IPV6_MAX_ADDRESSES, ··· 258 257 .use_tempaddr = 0, 259 258 .temp_valid_lft = TEMP_VALID_LIFETIME, 260 259 .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, 260 + .regen_min_advance = REGEN_MIN_ADVANCE, 261 261 .regen_max_retry = REGEN_MAX_RETRY, 262 262 .max_desync_factor = MAX_DESYNC_FACTOR, 263 263 .max_addresses = IPV6_MAX_ADDRESSES, ··· 1341 1339 in6_ifa_put(ifp); 1342 1340 } 1343 1341 1342 + static unsigned long ipv6_get_regen_advance(struct inet6_dev *idev) 1343 + { 1344 + return idev->cnf.regen_min_advance + idev->cnf.regen_max_retry * 1345 + idev->cnf.dad_transmits * 1346 + max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; 1347 + } 1348 + 1344 1349 static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) 1345 1350 { 1346 1351 struct inet6_dev *idev = ifp->idev; 1347 1352 unsigned long tmp_tstamp, age; 1348 1353 unsigned long regen_advance; 1349 1354 unsigned long now = jiffies; 1355 + u32 if_public_preferred_lft; 1350 1356 s32 cnf_temp_preferred_lft; 1351 1357 struct inet6_ifaddr *ift; 1352 1358 struct ifa6_config cfg; ··· 1390 1380 1391 1381 age = (now - ifp->tstamp) / HZ; 1392 1382 1393 - regen_advance = idev->cnf.regen_max_retry * 1394 - idev->cnf.dad_transmits * 1395 - max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; 1383 + regen_advance = ipv6_get_regen_advance(idev); 1396 1384 1397 1385 /* recalculate max_desync_factor each time and update 1398 1386 * idev->desync_factor if it's larger ··· 1410 1402 } 1411 1403 } 1412 1404 1405 + if_public_preferred_lft = ifp->prefered_lft; 1406 + 1413 1407 memset(&cfg, 0, sizeof(cfg)); 1414 1408 cfg.valid_lft = min_t(__u32, ifp->valid_lft, 1415 1409 idev->cnf.temp_valid_lft + age); 1416 1410 cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor; 1417 - cfg.preferred_lft = min_t(__u32, ifp->prefered_lft, cfg.preferred_lft); 1411 + cfg.preferred_lft = min_t(__u32, if_public_preferred_lft, cfg.preferred_lft); 1418 1412 cfg.preferred_lft = min_t(__u32, cfg.valid_lft, cfg.preferred_lft); 1419 1413 1420 1414 cfg.plen = ifp->prefix_len; ··· 1425 1415 1426 1416 write_unlock_bh(&idev->lock); 1427 1417 1428 - /* A temporary address is created only if this calculated Preferred 1429 - * Lifetime is greater than REGEN_ADVANCE time units. In particular, 1430 - * an implementation must not create a temporary address with a zero 1431 - * Preferred Lifetime. 1418 + /* From RFC 4941: 1419 + * 1420 + * A temporary address is created only if this calculated Preferred 1421 + * Lifetime is greater than REGEN_ADVANCE time units. In 1422 + * particular, an implementation must not create a temporary address 1423 + * with a zero Preferred Lifetime. 1424 + * 1425 + * ... 1426 + * 1427 + * When creating a temporary address, the lifetime values MUST be 1428 + * derived from the corresponding prefix as follows: 1429 + * 1430 + * ... 1431 + * 1432 + * * Its Preferred Lifetime is the lower of the Preferred Lifetime 1433 + * of the public address or TEMP_PREFERRED_LIFETIME - 1434 + * DESYNC_FACTOR. 1435 + * 1436 + * To comply with the RFC's requirements, clamp the preferred lifetime 1437 + * to a minimum of regen_advance, unless that would exceed valid_lft or 1438 + * ifp->prefered_lft. 1439 + * 1432 1440 * Use age calculation as in addrconf_verify to avoid unnecessary 1433 1441 * temporary addresses being generated. 1434 1442 */ 1435 1443 age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; 1436 1444 if (cfg.preferred_lft <= regen_advance + age) { 1437 - in6_ifa_put(ifp); 1438 - in6_dev_put(idev); 1439 - ret = -1; 1440 - goto out; 1445 + cfg.preferred_lft = regen_advance + age + 1; 1446 + if (cfg.preferred_lft > cfg.valid_lft || 1447 + cfg.preferred_lft > if_public_preferred_lft) { 1448 + in6_ifa_put(ifp); 1449 + in6_dev_put(idev); 1450 + ret = -1; 1451 + goto out; 1452 + } 1441 1453 } 1442 1454 1443 1455 cfg.ifa_flags = IFA_F_TEMPORARY; ··· 4627 4595 !ifp->regen_count && ifp->ifpub) { 4628 4596 /* This is a non-regenerated temporary addr. */ 4629 4597 4630 - unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * 4631 - ifp->idev->cnf.dad_transmits * 4632 - max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; 4598 + unsigned long regen_advance = ipv6_get_regen_advance(ifp->idev); 4633 4599 4634 4600 if (age + regen_advance >= ifp->prefered_lft) { 4635 4601 struct inet6_ifaddr *ifpub = ifp->ifpub; ··· 6845 6815 .maxlen = sizeof(int), 6846 6816 .mode = 0644, 6847 6817 .proc_handler = proc_dointvec, 6818 + }, 6819 + { 6820 + .procname = "regen_min_advance", 6821 + .data = &ipv6_devconf.regen_min_advance, 6822 + .maxlen = sizeof(int), 6823 + .mode = 0644, 6824 + .proc_handler = proc_dointvec, 6848 6825 }, 6849 6826 { 6850 6827 .procname = "regen_max_retry",