Merge branch 'act_ct-software-offload-of-established-flows-fixes'

Paul Blakey says:

====================
Fixes for tc act_ct software offload of established flows (diff v4->v6)

v4 of the original patchset was accidentally merged while we moved ahead
with v6 review. This two patches are the diff between v4 that was merged and
v6 that was the final revision, which was acked by the community.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-03-04 11:05:04 -08:00
commit ef71037047
1 changed files with 28 additions and 36 deletions

View File

@ -188,13 +188,14 @@ static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft,
static bool
tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
struct flow_offload_tuple *tuple)
struct flow_offload_tuple *tuple,
struct tcphdr **tcph)
{
struct flow_ports *ports;
unsigned int thoff;
struct iphdr *iph;
if (!pskb_may_pull(skb, sizeof(*iph)))
if (!pskb_network_may_pull(skb, sizeof(*iph)))
return false;
iph = ip_hdr(skb);
@ -211,11 +212,16 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
if (iph->ttl <= 1)
return false;
if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
if (!pskb_network_may_pull(skb, iph->protocol == IPPROTO_TCP ?
thoff + sizeof(struct tcphdr) :
thoff + sizeof(*ports)))
return false;
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_TCP)
*tcph = (void *)(skb_network_header(skb) + thoff);
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v4.s_addr = iph->saddr;
tuple->dst_v4.s_addr = iph->daddr;
tuple->src_port = ports->source;
@ -228,13 +234,14 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
static bool
tcf_ct_flow_table_fill_tuple_ipv6(struct sk_buff *skb,
struct flow_offload_tuple *tuple)
struct flow_offload_tuple *tuple,
struct tcphdr **tcph)
{
struct flow_ports *ports;
struct ipv6hdr *ip6h;
unsigned int thoff;
if (!pskb_may_pull(skb, sizeof(*ip6h)))
if (!pskb_network_may_pull(skb, sizeof(*ip6h)))
return false;
ip6h = ipv6_hdr(skb);
@ -247,11 +254,16 @@ tcf_ct_flow_table_fill_tuple_ipv6(struct sk_buff *skb,
return false;
thoff = sizeof(*ip6h);
if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
if (!pskb_network_may_pull(skb, ip6h->nexthdr == IPPROTO_TCP ?
thoff + sizeof(struct tcphdr) :
thoff + sizeof(*ports)))
return false;
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
ip6h = ipv6_hdr(skb);
if (ip6h->nexthdr == IPPROTO_TCP)
*tcph = (void *)(skb_network_header(skb) + thoff);
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v6 = ip6h->saddr;
tuple->dst_v6 = ip6h->daddr;
tuple->src_port = ports->source;
@ -262,24 +274,6 @@ tcf_ct_flow_table_fill_tuple_ipv6(struct sk_buff *skb,
return true;
}
static bool tcf_ct_flow_table_check_tcp(struct flow_offload *flow,
struct sk_buff *skb,
unsigned int thoff)
{
struct tcphdr *tcph;
if (!pskb_may_pull(skb, thoff + sizeof(*tcph)))
return false;
tcph = (void *)(skb_network_header(skb) + thoff);
if (unlikely(tcph->fin || tcph->rst)) {
flow_offload_teardown(flow);
return false;
}
return true;
}
static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
struct sk_buff *skb,
u8 family)
@ -288,10 +282,9 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
struct flow_offload_tuple_rhash *tuplehash;
struct flow_offload_tuple tuple = {};
enum ip_conntrack_info ctinfo;
struct tcphdr *tcph = NULL;
struct flow_offload *flow;
struct nf_conn *ct;
unsigned int thoff;
int ip_proto;
u8 dir;
/* Previously seen or loopback */
@ -301,11 +294,11 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
switch (family) {
case NFPROTO_IPV4:
if (!tcf_ct_flow_table_fill_tuple_ipv4(skb, &tuple))
if (!tcf_ct_flow_table_fill_tuple_ipv4(skb, &tuple, &tcph))
return false;
break;
case NFPROTO_IPV6:
if (!tcf_ct_flow_table_fill_tuple_ipv6(skb, &tuple))
if (!tcf_ct_flow_table_fill_tuple_ipv6(skb, &tuple, &tcph))
return false;
break;
default:
@ -320,15 +313,14 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
ct = flow->ct;
if (tcph && (unlikely(tcph->fin || tcph->rst))) {
flow_offload_teardown(flow);
return false;
}
ctinfo = dir == FLOW_OFFLOAD_DIR_ORIGINAL ? IP_CT_ESTABLISHED :
IP_CT_ESTABLISHED_REPLY;
thoff = ip_hdr(skb)->ihl * 4;
ip_proto = ip_hdr(skb)->protocol;
if (ip_proto == IPPROTO_TCP &&
!tcf_ct_flow_table_check_tcp(flow, skb, thoff))
return false;
nf_conntrack_get(&ct->ct_general);
nf_ct_set(skb, ct, ctinfo);