mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 14:50:19 +00:00
ipv6: Fix preferred_lft not updating in some cases
Consider the scenario where an IPv6 router is advertising a fixed preferred_lft of 1800 seconds, while the valid_lft begins at 3600 seconds and counts down in realtime. A client should reset its preferred_lft to 1800 every time the RA is received, but a bug is causing Linux to ignore the update. The core problem is here: if (prefered_lft != ifp->prefered_lft) { Note that ifp->prefered_lft is an offset, so it doesn't decrease over time. Thus, the comparison is always (1800 != 1800), which fails to trigger an update. The most direct solution would be to compute a "stored_prefered_lft", and use that value in the comparison. But I think that trying to filter out unnecessary updates here is a premature optimization. In order for the filter to apply, both of these would need to hold: - The advertised valid_lft and preferred_lft are both declining in real time. - No clock skew exists between the router & client. So in this patch, I've set "update_lft = 1" unconditionally, which allows the surrounding code to be greatly simplified. Signed-off-by: Paul Marks <pmarks@google.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d4a71b155c
commit
c9d55d5bff
@ -2220,43 +2220,21 @@ ok:
|
|||||||
else
|
else
|
||||||
stored_lft = 0;
|
stored_lft = 0;
|
||||||
if (!update_lft && !create && stored_lft) {
|
if (!update_lft && !create && stored_lft) {
|
||||||
if (valid_lft > MIN_VALID_LIFETIME ||
|
const u32 minimum_lft = min(
|
||||||
valid_lft > stored_lft)
|
stored_lft, (u32)MIN_VALID_LIFETIME);
|
||||||
update_lft = 1;
|
valid_lft = max(valid_lft, minimum_lft);
|
||||||
else if (stored_lft <= MIN_VALID_LIFETIME) {
|
|
||||||
/* valid_lft <= stored_lft is always true */
|
/* RFC4862 Section 5.5.3e:
|
||||||
/*
|
* "Note that the preferred lifetime of the
|
||||||
* RFC 4862 Section 5.5.3e:
|
* corresponding address is always reset to
|
||||||
* "Note that the preferred lifetime of
|
* the Preferred Lifetime in the received
|
||||||
* the corresponding address is always
|
* Prefix Information option, regardless of
|
||||||
* reset to the Preferred Lifetime in
|
* whether the valid lifetime is also reset or
|
||||||
* the received Prefix Information
|
* ignored."
|
||||||
* option, regardless of whether the
|
*
|
||||||
* valid lifetime is also reset or
|
* So we should always update prefered_lft here.
|
||||||
* ignored."
|
*/
|
||||||
*
|
update_lft = 1;
|
||||||
* So if the preferred lifetime in
|
|
||||||
* this advertisement is different
|
|
||||||
* than what we have stored, but the
|
|
||||||
* valid lifetime is invalid, just
|
|
||||||
* reset prefered_lft.
|
|
||||||
*
|
|
||||||
* We must set the valid lifetime
|
|
||||||
* to the stored lifetime since we'll
|
|
||||||
* be updating the timestamp below,
|
|
||||||
* else we'll set it back to the
|
|
||||||
* minimum.
|
|
||||||
*/
|
|
||||||
if (prefered_lft != ifp->prefered_lft) {
|
|
||||||
valid_lft = stored_lft;
|
|
||||||
update_lft = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
valid_lft = MIN_VALID_LIFETIME;
|
|
||||||
if (valid_lft < prefered_lft)
|
|
||||||
prefered_lft = valid_lft;
|
|
||||||
update_lft = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_lft) {
|
if (update_lft) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user