aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorJiri Benc <jbenc@redhat.com>2013-12-11 07:48:20 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-11 16:02:58 -0500
commit7e9805696428113e34625a65a30dbc62cb78acc5 (patch)
tree3d5c13ae988049a6b4e53ff586826ee7779627a6 /net/ipv6
parente47726683803616c773bc75c88cfb3eb54a8172b (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.c16
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
68enum rt6_nud_state { 68enum 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;