aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-07-02 05:30:18 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-07-03 04:51:56 -0400
commitdd3abc4ef52597ec8268274222574b2700ba3ded (patch)
treee588e699dcb38c80a15bb9c7aa606994e82b134b /net/ipv6/route.c
parent1b34be74cbf18f5d58cc85c7c4afcd9f7d74accd (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/route.c')
-rw-r--r--net/ipv6/route.c20
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
238static inline struct rt6_info *rt6_device_match(struct net *net, 238static 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 }
281out:
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);
540restart: 552restart:
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);
544out: 556out:
545 dst_use(&rt->u.dst, jiffies); 557 dst_use(&rt->u.dst, jiffies);