diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-07-02 05:30:18 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-07-03 04:51:56 -0400 |
commit | dd3abc4ef52597ec8268274222574b2700ba3ded (patch) | |
tree | e588e699dcb38c80a15bb9c7aa606994e82b134b /net/ipv6 | |
parent | 1b34be74cbf18f5d58cc85c7c4afcd9f7d74accd (diff) |
ipv6 route: Prefer outgoing interface with source address assigned.
Outgoing interface is selected by the route decision if unspecified.
Let's prefer routes via interface(s) with the address assigned if we
have multiple routes with same cost.
With help from Naohiro Ooiwa <nooiwa@miraclelinux.com>.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/route.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index dbad96c58baa..5d6c166dfbb6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -237,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr) | |||
237 | 237 | ||
238 | static inline struct rt6_info *rt6_device_match(struct net *net, | 238 | static inline struct rt6_info *rt6_device_match(struct net *net, |
239 | struct rt6_info *rt, | 239 | struct rt6_info *rt, |
240 | struct in6_addr *saddr, | ||
240 | int oif, | 241 | int oif, |
241 | int flags) | 242 | int flags) |
242 | { | 243 | { |
243 | struct rt6_info *local = NULL; | 244 | struct rt6_info *local = NULL; |
244 | struct rt6_info *sprt; | 245 | struct rt6_info *sprt; |
245 | 246 | ||
246 | if (oif) { | 247 | if (!oif && ipv6_addr_any(saddr)) |
247 | for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { | 248 | goto out; |
248 | struct net_device *dev = sprt->rt6i_dev; | 249 | |
250 | for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { | ||
251 | struct net_device *dev = sprt->rt6i_dev; | ||
252 | |||
253 | if (oif) { | ||
249 | if (dev->ifindex == oif) | 254 | if (dev->ifindex == oif) |
250 | return sprt; | 255 | return sprt; |
251 | if (dev->flags & IFF_LOOPBACK) { | 256 | if (dev->flags & IFF_LOOPBACK) { |
@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net, | |||
259 | } | 264 | } |
260 | local = sprt; | 265 | local = sprt; |
261 | } | 266 | } |
267 | } else { | ||
268 | if (ipv6_chk_addr(net, saddr, dev, | ||
269 | flags & RT6_LOOKUP_F_IFACE)) | ||
270 | return sprt; | ||
262 | } | 271 | } |
272 | } | ||
263 | 273 | ||
274 | if (oif) { | ||
264 | if (local) | 275 | if (local) |
265 | return local; | 276 | return local; |
266 | 277 | ||
267 | if (flags & RT6_LOOKUP_F_IFACE) | 278 | if (flags & RT6_LOOKUP_F_IFACE) |
268 | return net->ipv6.ip6_null_entry; | 279 | return net->ipv6.ip6_null_entry; |
269 | } | 280 | } |
281 | out: | ||
270 | return rt; | 282 | return rt; |
271 | } | 283 | } |
272 | 284 | ||
@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, | |||
539 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 551 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
540 | restart: | 552 | restart: |
541 | rt = fn->leaf; | 553 | rt = fn->leaf; |
542 | rt = rt6_device_match(net, rt, fl->oif, flags); | 554 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); |
543 | BACKTRACK(net, &fl->fl6_src); | 555 | BACKTRACK(net, &fl->fl6_src); |
544 | out: | 556 | out: |
545 | dst_use(&rt->u.dst, jiffies); | 557 | dst_use(&rt->u.dst, jiffies); |