diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 22d1933278ae..200bd5bb56bf 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -632,25 +632,22 @@ static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif, return m; } -static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict, - int *mpri, struct fib6_info *match, - bool *do_rr) +static bool find_match(struct fib6_nh *nh, u32 fib6_flags, + int oif, int strict, int *mpri, bool *do_rr) { - int m; bool match_do_rr = false; + bool rc = false; + int m; - if (rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD) + if (nh->fib_nh_flags & RTNH_F_DEAD) goto out; - if (ip6_ignore_linkdown(rt->fib6_nh.fib_nh_dev) && - rt->fib6_nh.fib_nh_flags & RTNH_F_LINKDOWN && + if (ip6_ignore_linkdown(nh->fib_nh_dev) && + nh->fib_nh_flags & RTNH_F_LINKDOWN && !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) goto out; - if (fib6_check_expired(rt)) - goto out; - - m = rt6_score_route(&rt->fib6_nh, rt->fib6_flags, oif, strict); + m = rt6_score_route(nh, fib6_flags, oif, strict); if (m == RT6_NUD_FAIL_DO_RR) { match_do_rr = true; m = 0; /* lowest valid score */ @@ -659,16 +656,16 @@ static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict, } if (strict & RT6_LOOKUP_F_REACHABLE) - rt6_probe(&rt->fib6_nh); + rt6_probe(nh); /* note that m can be RT6_NUD_FAIL_PROBE at this point */ if (m > *mpri) { *do_rr = match_do_rr; *mpri = m; - match = rt; + rc = true; } out: - return match; + return rc; } static struct fib6_info *find_rr_leaf(struct fib6_node *fn, @@ -678,6 +675,7 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn, bool *do_rr) { struct fib6_info *rt, *match, *cont; + struct fib6_nh *nh; int mpri = -1; match = NULL; @@ -688,7 +686,12 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn, break; } - match = find_match(rt, oif, strict, &mpri, match, do_rr); + if (fib6_check_expired(rt)) + continue; + + nh = &rt->fib6_nh; + if (find_match(nh, rt->fib6_flags, oif, strict, &mpri, do_rr)) + match = rt; } for (rt = leaf; rt && rt != rr_head; @@ -698,14 +701,25 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn, break; } - match = find_match(rt, oif, strict, &mpri, match, do_rr); + if (fib6_check_expired(rt)) + continue; + + nh = &rt->fib6_nh; + if (find_match(nh, rt->fib6_flags, oif, strict, &mpri, do_rr)) + match = rt; } if (match || !cont) return match; - for (rt = cont; rt; rt = rcu_dereference(rt->fib6_next)) - match = find_match(rt, oif, strict, &mpri, match, do_rr); + for (rt = cont; rt; rt = rcu_dereference(rt->fib6_next)) { + if (fib6_check_expired(rt)) + continue; + + nh = &rt->fib6_nh; + if (find_match(nh, rt->fib6_flags, oif, strict, &mpri, do_rr)) + match = rt; + } return match; } |