Index: /trunk/kernel/linux-2.6.35.14/include/net/ip6_route.h =================================================================== --- /trunk/kernel/linux-2.6.35.14/include/net/ip6_route.h (revision 68) +++ /trunk/kernel/linux-2.6.35.14/include/net/ip6_route.h (revision 384) @@ -34,10 +34,11 @@ #define RT6_LOOKUP_F_REACHABLE 0x00000002 #define RT6_LOOKUP_F_HAS_SADDR 0x00000004 #define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 #define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 #define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 +#define RT6_LOOKUP_F_IP6TUNNEL 0x00000040 /* * rt6_srcprefs2flags() and rt6_flags2srcprefs() translate * between IPV6_ADDR_PREFERENCES socket option values * IPV6_PREFER_SRC_TMP = 0x1 @@ -58,11 +59,11 @@ extern void ip6_route_input(struct sk_buff *skb); extern struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, - struct flowi *fl); + struct flowi *fl, int flags); extern int ip6_route_init(void); extern void ip6_route_cleanup(void); extern int ipv6_route_ioctl(struct net *net, Index: /trunk/kernel/linux-2.6.35.14/net/ipv6/ip6_tunnel.c =================================================================== --- /trunk/kernel/linux-2.6.35.14/net/ipv6/ip6_tunnel.c (revision 68) +++ /trunk/kernel/linux-2.6.35.14/net/ipv6/ip6_tunnel.c (revision 384) @@ -860,11 +860,11 @@ int pkt_len; if ((dst = ip6_tnl_dst_check(t)) != NULL) dst_hold(dst); else { - dst = ip6_route_output(net, NULL, fl); + dst = ip6_route_output(net, NULL, fl, RT6_LOOKUP_F_IP6TUNNEL); if (dst->error || xfrm_lookup(net, &dst, fl, NULL, 0) < 0) goto tx_err_link_failure; } Index: /trunk/kernel/linux-2.6.35.14/net/ipv6/route.c =================================================================== --- /trunk/kernel/linux-2.6.35.14/net/ipv6/route.c (revision 68) +++ /trunk/kernel/linux-2.6.35.14/net/ipv6/route.c (revision 384) @@ -398,27 +398,32 @@ return match; } static struct rt6_info *find_rr_leaf(struct fib6_node *fn, struct rt6_info *rr_head, - u32 metric, int oif, int strict) + u32 metric, int oif, int flags, int reachable) { struct rt6_info *rt, *match; int mpri = -1; + int strict = 0; + + strict |= flags & RT6_LOOKUP_F_IFACE; match = NULL; - for (rt = rr_head; rt && rt->rt6i_metric == metric; - rt = rt->u.dst.rt6_next) + for (rt = rr_head; rt && ((flags & RT6_LOOKUP_F_IP6TUNNEL) || rt->rt6i_metric == metric); + rt = rt->u.dst.rt6_next) { match = find_match(rt, oif, strict, &mpri, match); - for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric; - rt = rt->u.dst.rt6_next) + } + for (rt = fn->leaf; rt && rt != rr_head && ((flags & RT6_LOOKUP_F_IP6TUNNEL) || rt->rt6i_metric == metric); + rt = rt->u.dst.rt6_next) { match = find_match(rt, 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 fib6_node *fn, int oif, int flags, int reachable) { struct rt6_info *match, *rt0; struct net *net; RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", @@ -426,14 +431,13 @@ rt0 = fn->rr_ptr; if (!rt0) fn->rr_ptr = rt0 = fn->leaf; - match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict); - - if (!match && - (strict & RT6_LOOKUP_F_REACHABLE)) { + match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, flags, reachable); + + if (!match && reachable) { struct rt6_info *next = rt0->u.dst.rt6_next; /* no entries matched; do round-robin */ if (!next || next->rt6i_metric != rt0->rt6i_metric) next = fn->leaf; @@ -703,25 +707,22 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, struct flowi *fl, int flags) { struct fib6_node *fn; struct rt6_info *rt, *nrt; - int strict = 0; int attempts = 3; int err; int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE; - strict |= flags & RT6_LOOKUP_F_IFACE; - relookup: read_lock_bh(&table->tb6_lock); 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(fn, oif, flags, reachable); BACKTRACK(net, &fl->fl6_src); if (rt == net->ipv6.ip6_null_entry || rt->rt6i_flags & RTF_CACHE) goto out; @@ -768,11 +769,15 @@ read_unlock_bh(&table->tb6_lock); out2: rt->u.dst.lastuse = jiffies; rt->u.dst.__use++; - return rt; + if (flags & RT6_LOOKUP_F_IP6TUNNEL) { + printk(KERN_INFO "*** %s: %s\n", __FUNCTION__, rt->rt6i_dev->name); + } + + return rt; } static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, struct flowi *fl, int flags) { @@ -808,14 +813,12 @@ { return ip6_pol_route(net, table, fl->oif, fl, flags); } struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, - struct flowi *fl) -{ - int flags = 0; - + struct flowi *fl, int flags) +{ if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst)) flags |= RT6_LOOKUP_F_IFACE; if (!ipv6_addr_any(&fl->fl6_src)) flags |= RT6_LOOKUP_F_HAS_SADDR; @@ -2381,11 +2384,11 @@ through good chunk of routing engine. */ skb_reset_mac_header(skb); skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); - rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); + rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl, 0); skb_dst_set(skb, &rt->u.dst); err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, 0, 0, 0);