aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-03-04 11:05:04 -0800
committerDavid S. Miller <davem@davemloft.net>2020-03-04 11:05:04 -0800
commitef71037047b0cc192b661608e2021de828cd82b1 (patch)
treeae8b8d5c9207e8bdda7fe8780f6f0791a4ac96d4
parentgianfar: remove unnecessary zeroing coalesce settings (diff)
parentnet/sched: act_ct: Use pskb_network_may_pull() (diff)
downloadlinux-dev-ef71037047b0cc192b661608e2021de828cd82b1.tar.xz
linux-dev-ef71037047b0cc192b661608e2021de828cd82b1.zip
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>
-rw-r--r--net/sched/act_ct.c64
1 files changed, 28 insertions, 36 deletions
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index a2d5582a701e..23eba61f0f81 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -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);