aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2018-01-07 05:45:09 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-07 21:29:40 -0500
commit8067bb8c1d3599e137dee445d65b64db90ebc6f5 (patch)
tree704e1f5efb55ba66711f3369a4a827432c90477b
parent44c9f2f206f880c959fa4b43618e3f7fe2cd6157 (diff)
ipv6: Ignore dead routes during lookup
Currently, dead routes are only present in the routing tables in case the 'ignore_routes_with_linkdown' sysctl is set. Otherwise, they are flushed. Subsequent patches are going to remove the reliance on this sysctl and make IPv6 more consistent with IPv4. Before this is done, we need to make sure dead routes are skipped during route lookup, so as to not cause packet loss. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Acked-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/route.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f980f904d6ea..c00156805bf0 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -474,6 +474,8 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
474 if (route_choosen == 0) { 474 if (route_choosen == 0) {
475 struct inet6_dev *idev = sibling->rt6i_idev; 475 struct inet6_dev *idev = sibling->rt6i_idev;
476 476
477 if (sibling->rt6i_nh_flags & RTNH_F_DEAD)
478 break;
477 if (sibling->rt6i_nh_flags & RTNH_F_LINKDOWN && 479 if (sibling->rt6i_nh_flags & RTNH_F_LINKDOWN &&
478 idev->cnf.ignore_routes_with_linkdown) 480 idev->cnf.ignore_routes_with_linkdown)
479 break; 481 break;
@@ -499,12 +501,15 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
499 struct rt6_info *local = NULL; 501 struct rt6_info *local = NULL;
500 struct rt6_info *sprt; 502 struct rt6_info *sprt;
501 503
502 if (!oif && ipv6_addr_any(saddr)) 504 if (!oif && ipv6_addr_any(saddr) && !(rt->rt6i_nh_flags & RTNH_F_DEAD))
503 goto out; 505 return rt;
504 506
505 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) { 507 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) {
506 struct net_device *dev = sprt->dst.dev; 508 struct net_device *dev = sprt->dst.dev;
507 509
510 if (sprt->rt6i_nh_flags & RTNH_F_DEAD)
511 continue;
512
508 if (oif) { 513 if (oif) {
509 if (dev->ifindex == oif) 514 if (dev->ifindex == oif)
510 return sprt; 515 return sprt;
@@ -533,8 +538,8 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
533 if (flags & RT6_LOOKUP_F_IFACE) 538 if (flags & RT6_LOOKUP_F_IFACE)
534 return net->ipv6.ip6_null_entry; 539 return net->ipv6.ip6_null_entry;
535 } 540 }
536out: 541
537 return rt; 542 return rt->rt6i_nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt;
538} 543}
539 544
540#ifdef CONFIG_IPV6_ROUTER_PREF 545#ifdef CONFIG_IPV6_ROUTER_PREF
@@ -680,6 +685,9 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
680 bool match_do_rr = false; 685 bool match_do_rr = false;
681 struct inet6_dev *idev = rt->rt6i_idev; 686 struct inet6_dev *idev = rt->rt6i_idev;
682 687
688 if (rt->rt6i_nh_flags & RTNH_F_DEAD)
689 goto out;
690
683 if (idev->cnf.ignore_routes_with_linkdown && 691 if (idev->cnf.ignore_routes_with_linkdown &&
684 rt->rt6i_nh_flags & RTNH_F_LINKDOWN && 692 rt->rt6i_nh_flags & RTNH_F_LINKDOWN &&
685 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) 693 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
@@ -2153,6 +2161,8 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
2153 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); 2161 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
2154restart: 2162restart:
2155 for_each_fib6_node_rt_rcu(fn) { 2163 for_each_fib6_node_rt_rcu(fn) {
2164 if (rt->rt6i_nh_flags & RTNH_F_DEAD)
2165 continue;
2156 if (rt6_check_expired(rt)) 2166 if (rt6_check_expired(rt))
2157 continue; 2167 continue;
2158 if (rt->dst.error) 2168 if (rt->dst.error)