diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2013-06-28 11:35:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-07-01 16:27:38 -0400 |
commit | 52bd4c0c1551daa2efa7bb9e01a2f4ea6d1311bb (patch) | |
tree | 2324d5dbb005babd1085661734936724dd8f1630 /net | |
parent | 5c29fb12e8fb8a8105ea048cb160fd79a85a52bb (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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/route.c | 12 |
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); |
84 | static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, | 84 | static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, |
85 | struct sk_buff *skb); | 85 | struct sk_buff *skb); |
86 | static 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 |
88 | static struct rt6_info *rt6_add_route_info(struct net *net, | 89 | static 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 | ||
396 | static struct rt6_info *rt6_multipath_select(struct rt6_info *match, | 397 | static 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); |
748 | out: | 752 | out: |
749 | dst_use(&rt->dst, jiffies); | 753 | dst_use(&rt->dst, jiffies); |
@@ -875,8 +879,8 @@ restart_2: | |||
875 | 879 | ||
876 | restart: | 880 | restart: |
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) |