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

netfilter: flowtable: Support GRE

Support GREv0 without NAT.
Signed-off-by: default avatarToshiaki Makita <toshiaki.makita1@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent f1082dd3
...@@ -39,8 +39,14 @@ flow_offload_fill_dir(struct flow_offload *flow, ...@@ -39,8 +39,14 @@ flow_offload_fill_dir(struct flow_offload *flow,
ft->l3proto = ctt->src.l3num; ft->l3proto = ctt->src.l3num;
ft->l4proto = ctt->dst.protonum; ft->l4proto = ctt->dst.protonum;
ft->src_port = ctt->src.u.tcp.port;
ft->dst_port = ctt->dst.u.tcp.port; switch (ctt->dst.protonum) {
case IPPROTO_TCP:
case IPPROTO_UDP:
ft->src_port = ctt->src.u.tcp.port;
ft->dst_port = ctt->dst.u.tcp.port;
break;
}
} }
struct flow_offload *flow_offload_alloc(struct nf_conn *ct) struct flow_offload *flow_offload_alloc(struct nf_conn *ct)
......
...@@ -172,6 +172,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, ...@@ -172,6 +172,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
struct flow_ports *ports; struct flow_ports *ports;
unsigned int thoff; unsigned int thoff;
struct iphdr *iph; struct iphdr *iph;
u8 ipproto;
if (!pskb_may_pull(skb, sizeof(*iph) + offset)) if (!pskb_may_pull(skb, sizeof(*iph) + offset))
return -1; return -1;
...@@ -185,13 +186,19 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, ...@@ -185,13 +186,19 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
thoff += offset; thoff += offset;
switch (iph->protocol) { ipproto = iph->protocol;
switch (ipproto) {
case IPPROTO_TCP: case IPPROTO_TCP:
*hdrsize = sizeof(struct tcphdr); *hdrsize = sizeof(struct tcphdr);
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
*hdrsize = sizeof(struct udphdr); *hdrsize = sizeof(struct udphdr);
break; break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
*hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default: default:
return -1; return -1;
} }
...@@ -202,15 +209,29 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, ...@@ -202,15 +209,29 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
if (!pskb_may_pull(skb, thoff + *hdrsize)) if (!pskb_may_pull(skb, thoff + *hdrsize))
return -1; return -1;
switch (ipproto) {
case IPPROTO_TCP:
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 -1;
break;
}
}
iph = (struct iphdr *)(skb_network_header(skb) + offset); iph = (struct iphdr *)(skb_network_header(skb) + offset);
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;
tuple->iifidx = dev->ifindex; tuple->iifidx = dev->ifindex;
nf_flow_tuple_encap(skb, tuple); nf_flow_tuple_encap(skb, tuple);
...@@ -521,6 +542,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, ...@@ -521,6 +542,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
struct flow_ports *ports; struct flow_ports *ports;
struct ipv6hdr *ip6h; struct ipv6hdr *ip6h;
unsigned int thoff; unsigned int thoff;
u8 nexthdr;
thoff = sizeof(*ip6h) + offset; thoff = sizeof(*ip6h) + offset;
if (!pskb_may_pull(skb, thoff)) if (!pskb_may_pull(skb, thoff))
...@@ -528,13 +550,19 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, ...@@ -528,13 +550,19 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
switch (ip6h->nexthdr) { nexthdr = ip6h->nexthdr;
switch (nexthdr) {
case IPPROTO_TCP: case IPPROTO_TCP:
*hdrsize = sizeof(struct tcphdr); *hdrsize = sizeof(struct tcphdr);
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
*hdrsize = sizeof(struct udphdr); *hdrsize = sizeof(struct udphdr);
break; break;
#ifdef CONFIG_NF_CT_PROTO_GRE
case IPPROTO_GRE:
*hdrsize = sizeof(struct gre_base_hdr);
break;
#endif
default: default:
return -1; return -1;
} }
...@@ -545,15 +573,29 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, ...@@ -545,15 +573,29 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
if (!pskb_may_pull(skb, thoff + *hdrsize)) if (!pskb_may_pull(skb, thoff + *hdrsize))
return -1; return -1;
switch (nexthdr) {
case IPPROTO_TCP:
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 -1;
break;
}
}
ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
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;
tuple->iifidx = dev->ifindex; tuple->iifidx = dev->ifindex;
nf_flow_tuple_encap(skb, tuple); nf_flow_tuple_encap(skb, tuple);
......
...@@ -170,6 +170,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match, ...@@ -170,6 +170,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP); match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
case IPPROTO_GRE:
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -178,15 +179,22 @@ static int nf_flow_rule_match(struct nf_flow_match *match, ...@@ -178,15 +179,22 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
key->basic.ip_proto = tuple->l4proto; key->basic.ip_proto = tuple->l4proto;
mask->basic.ip_proto = 0xff; mask->basic.ip_proto = 0xff;
key->tp.src = tuple->src_port;
mask->tp.src = 0xffff;
key->tp.dst = tuple->dst_port;
mask->tp.dst = 0xffff;
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) | match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) | BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) | BIT(FLOW_DISSECTOR_KEY_BASIC);
BIT(FLOW_DISSECTOR_KEY_PORTS);
switch (tuple->l4proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
key->tp.src = tuple->src_port;
mask->tp.src = 0xffff;
key->tp.dst = tuple->dst_port;
mask->tp.dst = 0xffff;
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
break;
}
return 0; return 0;
} }
......
...@@ -298,6 +298,19 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, ...@@ -298,6 +298,19 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
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)
goto out;
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
/* No support for GRE v1 */
if (tuple->src.u.gre.key || tuple->dst.u.gre.key)
goto out;
break;
}
#endif
default: default:
goto out; goto out;
} }
......
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