mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 06:12:08 +00:00
netfilter: nf_flow_table: fix offload for flows that are subject to xfrm
This makes the previously added 'encap test' pass. Because its possible that the xfrm dst entry becomes stale while such a flow is offloaded, we need to call dst_check() -- the notifier that handles this for non-tunneled traffic isn't sufficient, because SA or or policies might have changed. If dst becomes stale the flow offload entry will be tagged for teardown and packets will be passed to 'classic' forwarding path. Removing the entry right away is problematic, as this would introduce a race condition with the gc worker. In case flow is long-lived, it could eventually be offloaded again once the gc worker removes the entry from the flow table. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
0ca1bbb7f4
commit
589b474a4b
@ -214,6 +214,25 @@ static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nf_flow_offload_dst_check(struct dst_entry *dst)
|
||||
{
|
||||
if (unlikely(dst_xfrm(dst)))
|
||||
return dst_check(dst, 0) ? 0 : -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
|
||||
const struct nf_hook_state *state,
|
||||
struct dst_entry *dst)
|
||||
{
|
||||
skb_orphan(skb);
|
||||
skb_dst_set_noref(skb, dst);
|
||||
skb->tstamp = 0;
|
||||
dst_output(state->net, state->sk, skb);
|
||||
return NF_STOLEN;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
@ -254,6 +273,11 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
||||
if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
|
||||
return NF_ACCEPT;
|
||||
|
||||
if (nf_flow_offload_dst_check(&rt->dst)) {
|
||||
flow_offload_teardown(flow);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
|
||||
return NF_DROP;
|
||||
|
||||
@ -261,6 +285,13 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
||||
iph = ip_hdr(skb);
|
||||
ip_decrease_ttl(iph);
|
||||
|
||||
if (unlikely(dst_xfrm(&rt->dst))) {
|
||||
memset(skb->cb, 0, sizeof(struct inet_skb_parm));
|
||||
IPCB(skb)->iif = skb->dev->ifindex;
|
||||
IPCB(skb)->flags = IPSKB_FORWARDED;
|
||||
return nf_flow_xmit_xfrm(skb, state, &rt->dst);
|
||||
}
|
||||
|
||||
skb->dev = outdev;
|
||||
nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
@ -467,6 +498,11 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
|
||||
sizeof(*ip6h)))
|
||||
return NF_ACCEPT;
|
||||
|
||||
if (nf_flow_offload_dst_check(&rt->dst)) {
|
||||
flow_offload_teardown(flow);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
if (skb_try_make_writable(skb, sizeof(*ip6h)))
|
||||
return NF_DROP;
|
||||
|
||||
@ -477,6 +513,13 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
|
||||
ip6h = ipv6_hdr(skb);
|
||||
ip6h->hop_limit--;
|
||||
|
||||
if (unlikely(dst_xfrm(&rt->dst))) {
|
||||
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
|
||||
IP6CB(skb)->iif = skb->dev->ifindex;
|
||||
IP6CB(skb)->flags = IP6SKB_FORWARDED;
|
||||
return nf_flow_xmit_xfrm(skb, state, &rt->dst);
|
||||
}
|
||||
|
||||
skb->dev = outdev;
|
||||
nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
|
Loading…
Reference in New Issue
Block a user