aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2013-06-28 11:35:48 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-01 16:27:38 -0400
commit52bd4c0c1551daa2efa7bb9e01a2f4ea6d1311bb (patch)
tree2324d5dbb005babd1085661734936724dd8f1630
parent5c29fb12e8fb8a8105ea048cb160fd79a85a52bb (diff)
ipv6: fix ecmp lookup when oif is specified
There is no reason to skip ECMP lookup when oif is specified, but this implies to check oif given by user when selecting another route. When the new route does not match oif requirement, we simply keep the initial one. Spotted-by: dingzhi <zhi.ding@6wind.com> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/route.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 7ca87b37c0ef..9ff0b78a9c15 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -83,6 +83,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
83 struct sk_buff *skb, u32 mtu); 83 struct sk_buff *skb, u32 mtu);
84static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, 84static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
85 struct sk_buff *skb); 85 struct sk_buff *skb);
86static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
86 87
87#ifdef CONFIG_IPV6_ROUTE_INFO 88#ifdef CONFIG_IPV6_ROUTE_INFO
88static struct rt6_info *rt6_add_route_info(struct net *net, 89static struct rt6_info *rt6_add_route_info(struct net *net,
@@ -394,7 +395,8 @@ static int rt6_info_hash_nhsfn(unsigned int candidate_count,
394} 395}
395 396
396static struct rt6_info *rt6_multipath_select(struct rt6_info *match, 397static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
397 struct flowi6 *fl6) 398 struct flowi6 *fl6, int oif,
399 int strict)
398{ 400{
399 struct rt6_info *sibling, *next_sibling; 401 struct rt6_info *sibling, *next_sibling;
400 int route_choosen; 402 int route_choosen;
@@ -408,6 +410,8 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
408 &match->rt6i_siblings, rt6i_siblings) { 410 &match->rt6i_siblings, rt6i_siblings) {
409 route_choosen--; 411 route_choosen--;
410 if (route_choosen == 0) { 412 if (route_choosen == 0) {
413 if (rt6_score_route(sibling, oif, strict) < 0)
414 break;
411 match = sibling; 415 match = sibling;
412 break; 416 break;
413 } 417 }
@@ -743,7 +747,7 @@ restart:
743 rt = fn->leaf; 747 rt = fn->leaf;
744 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); 748 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
745 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0) 749 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
746 rt = rt6_multipath_select(rt, fl6); 750 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
747 BACKTRACK(net, &fl6->saddr); 751 BACKTRACK(net, &fl6->saddr);
748out: 752out:
749 dst_use(&rt->dst, jiffies); 753 dst_use(&rt->dst, jiffies);
@@ -875,8 +879,8 @@ restart_2:
875 879
876restart: 880restart:
877 rt = rt6_select(fn, oif, strict | reachable); 881 rt = rt6_select(fn, oif, strict | reachable);
878 if (rt->rt6i_nsiblings && oif == 0) 882 if (rt->rt6i_nsiblings)
879 rt = rt6_multipath_select(rt, fl6); 883 rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
880 BACKTRACK(net, &fl6->saddr); 884 BACKTRACK(net, &fl6->saddr);
881 if (rt == net->ipv6.ip6_null_entry || 885 if (rt == net->ipv6.ip6_null_entry ||
882 rt->rt6i_flags & RTF_CACHE) 886 rt->rt6i_flags & RTF_CACHE)