IPv6 SLAAC: Honor small PIO Valid Lifetimes

This commit implements Section 4.2 of
<https://tools.ietf.org/html/draft-gont-6man-slaac-renum-05>, to improve the
reaction of IPv6 SLAAC to renumbering events.

Namely:

* It honors PIO Valid Lifetimes < 2 hours, deviating from item "e)"
  (pp. 19-20) of Section 5.5.3 of RFC4862.

[thaller@redhat.com: squash commits and adjust unit test]

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/454
This commit is contained in:
Fernando Gont 2020-03-28 01:30:04 +01:00 committed by Thomas Haller
parent 5feba97cd1
commit 2da092b592
2 changed files with 18 additions and 26 deletions

View file

@ -442,8 +442,15 @@ nm_ndisc_add_address (NMNDisc *ndisc,
} }
if (existing) { if (existing) {
/* A Valid Lifetime of 0 eliminates the corresponding address(es). This deviates
* from RFC4862 Section 5.5.3, item e), as recommended in IETF draft draft-gont-6man-slaac-renum.
*/
if (new->lifetime == 0) {
g_array_remove_index (rdata->addresses, i);
return TRUE;
}
if (from_ra) { if (from_ra) {
const gint32 NM_NDISC_PREFIX_LFT_MIN = 7200; /* seconds, RFC4862 5.5.3.e */
gint64 old_expiry_lifetime, old_expiry_preferred; gint64 old_expiry_lifetime, old_expiry_preferred;
old_expiry_lifetime = get_expiry (existing); old_expiry_lifetime = get_expiry (existing);
@ -452,25 +459,16 @@ nm_ndisc_add_address (NMNDisc *ndisc,
if (new->lifetime == NM_NDISC_INFINITY) if (new->lifetime == NM_NDISC_INFINITY)
existing->lifetime = NM_NDISC_INFINITY; existing->lifetime = NM_NDISC_INFINITY;
else { else {
gint64 new_lifetime, remaining_lifetime; gint64 new_lifetime;
/* see RFC4862 5.5.3.e */ /* Honor small valid lifetimes, as discussed in
if (existing->lifetime == NM_NDISC_INFINITY) * draft-gont-6man-slaac-renum, to allow for more timelier
remaining_lifetime = G_MAXINT64; * reaction to renumbering events. This deviates from
else * RFC4862 Section 5.5.3, item e).
remaining_lifetime = ((gint64) existing->timestamp) + ((gint64) existing->lifetime) - ((gint64) now_s); */
new_lifetime = ((gint64) new->timestamp) + ((gint64) new->lifetime) - ((gint64) now_s); new_lifetime = ((gint64) new->timestamp) + ((gint64) new->lifetime) - ((gint64) now_s);
existing->timestamp = now_s;
if ( new_lifetime > (gint64) NM_NDISC_PREFIX_LFT_MIN existing->lifetime = CLAMP (new_lifetime, (gint64) 0, (gint64) (G_MAXUINT32 - 1));
|| new_lifetime > remaining_lifetime) {
existing->timestamp = now_s;
existing->lifetime = CLAMP (new_lifetime, (gint64) 0, (gint64) (G_MAXUINT32 - 1));
} else if (remaining_lifetime <= (gint64) NM_NDISC_PREFIX_LFT_MIN) {
/* keep the current lifetime. */
} else {
existing->timestamp = now_s;
existing->lifetime = NM_NDISC_PREFIX_LFT_MIN;
}
} }
if (new->preferred == NM_NDISC_INFINITY) { if (new->preferred == NM_NDISC_INFINITY) {
@ -487,11 +485,6 @@ nm_ndisc_add_address (NMNDisc *ndisc,
|| old_expiry_preferred != get_expiry_preferred (existing); || old_expiry_preferred != get_expiry_preferred (existing);
} }
if (new->lifetime == 0) {
g_array_remove_index (rdata->addresses, i);
return TRUE;
}
if ( get_expiry (existing) == get_expiry (new) if ( get_expiry (existing) == get_expiry (new)
&& get_expiry_preferred (existing) == get_expiry_preferred (new)) && get_expiry_preferred (existing) == get_expiry_preferred (new))
return FALSE; return FALSE;

View file

@ -217,9 +217,8 @@ test_everything_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed
g_assert_cmpint (rdata->gateways_n, ==, 1); g_assert_cmpint (rdata->gateways_n, ==, 1);
match_gateway (rdata, 0, "fe80::2", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM); match_gateway (rdata, 0, "fe80::2", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM);
g_assert_cmpint (rdata->addresses_n, ==, 2); g_assert_cmpint (rdata->addresses_n, ==, 1);
match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 0); match_address (rdata, 0, "2001:db8:a:b::1", data->timestamp1, 10, 10);
match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1, 10, 10);
g_assert_cmpint (rdata->routes_n, ==, 1); g_assert_cmpint (rdata->routes_n, ==, 1);
match_route (rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10); match_route (rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10);
g_assert_cmpint (rdata->dns_servers_n, ==, 1); g_assert_cmpint (rdata->dns_servers_n, ==, 1);