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

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
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -39,8 +39,14 @@ flow_offload_fill_dir(struct flow_offload *flow,

	ft->l3proto = ctt->src.l3num;
	ft->l4proto = ctt->dst.protonum;

	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)
+52 −10
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
	struct flow_ports *ports;
	unsigned int thoff;
	struct iphdr *iph;
	u8 ipproto;

	if (!pskb_may_pull(skb, sizeof(*iph) + offset))
		return -1;
@@ -185,13 +186,19 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,

	thoff += offset;

	switch (iph->protocol) {
	ipproto = iph->protocol;
	switch (ipproto) {
	case IPPROTO_TCP:
		*hdrsize = sizeof(struct tcphdr);
		break;
	case IPPROTO_UDP:
		*hdrsize = sizeof(struct udphdr);
		break;
#ifdef CONFIG_NF_CT_PROTO_GRE
	case IPPROTO_GRE:
		*hdrsize = sizeof(struct gre_base_hdr);
		break;
#endif
	default:
		return -1;
	}
@@ -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))
		return -1;

	iph = (struct iphdr *)(skb_network_header(skb) + offset);
	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);

	tuple->src_v4.s_addr	= iph->saddr;
	tuple->dst_v4.s_addr	= iph->daddr;
	tuple->src_port		= ports->source;
	tuple->dst_port		= ports->dest;
	tuple->l3proto		= AF_INET;
	tuple->l4proto		= iph->protocol;
	tuple->l4proto		= ipproto;
	tuple->iifidx		= dev->ifindex;
	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,
	struct flow_ports *ports;
	struct ipv6hdr *ip6h;
	unsigned int thoff;
	u8 nexthdr;

	thoff = sizeof(*ip6h) + offset;
	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,

	ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);

	switch (ip6h->nexthdr) {
	nexthdr = ip6h->nexthdr;
	switch (nexthdr) {
	case IPPROTO_TCP:
		*hdrsize = sizeof(struct tcphdr);
		break;
	case IPPROTO_UDP:
		*hdrsize = sizeof(struct udphdr);
		break;
#ifdef CONFIG_NF_CT_PROTO_GRE
	case IPPROTO_GRE:
		*hdrsize = sizeof(struct gre_base_hdr);
		break;
#endif
	default:
		return -1;
	}
@@ -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))
		return -1;

	ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
	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);

	tuple->src_v6		= ip6h->saddr;
	tuple->dst_v6		= ip6h->daddr;
	tuple->src_port		= ports->source;
	tuple->dst_port		= ports->dest;
	tuple->l3proto		= AF_INET6;
	tuple->l4proto		= ip6h->nexthdr;
	tuple->l4proto		= nexthdr;
	tuple->iifidx		= dev->ifindex;
	nf_flow_tuple_encap(skb, tuple);

+15 −7
Original line number Diff line number Diff line
@@ -170,6 +170,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
		match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
		break;
	case IPPROTO_UDP:
	case IPPROTO_GRE:
		break;
	default:
		return -EOPNOTSUPP;
@@ -178,15 +179,22 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
	key->basic.ip_proto = tuple->l4proto;
	mask->basic.ip_proto = 0xff;

	match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
				      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
				      BIT(FLOW_DISSECTOR_KEY_BASIC);

	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_META) |
				      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
				      BIT(FLOW_DISSECTOR_KEY_BASIC) |
				      BIT(FLOW_DISSECTOR_KEY_PORTS);
		match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
		break;
	}

	return 0;
}

+13 −0
Original line number Diff line number Diff line
@@ -298,6 +298,19 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
		break;
	case IPPROTO_UDP:
		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:
		goto out;
	}