diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-10-13 15:01:03 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-10-15 23:14:19 -0700 |
commit | adaa70bbdfbc725e485179b06c8b23a20fbb7952 (patch) | |
tree | c402d42c660163902e1667fd67a00de409ac4a68 /net | |
parent | 918049f0135854a1583f9b3b88f44dbf2b027329 (diff) | |
download | op-kernel-dev-adaa70bbdfbc725e485179b06c8b23a20fbb7952.zip op-kernel-dev-adaa70bbdfbc725e485179b06c8b23a20fbb7952.tar.gz |
[IPv6] rules: Use RT6_LOOKUP_F_HAS_SADDR and fix source based selectors
Fixes rt6_lookup() to provide the source address in the flow
and sets RT6_LOOKUP_F_HAS_SADDR whenever it is present in
the flow.
Avoids unnecessary prefix comparisons by checking for a prefix
length first.
Fixes the rule logic to not match packets if a source selector
has been specified but no source address is available.
Thanks to Kim Nordlund <kim.nordlund@nokia.com> for working
on this patch with me.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Acked-by: Ville Nuorvala <vnuorval@tcs.hut.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/fib6_rules.c | 11 | ||||
-rw-r--r-- | net/ipv6/route.c | 19 |
2 files changed, 23 insertions, 7 deletions
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index d8c1057..1896ecb 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -117,12 +117,15 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) { struct fib6_rule *r = (struct fib6_rule *) rule; - if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) + if (r->dst.plen && + !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) return 0; - if ((flags & RT6_LOOKUP_F_HAS_SADDR) && - !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) - return 0; + if (r->src.plen) { + if (!(flags & RT6_LOOKUP_F_HAS_SADDR) || + !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) + return 0; + } if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) return 0; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d6b4b4f..a1b0f07 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -529,13 +529,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, .nl_u = { .ip6_u = { .daddr = *daddr, - /* TODO: saddr */ }, }, }; struct dst_entry *dst; int flags = strict ? RT6_LOOKUP_F_IFACE : 0; + if (saddr) { + memcpy(&fl.fl6_src, saddr, sizeof(*saddr)); + flags |= RT6_LOOKUP_F_HAS_SADDR; + } + dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); if (dst->error == 0) return (struct rt6_info *) dst; @@ -697,6 +701,7 @@ out2: void ip6_route_input(struct sk_buff *skb) { struct ipv6hdr *iph = skb->nh.ipv6h; + int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi fl = { .iif = skb->dev->ifindex, .nl_u = { @@ -711,7 +716,9 @@ void ip6_route_input(struct sk_buff *skb) }, .proto = iph->nexthdr, }; - int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0; + + if (rt6_need_strict(&iph->daddr)) + flags |= RT6_LOOKUP_F_IFACE; skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); } @@ -794,6 +801,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) 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; + return fib6_rule_lookup(fl, flags, ip6_pol_route_output); } @@ -1345,6 +1355,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, struct in6_addr *gateway, struct net_device *dev) { + int flags = RT6_LOOKUP_F_HAS_SADDR; struct ip6rd_flowi rdfl = { .fl = { .oif = dev->ifindex, @@ -1357,7 +1368,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, }, .gateway = *gateway, }; - int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0; + + if (rt6_need_strict(dest)) + flags |= RT6_LOOKUP_F_IFACE; return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); } |