|
@@ -83,6 +83,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
|
|
|
struct sk_buff *skb, u32 mtu);
|
|
|
static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
|
|
|
struct sk_buff *skb);
|
|
|
+static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
|
|
|
|
|
|
#ifdef CONFIG_IPV6_ROUTE_INFO
|
|
|
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,
|
|
|
}
|
|
|
|
|
|
static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
|
|
|
- struct flowi6 *fl6)
|
|
|
+ struct flowi6 *fl6, int oif,
|
|
|
+ int strict)
|
|
|
{
|
|
|
struct rt6_info *sibling, *next_sibling;
|
|
|
int route_choosen;
|
|
@@ -408,6 +410,8 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
|
|
|
&match->rt6i_siblings, rt6i_siblings) {
|
|
|
route_choosen--;
|
|
|
if (route_choosen == 0) {
|
|
|
+ if (rt6_score_route(sibling, oif, strict) < 0)
|
|
|
+ break;
|
|
|
match = sibling;
|
|
|
break;
|
|
|
}
|
|
@@ -743,7 +747,7 @@ restart:
|
|
|
rt = fn->leaf;
|
|
|
rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
|
|
|
if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
|
|
|
- rt = rt6_multipath_select(rt, fl6);
|
|
|
+ rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
|
|
|
BACKTRACK(net, &fl6->saddr);
|
|
|
out:
|
|
|
dst_use(&rt->dst, jiffies);
|
|
@@ -875,8 +879,8 @@ restart_2:
|
|
|
|
|
|
restart:
|
|
|
rt = rt6_select(fn, oif, strict | reachable);
|
|
|
- if (rt->rt6i_nsiblings && oif == 0)
|
|
|
- rt = rt6_multipath_select(rt, fl6);
|
|
|
+ if (rt->rt6i_nsiblings)
|
|
|
+ rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
|
|
|
BACKTRACK(net, &fl6->saddr);
|
|
|
if (rt == net->ipv6.ip6_null_entry ||
|
|
|
rt->rt6i_flags & RTF_CACHE)
|