Commit cfab6dbd authored by wenxu's avatar wenxu Committed by Pablo Neira Ayuso
Browse files

netfilter: flowtable: add tunnel match offload support



This patch support both ipv4 and ipv6 tunnel_id, tunnel_src and
tunnel_dst match for flowtable offload

Signed-off-by: default avatarwenxu <wenxu@ucloud.cn>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent b5140a36
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -19,11 +19,17 @@ enum flow_offload_tuple_dir;
struct nf_flow_key {
struct nf_flow_key {
	struct flow_dissector_key_meta			meta;
	struct flow_dissector_key_meta			meta;
	struct flow_dissector_key_control		control;
	struct flow_dissector_key_control		control;
	struct flow_dissector_key_control		enc_control;
	struct flow_dissector_key_basic			basic;
	struct flow_dissector_key_basic			basic;
	union {
	union {
		struct flow_dissector_key_ipv4_addrs	ipv4;
		struct flow_dissector_key_ipv4_addrs	ipv4;
		struct flow_dissector_key_ipv6_addrs	ipv6;
		struct flow_dissector_key_ipv6_addrs	ipv6;
	};
	};
	struct flow_dissector_key_keyid			enc_key_id;
	union {
		struct flow_dissector_key_ipv4_addrs	enc_ipv4;
		struct flow_dissector_key_ipv6_addrs	enc_ipv6;
	};
	struct flow_dissector_key_tcp			tcp;
	struct flow_dissector_key_tcp			tcp;
	struct flow_dissector_key_ports			tp;
	struct flow_dissector_key_ports			tp;
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
+59 −2
Original line number Original line Diff line number Diff line
@@ -28,11 +28,61 @@ struct flow_offload_work {
	(__match)->dissector.offset[__type] =		\
	(__match)->dissector.offset[__type] =		\
		offsetof(struct nf_flow_key, __field)
		offsetof(struct nf_flow_key, __field)


static void nf_flow_rule_lwt_match(struct nf_flow_match *match,
				   struct ip_tunnel_info *tun_info)
{
	struct nf_flow_key *mask = &match->mask;
	struct nf_flow_key *key = &match->key;
	unsigned int enc_keys;

	if (!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX))
		return;

	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_ENC_CONTROL, enc_control);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
	key->enc_key_id.keyid = tunnel_id_to_key32(tun_info->key.tun_id);
	mask->enc_key_id.keyid = 0xffffffff;
	enc_keys = BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
		   BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL);

	if (ip_tunnel_info_af(tun_info) == AF_INET) {
		NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
				  enc_ipv4);
		key->enc_ipv4.src = tun_info->key.u.ipv4.dst;
		key->enc_ipv4.dst = tun_info->key.u.ipv4.src;
		if (key->enc_ipv4.src)
			mask->enc_ipv4.src = 0xffffffff;
		if (key->enc_ipv4.dst)
			mask->enc_ipv4.dst = 0xffffffff;
		enc_keys |= BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS);
		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
	} else {
		memcpy(&key->enc_ipv6.src, &tun_info->key.u.ipv6.dst,
		       sizeof(struct in6_addr));
		memcpy(&key->enc_ipv6.dst, &tun_info->key.u.ipv6.src,
		       sizeof(struct in6_addr));
		if (memcmp(&key->enc_ipv6.src, &in6addr_any,
			   sizeof(struct in6_addr)))
			memset(&key->enc_ipv6.src, 0xff,
			       sizeof(struct in6_addr));
		if (memcmp(&key->enc_ipv6.dst, &in6addr_any,
			   sizeof(struct in6_addr)))
			memset(&key->enc_ipv6.dst, 0xff,
			       sizeof(struct in6_addr));
		enc_keys |= BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS);
		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
	}

	match->dissector.used_keys |= enc_keys;
}

static int nf_flow_rule_match(struct nf_flow_match *match,
static int nf_flow_rule_match(struct nf_flow_match *match,
			      const struct flow_offload_tuple *tuple)
			      const struct flow_offload_tuple *tuple,
			      struct dst_entry *other_dst)
{
{
	struct nf_flow_key *mask = &match->mask;
	struct nf_flow_key *mask = &match->mask;
	struct nf_flow_key *key = &match->key;
	struct nf_flow_key *key = &match->key;
	struct ip_tunnel_info *tun_info;


	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_META, meta);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_META, meta);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_CONTROL, control);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_CONTROL, control);
@@ -42,6 +92,11 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);


	if (other_dst->lwtstate) {
		tun_info = lwt_tun_info(other_dst->lwtstate);
		nf_flow_rule_lwt_match(match, tun_info);
	}

	key->meta.ingress_ifindex = tuple->iifidx;
	key->meta.ingress_ifindex = tuple->iifidx;
	mask->meta.ingress_ifindex = 0xffffffff;
	mask->meta.ingress_ifindex = 0xffffffff;


@@ -480,6 +535,7 @@ nf_flow_offload_rule_alloc(struct net *net,
	const struct flow_offload *flow = offload->flow;
	const struct flow_offload *flow = offload->flow;
	const struct flow_offload_tuple *tuple;
	const struct flow_offload_tuple *tuple;
	struct nf_flow_rule *flow_rule;
	struct nf_flow_rule *flow_rule;
	struct dst_entry *other_dst;
	int err = -ENOMEM;
	int err = -ENOMEM;


	flow_rule = kzalloc(sizeof(*flow_rule), GFP_KERNEL);
	flow_rule = kzalloc(sizeof(*flow_rule), GFP_KERNEL);
@@ -495,7 +551,8 @@ nf_flow_offload_rule_alloc(struct net *net,
	flow_rule->rule->match.key = &flow_rule->match.key;
	flow_rule->rule->match.key = &flow_rule->match.key;


	tuple = &flow->tuplehash[dir].tuple;
	tuple = &flow->tuplehash[dir].tuple;
	err = nf_flow_rule_match(&flow_rule->match, tuple);
	other_dst = flow->tuplehash[!dir].tuple.dst_cache;
	err = nf_flow_rule_match(&flow_rule->match, tuple, other_dst);
	if (err < 0)
	if (err < 0)
		goto err_flow_match;
		goto err_flow_match;