[IPv6] rules: Use RT6_LOOKUP_F_HAS_SADDR and fix source based selectors
authorThomas Graf <tgraf@suug.ch>
Fri, 13 Oct 2006 22:01:03 +0000 (15:01 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 16 Oct 2006 06:14:19 +0000 (23:14 -0700)
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>
net/ipv6/fib6_rules.c
net/ipv6/route.c

index d8c1057e8b008520f2f9c3a8e21e6de1bd90f757..1896ecb52899069a80b577748885b0d2489a6754 100644 (file)
@@ -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;
index d6b4b4f48d18cb6d9736c520b854d0899c98bc23..a1b0f075462e0e64fd76a91cd6696765e0f8b6e4 100644 (file)
@@ -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);
 }