act_ct: Support GRE offload
Support GREv0 without NAT. Signed-off-by: Toshiaki Makita <toshiaki.makita1@gmail.com> Acked-by: Paul Blakey <paulb@nvidia.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
4e8d9584d1
commit
fcb6aa8653
1 changed files with 91 additions and 24 deletions
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue