diff options
author | Jiri Benc <jbenc@redhat.com> | 2013-12-11 07:48:20 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-12-11 16:02:58 -0500 |
commit | 7e9805696428113e34625a65a30dbc62cb78acc5 (patch) | |
tree | 3d5c13ae988049a6b4e53ff586826ee7779627a6 /net/ipv6 | |
parent | e47726683803616c773bc75c88cfb3eb54a8172b (diff) |
ipv6: router reachability probing
RFC 4191 states in 3.5:
When a host avoids using any non-reachable router X and instead sends
a data packet to another router Y, and the host would have used
router X if router X were reachable, then the host SHOULD probe each
such router X's reachability by sending a single Neighbor
Solicitation to that router's address. A host MUST NOT probe a
router's reachability in the absence of useful traffic that the host
would have sent to the router if it were reachable. In any case,
these probes MUST be rate-limited to no more than one per minute per
router.
Currently, when the neighbour corresponding to a router falls into
NUD_FAILED, it's never considered again. Introduce a new rt6_nud_state
value, RT6_NUD_FAIL_PROBE, which suggests the route should not be used but
should be probed with a single NS. The probe is ratelimited by the existing
code. To better distinguish meanings of the failure values, rename
RT6_NUD_FAIL_SOFT to RT6_NUD_FAIL_DO_RR.
Signed-off-by: Jiri Benc <jbenc@redhat.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/route.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ddb9d41c8eea..a1a57523b158 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -66,8 +66,9 @@ | |||
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | enum rt6_nud_state { | 68 | enum rt6_nud_state { |
69 | RT6_NUD_FAIL_HARD = -2, | 69 | RT6_NUD_FAIL_HARD = -3, |
70 | RT6_NUD_FAIL_SOFT = -1, | 70 | RT6_NUD_FAIL_PROBE = -2, |
71 | RT6_NUD_FAIL_DO_RR = -1, | ||
71 | RT6_NUD_SUCCEED = 1 | 72 | RT6_NUD_SUCCEED = 1 |
72 | }; | 73 | }; |
73 | 74 | ||
@@ -521,7 +522,7 @@ static void rt6_probe(struct rt6_info *rt) | |||
521 | work = kmalloc(sizeof(*work), GFP_ATOMIC); | 522 | work = kmalloc(sizeof(*work), GFP_ATOMIC); |
522 | 523 | ||
523 | if (neigh && work) | 524 | if (neigh && work) |
524 | neigh->updated = jiffies; | 525 | __neigh_set_probe_once(neigh); |
525 | 526 | ||
526 | if (neigh) | 527 | if (neigh) |
527 | write_unlock(&neigh->lock); | 528 | write_unlock(&neigh->lock); |
@@ -577,11 +578,13 @@ static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) | |||
577 | #ifdef CONFIG_IPV6_ROUTER_PREF | 578 | #ifdef CONFIG_IPV6_ROUTER_PREF |
578 | else if (!(neigh->nud_state & NUD_FAILED)) | 579 | else if (!(neigh->nud_state & NUD_FAILED)) |
579 | ret = RT6_NUD_SUCCEED; | 580 | ret = RT6_NUD_SUCCEED; |
581 | else | ||
582 | ret = RT6_NUD_FAIL_PROBE; | ||
580 | #endif | 583 | #endif |
581 | read_unlock(&neigh->lock); | 584 | read_unlock(&neigh->lock); |
582 | } else { | 585 | } else { |
583 | ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? | 586 | ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? |
584 | RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT; | 587 | RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR; |
585 | } | 588 | } |
586 | rcu_read_unlock_bh(); | 589 | rcu_read_unlock_bh(); |
587 | 590 | ||
@@ -618,16 +621,17 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, | |||
618 | goto out; | 621 | goto out; |
619 | 622 | ||
620 | m = rt6_score_route(rt, oif, strict); | 623 | m = rt6_score_route(rt, oif, strict); |
621 | if (m == RT6_NUD_FAIL_SOFT) { | 624 | if (m == RT6_NUD_FAIL_DO_RR) { |
622 | match_do_rr = true; | 625 | match_do_rr = true; |
623 | m = 0; /* lowest valid score */ | 626 | m = 0; /* lowest valid score */ |
624 | } else if (m < 0) { | 627 | } else if (m == RT6_NUD_FAIL_HARD) { |
625 | goto out; | 628 | goto out; |
626 | } | 629 | } |
627 | 630 | ||
628 | if (strict & RT6_LOOKUP_F_REACHABLE) | 631 | if (strict & RT6_LOOKUP_F_REACHABLE) |
629 | rt6_probe(rt); | 632 | rt6_probe(rt); |
630 | 633 | ||
634 | /* note that m can be RT6_NUD_FAIL_PROBE at this point */ | ||
631 | if (m > *mpri) { | 635 | if (m > *mpri) { |
632 | *do_rr = match_do_rr; | 636 | *do_rr = match_do_rr; |
633 | *mpri = m; | 637 | *mpri = m; |