Message ID | 1658810716-106274-1-git-send-email-wenxu@chinatelecom.cn |
---|---|
State | Changes Requested |
Delegated to: | Pablo Neira |
Headers | show |
Series | [nf-next] netfilter: nf_flow_table: delay teardown the offload flow until fin packet recv from both direction | expand |
Hi, On Tue, Jul 26, 2022 at 12:45:16AM -0400, wenxu@chinatelecom.cn wrote: > From: wenxu <wenxu@chinatelecom.cn> > > A fin packet receive not always means the tcp connection teardown. > For tcp half close case, only the client shutdown the connection > and the server still can sendmsg to the client. The connection > can still be offloaded until the server shutdown the connection. > > Signed-off-by: wenxu <wenxu@chinatelecom.cn> > --- > include/net/netfilter/nf_flow_table.h | 3 ++- > net/netfilter/nf_flow_table_ip.c | 14 ++++++++++---- > 2 files changed, 12 insertions(+), 5 deletions(-) > > diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h > index d5326c4..0c4864d 100644 > --- a/include/net/netfilter/nf_flow_table.h > +++ b/include/net/netfilter/nf_flow_table.h > @@ -129,7 +129,8 @@ struct flow_offload_tuple { > /* All members above are keys for lookups, see flow_offload_hash(). */ > struct { } __hash; > > - u8 dir:2, > + u8 dir:1, > + fin:1, > xmit_type:3, > encap_num:2, > in_vlan_ingress:2; > diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c > index b350fe9..c191861 100644 > --- a/net/netfilter/nf_flow_table_ip.c > +++ b/net/netfilter/nf_flow_table_ip.c > @@ -19,7 +19,8 @@ > #include <linux/udp.h> > > static int nf_flow_state_check(struct flow_offload *flow, int proto, > - struct sk_buff *skb, unsigned int thoff) > + struct sk_buff *skb, unsigned int thoff, > + enum flow_offload_tuple_dir dir) > { > struct tcphdr *tcph; > > @@ -27,9 +28,14 @@ static int nf_flow_state_check(struct flow_offload *flow, int proto, > return 0; > > tcph = (void *)(skb_network_header(skb) + thoff); > - if (unlikely(tcph->fin || tcph->rst)) { > + if (unlikely(tcph->rst)) { > flow_offload_teardown(flow); > return -1; > + } else if (unlikely(tcph->fin)) { > + flow->tuplehash[dir].tuple.fin = 1; > + if (flow->tuplehash[!dir].tuple.fin == 1) > + flow_offload_teardown(flow); Maybe add a new flag to enum nf_flow_flags instead?
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index d5326c4..0c4864d 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -129,7 +129,8 @@ struct flow_offload_tuple { /* All members above are keys for lookups, see flow_offload_hash(). */ struct { } __hash; - u8 dir:2, + u8 dir:1, + fin:1, xmit_type:3, encap_num:2, in_vlan_ingress:2; diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index b350fe9..c191861 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -19,7 +19,8 @@ #include <linux/udp.h> static int nf_flow_state_check(struct flow_offload *flow, int proto, - struct sk_buff *skb, unsigned int thoff) + struct sk_buff *skb, unsigned int thoff, + enum flow_offload_tuple_dir dir) { struct tcphdr *tcph; @@ -27,9 +28,14 @@ static int nf_flow_state_check(struct flow_offload *flow, int proto, return 0; tcph = (void *)(skb_network_header(skb) + thoff); - if (unlikely(tcph->fin || tcph->rst)) { + if (unlikely(tcph->rst)) { flow_offload_teardown(flow); return -1; + } else if (unlikely(tcph->fin)) { + flow->tuplehash[dir].tuple.fin = 1; + if (flow->tuplehash[!dir].tuple.fin == 1) + flow_offload_teardown(flow); + return -1; } return 0; @@ -373,7 +379,7 @@ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb, iph = (struct iphdr *)(skb_network_header(skb) + offset); thoff = (iph->ihl * 4) + offset; - if (nf_flow_state_check(flow, iph->protocol, skb, thoff)) + if (nf_flow_state_check(flow, iph->protocol, skb, thoff, dir)) return NF_ACCEPT; if (!nf_flow_dst_check(&tuplehash->tuple)) { @@ -635,7 +641,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); thoff = sizeof(*ip6h) + offset; - if (nf_flow_state_check(flow, ip6h->nexthdr, skb, thoff)) + if (nf_flow_state_check(flow, ip6h->nexthdr, skb, thoff, dir)) return NF_ACCEPT; if (!nf_flow_dst_check(&tuplehash->tuple)) {