[nf-next,v2,3/4] netfilter: nf_flow_table_offload: add tunnel match offload support
diff mbox series

Message ID 1574330056-5377-4-git-send-email-wenxu@ucloud.cn
State Superseded
Delegated to: Pablo Neira
Headers show
Series
  • netfilter: nf_flow_table_offload: support tunnel offload
Related show

Commit Message

wenxu Nov. 21, 2019, 9:54 a.m. UTC
From: wenxu <wenxu@ucloud.cn>

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

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v2: add ecn_control to match outer addr

 net/netfilter/nf_flow_table_offload.c | 67 +++++++++++++++++++++++++++++++++--
 1 file changed, 65 insertions(+), 2 deletions(-)

Comments

wenxu Nov. 21, 2019, 12:37 p.m. UTC | #1
在 2019/11/21 17:54, wenxu@ucloud.cn 写道:
> From: wenxu <wenxu@ucloud.cn>
>
> This patch support both ipv4 and ipv6 tunnel_id, tunnel_src and
> tunnel_dst match for flowtable offload
>
> Signed-off-by: wenxu <wenxu@ucloud.cn>
> ---
> v2: add ecn_control to match outer addr
>
>  net/netfilter/nf_flow_table_offload.c | 67 +++++++++++++++++++++++++++++++++--
>  1 file changed, 65 insertions(+), 2 deletions(-)
>
> diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
> index 653866f..656095c 100644
> --- a/net/netfilter/nf_flow_table_offload.c
> +++ b/net/netfilter/nf_flow_table_offload.c
> @@ -26,10 +26,16 @@ struct flow_offload_work {
>  
>  struct nf_flow_key {
>  	struct flow_dissector_key_control		control;
> +	struct flow_dissector_key_control               enc_control;
>  	struct flow_dissector_key_basic			basic;
>  	union {
>  		struct flow_dissector_key_ipv4_addrs	ipv4;
>  	};
> +	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_ports			tp;
>  } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
> @@ -49,11 +55,61 @@ struct nf_flow_rule {
>  	(__match)->dissector.offset[__type] =		\
>  		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,
> -			      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 *key = &match->key;
> +	struct ip_tunnel_info *tun_info;
>  
>  	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_CONTROL, control);
>  	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_BASIC, basic);
> @@ -61,6 +117,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_PORTS, tp);
>  
> +	if (other_dst->lwtstate) {
> +		tun_info = lwt_tun_info(other_dst->lwtstate);
> +		nf_flow_rule_lwt_match(match, tun_info);
> +	}
> +
>  	switch (tuple->l3proto) {
>  	case AF_INET:
>  		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
> @@ -468,6 +529,7 @@ int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
>  	const struct flow_offload *flow = offload->flow;
>  	const struct flow_offload_tuple *tuple;
>  	struct nf_flow_rule *flow_rule;
> +	struct dst_entry *other_dst;
>  	int err = -ENOMEM;
>  
>  	flow_rule = kzalloc(sizeof(*flow_rule), GFP_KERNEL);
> @@ -483,7 +545,8 @@ int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
>  	flow_rule->rule->match.key = &flow_rule->match.key;
>  
>  	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)
>  		goto err_flow_match;
>

Patch
diff mbox series

diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index 653866f..656095c 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -26,10 +26,16 @@  struct flow_offload_work {
 
 struct nf_flow_key {
 	struct flow_dissector_key_control		control;
+	struct flow_dissector_key_control               enc_control;
 	struct flow_dissector_key_basic			basic;
 	union {
 		struct flow_dissector_key_ipv4_addrs	ipv4;
 	};
+	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_ports			tp;
 } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
@@ -49,11 +55,61 @@  struct nf_flow_rule {
 	(__match)->dissector.offset[__type] =		\
 		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,
-			      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 *key = &match->key;
+	struct ip_tunnel_info *tun_info;
 
 	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_CONTROL, control);
 	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_BASIC, basic);
@@ -61,6 +117,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_PORTS, tp);
 
+	if (other_dst->lwtstate) {
+		tun_info = lwt_tun_info(other_dst->lwtstate);
+		nf_flow_rule_lwt_match(match, tun_info);
+	}
+
 	switch (tuple->l3proto) {
 	case AF_INET:
 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
@@ -468,6 +529,7 @@  int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
 	const struct flow_offload *flow = offload->flow;
 	const struct flow_offload_tuple *tuple;
 	struct nf_flow_rule *flow_rule;
+	struct dst_entry *other_dst;
 	int err = -ENOMEM;
 
 	flow_rule = kzalloc(sizeof(*flow_rule), GFP_KERNEL);
@@ -483,7 +545,8 @@  int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
 	flow_rule->rule->match.key = &flow_rule->match.key;
 
 	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)
 		goto err_flow_match;