Commit adaa70bb authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[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: default avatarThomas Graf <tgraf@suug.ch>
Acked-by: default avatarVille Nuorvala <vnuorval@tcs.hut.fi>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 918049f0
...@@ -117,12 +117,15 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) ...@@ -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; 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; return 0;
if ((flags & RT6_LOOKUP_F_HAS_SADDR) && if (r->src.plen) {
if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
return 0; return 0;
}
if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff))
return 0; return 0;
......
...@@ -529,13 +529,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, ...@@ -529,13 +529,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
.nl_u = { .nl_u = {
.ip6_u = { .ip6_u = {
.daddr = *daddr, .daddr = *daddr,
/* TODO: saddr */
}, },
}, },
}; };
struct dst_entry *dst; struct dst_entry *dst;
int flags = strict ? RT6_LOOKUP_F_IFACE : 0; 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); dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
if (dst->error == 0) if (dst->error == 0)
return (struct rt6_info *) dst; return (struct rt6_info *) dst;
...@@ -697,6 +701,7 @@ out2: ...@@ -697,6 +701,7 @@ out2:
void ip6_route_input(struct sk_buff *skb) void ip6_route_input(struct sk_buff *skb)
{ {
struct ipv6hdr *iph = skb->nh.ipv6h; struct ipv6hdr *iph = skb->nh.ipv6h;
int flags = RT6_LOOKUP_F_HAS_SADDR;
struct flowi fl = { struct flowi fl = {
.iif = skb->dev->ifindex, .iif = skb->dev->ifindex,
.nl_u = { .nl_u = {
...@@ -711,7 +716,9 @@ void ip6_route_input(struct sk_buff *skb) ...@@ -711,7 +716,9 @@ void ip6_route_input(struct sk_buff *skb)
}, },
.proto = iph->nexthdr, .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); 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) ...@@ -794,6 +801,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
if (rt6_need_strict(&fl->fl6_dst)) if (rt6_need_strict(&fl->fl6_dst))
flags |= RT6_LOOKUP_F_IFACE; 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); 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, ...@@ -1345,6 +1355,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
struct in6_addr *gateway, struct in6_addr *gateway,
struct net_device *dev) struct net_device *dev)
{ {
int flags = RT6_LOOKUP_F_HAS_SADDR;
struct ip6rd_flowi rdfl = { struct ip6rd_flowi rdfl = {
.fl = { .fl = {
.oif = dev->ifindex, .oif = dev->ifindex,
...@@ -1357,7 +1368,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, ...@@ -1357,7 +1368,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
}, },
.gateway = *gateway, .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); return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment