(usagi-users 04080) [PATCH] Pv6: fix outgoing device selection
Naohiro Ooiwa <[email protected]> Wed, 08 Oct 2008 12:30:26 +0900
| Newsgroups | gmane.linux.ipv6.usagi.users |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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