Commit fcb6aa86 authored by Toshiaki Makita's avatar Toshiaki Makita Committed by Pablo Neira Ayuso

act_ct: Support GRE offload

Support GREv0 without NAT.
Signed-off-by: default avatarToshiaki Makita <toshiaki.makita1@gmail.com>
Acked-by: default avatarPaul Blakey <paulb@nvidia.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 4e8d9584
...@@ -415,6 +415,19 @@ static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft, ...@@ -415,6 +415,19 @@ static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft,
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
break; break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE: {
struct nf_conntrack_tuple *tuple;
if (ct->status & IPS_NAT_MASK)
return;
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
/* No support for GRE v1 */
if (tuple->src.u.gre.key || tuple->dst.u.gre.key)
return;
break;
}
#endif
default: default:
return; return;
} }
...@@ -434,6 +447,8 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb, ...@@ -434,6 +447,8 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
struct flow_ports *ports; struct flow_ports *ports;
unsigned int thoff; unsigned int thoff;
struct iphdr *iph; struct iphdr *iph;
size_t hdrsize;
u8 ipproto;
if (!pskb_network_may_pull(skb, sizeof(*iph))) if (!pskb_network_may_pull(skb, sizeof(*iph)))
return false; return false;
...@@ -445,29 +460,54 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb, ...@@ -445,29 +460,54 @@ tcf_ct_flow_table_fill_tuple_ipv4(struct sk_buff *skb,
unlikely(thoff != sizeof(struct iphdr))) unlikely(thoff != sizeof(struct iphdr)))
return false; return false;
if (iph->protocol != IPPROTO_TCP && ipproto = iph->protocol;
iph->protocol != IPPROTO_UDP) switch (ipproto) {
case IPPROTO_TCP:
hdrsize = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
hdrsize = sizeof(*ports);
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default:
return false; return false;
}
if (iph->ttl <= 1) if (iph->ttl <= 1)
return false; return false;
if (!pskb_network_may_pull(skb, iph->protocol == IPPROTO_TCP ? if (!pskb_network_may_pull(skb, thoff + hdrsize))
thoff + sizeof(struct tcphdr) :
thoff + sizeof(*ports)))
return false; return false;
iph = ip_hdr(skb); switch (ipproto) {
if (iph->protocol == IPPROTO_TCP) case IPPROTO_TCP:
*tcph = (void *)(skb_network_header(skb) + thoff); *tcph = (void *)(skb_network_header(skb) + thoff);
fallthrough;
case IPPROTO_UDP:
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
break;
case IPPROTO_GRE: {
struct gre_base_hdr *greh;
greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
return false;
break;
}
}
iph = ip_hdr(skb);
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v4.s_addr = iph->saddr; tuple->src_v4.s_addr = iph->saddr;
tuple->dst_v4.s_addr = iph->daddr; tuple->dst_v4.s_addr = iph->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
tuple->l3proto = AF_INET; tuple->l3proto = AF_INET;
tuple->l4proto = iph->protocol; tuple->l4proto = ipproto;
return true; return true;
} }
...@@ -480,36 +520,63 @@ tcf_ct_flow_table_fill_tuple_ipv6(struct sk_buff *skb, ...@@ -480,36 +520,63 @@ tcf_ct_flow_table_fill_tuple_ipv6(struct sk_buff *skb,
struct flow_ports *ports; struct flow_ports *ports;
struct ipv6hdr *ip6h; struct ipv6hdr *ip6h;
unsigned int thoff; unsigned int thoff;
size_t hdrsize;
u8 nexthdr;
if (!pskb_network_may_pull(skb, sizeof(*ip6h))) if (!pskb_network_may_pull(skb, sizeof(*ip6h)))
return false; return false;
ip6h = ipv6_hdr(skb); ip6h = ipv6_hdr(skb);
thoff = sizeof(*ip6h);
if (ip6h->nexthdr != IPPROTO_TCP && nexthdr = ip6h->nexthdr;
ip6h->nexthdr != IPPROTO_UDP) switch (nexthdr) {
return false; case IPPROTO_TCP:
hdrsize = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
hdrsize = sizeof(*ports);
break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default:
return -1;
}
if (ip6h->hop_limit <= 1) if (ip6h->hop_limit <= 1)
return false; return false;
thoff = sizeof(*ip6h); if (!pskb_network_may_pull(skb, thoff + hdrsize))
if (!pskb_network_may_pull(skb, ip6h->nexthdr == IPPROTO_TCP ?
thoff + sizeof(struct tcphdr) :
thoff + sizeof(*ports)))
return false; return false;
ip6h = ipv6_hdr(skb); switch (nexthdr) {
if (ip6h->nexthdr == IPPROTO_TCP) case IPPROTO_TCP:
*tcph = (void *)(skb_network_header(skb) + thoff); *tcph = (void *)(skb_network_header(skb) + thoff);
fallthrough;
case IPPROTO_UDP:
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
break;
case IPPROTO_GRE: {
struct gre_base_hdr *greh;
greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
return false;
break;
}
}
ip6h = ipv6_hdr(skb);
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v6 = ip6h->saddr; tuple->src_v6 = ip6h->saddr;
tuple->dst_v6 = ip6h->daddr; tuple->dst_v6 = ip6h->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
tuple->l3proto = AF_INET6; tuple->l3proto = AF_INET6;
tuple->l4proto = ip6h->nexthdr; tuple->l4proto = nexthdr;
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment