[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>
This commit is contained in:
parent
918049f013
commit
adaa70bbdf
@ -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) {
|
||||||
!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
|
if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
|
||||||
return 0;
|
!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))
|
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,
|
|||||||
.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:
|
|||||||
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)
|
|||||||
},
|
},
|
||||||
.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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
},
|
},
|
||||||
.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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user