[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
(usagi-users 04080) [PATCH] Pv6: fix outgoing device selection
- To: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@xxxxxxxxxxxxxx>, usagi-users@xxxxxxxxxxxxxx
- Subject: (usagi-users 04080) [PATCH] Pv6: fix outgoing device selection
- From: Naohiro Ooiwa <nooiwa@xxxxxxxxxxxxxxxx>
- Date: Wed, 08 Oct 2008 12:30:26 +0900
- Reply-to: usagi-users@xxxxxxxxxxxxxxxxx
- User-agent: Thunderbird 2.0.0.14 (X11/20080501)
Hi all
There is still a problem for user about outgoing interface.
I want to fix the rt6_select().
It should compare the source address specified by user
with the assigned addrss to device like rt6_device_match() too.
I tried to create the patch.
This fix propagates "saddr" to rt6_check_dev() from rt6_select().
And the rt6_check_dev() compares them.
Could you please check this patch ?
Does this fix violate any RFCs ?
I already tested this patch on 2.6.26.
Signed-off-by: Naohiro Ooiwa <nooiwa@xxxxxxxxxxxxxxxx>
---
net/ipv6/route.c | 49 ++++++++++++++++++++++++++++++++++++-------------
1 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f4385a6..eca5424 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -321,9 +321,23 @@ static inline void rt6_probe(struct rt6_info *rt)
/*
* Default Router Selection (RFC 2461 6.3.6)
*/
-static inline int rt6_check_dev(struct rt6_info *rt, int oif)
+static inline int rt6_check_dev(struct net *net,
+ struct rt6_info *rt,
+ struct in6_addr *saddr,
+ int oif,
+ int strict)
{
struct net_device *dev = rt->rt6i_dev;
+
+ /*
+ * When user didn't specify outgoing interface (ex.SO_BINDTODEVICE)
+ * but specify the source address,
+ * we should complete the source address and
+ * the assigned address to device.
+ * This is convinient for user.
+ */
+ if (!oif && saddr && ipv6_chk_addr(net, saddr, dev, strict))
+ return 3;
if (!oif || dev->ifindex == oif)
return 2;
if ((dev->flags & IFF_LOOPBACK) &&
@@ -355,12 +369,15 @@ static inline int rt6_check_neigh(struct rt6_info *rt)
return m;
}
-static int rt6_score_route(struct rt6_info *rt, int oif,
+static int rt6_score_route(struct net *net,
+ struct rt6_info *rt,
+ struct in6_addr *saddr,
+ int oif,
int strict)
{
int m, n;
- m = rt6_check_dev(rt, oif);
+ m = rt6_check_dev(net, rt, saddr, oif, strict);
if (!m && (strict & RT6_LOOKUP_F_IFACE))
return -1;
#ifdef CONFIG_IPV6_ROUTER_PREF
@@ -372,7 +389,9 @@ static int rt6_score_route(struct rt6_info *rt, int oif,
return m;
}
-static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
+static struct rt6_info *find_match(struct net *net,
+ struct rt6_info *rt,
+ struct in6_addr *saddr, int oif, int strict,
int *mpri, struct rt6_info *match)
{
int m;
@@ -380,7 +399,7 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
if (rt6_check_expired(rt))
goto out;
- m = rt6_score_route(rt, oif, strict);
+ m = rt6_score_route(net, rt, saddr, oif, strict);
if (m < 0)
goto out;
@@ -397,7 +416,9 @@ out:
return match;
}
-static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
+static struct rt6_info *find_rr_leaf(struct net *net,
+ struct fib6_node *fn,
+ struct in6_addr *saddr,
struct rt6_info *rr_head,
u32 metric, int oif, int strict)
{
@@ -407,18 +428,21 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
match = NULL;
for (rt = rr_head; rt && rt->rt6i_metric == metric;
rt = rt->u.dst.rt6_next)
- match = find_match(rt, oif, strict, &mpri, match);
+ match = find_match(net, rt, saddr, oif, strict, &mpri, match);
for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
rt = rt->u.dst.rt6_next)
- match = find_match(rt, oif, strict, &mpri, match);
+ match = find_match(net, rt, saddr, oif, strict, &mpri, match);
return match;
}
-static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
+static struct rt6_info *rt6_select(struct net *net,
+ struct fib6_node *fn,
+ struct in6_addr *saddr,
+ int oif,
+ int strict)
{
struct rt6_info *match, *rt0;
- struct net *net;
RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
__func__, fn->leaf, oif);
@@ -427,7 +451,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
if (!rt0)
fn->rr_ptr = rt0 = fn->leaf;
- match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
+ match = find_rr_leaf(net, fn, saddr, rt0, rt0->rt6i_metric, oif, strict);
if (!match &&
(strict & RT6_LOOKUP_F_REACHABLE)) {
@@ -444,7 +468,6 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
RT6_TRACE("%s() => %p\n",
__func__, match);
- net = dev_net(rt0->rt6i_dev);
return (match ? match : net->ipv6.ip6_null_entry);
}
@@ -687,7 +710,7 @@ restart_2:
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart:
- rt = rt6_select(fn, oif, strict | reachable);
+ rt = rt6_select(net, fn, fl ? &fl->fl6_src : NULL, oif, strict | reachable);
BACKTRACK(net, &fl->fl6_src);
if (rt == net->ipv6.ip6_null_entry ||
--
1.5.4.1