162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/bitfield.h>
562306a36Sopenharmony_ci#include <net/pkt_cls.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "cmsg.h"
862306a36Sopenharmony_ci#include "main.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_civoid
1162306a36Sopenharmony_cinfp_flower_compile_meta(struct nfp_flower_meta_tci *ext,
1262306a36Sopenharmony_ci			struct nfp_flower_meta_tci *msk, u8 key_type)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	/* Populate the metadata frame. */
1562306a36Sopenharmony_ci	ext->nfp_flow_key_layer = key_type;
1662306a36Sopenharmony_ci	ext->mask_id = ~0;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	msk->nfp_flow_key_layer = key_type;
1962306a36Sopenharmony_ci	msk->mask_id = ~0;
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_civoid
2362306a36Sopenharmony_cinfp_flower_compile_tci(struct nfp_flower_meta_tci *ext,
2462306a36Sopenharmony_ci		       struct nfp_flower_meta_tci *msk,
2562306a36Sopenharmony_ci		       struct flow_rule *rule)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	u16 msk_tci, key_tci;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
3062306a36Sopenharmony_ci		struct flow_match_vlan match;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci		flow_rule_match_vlan(rule, &match);
3362306a36Sopenharmony_ci		/* Populate the tci field. */
3462306a36Sopenharmony_ci		key_tci = NFP_FLOWER_MASK_VLAN_PRESENT;
3562306a36Sopenharmony_ci		key_tci |= FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO,
3662306a36Sopenharmony_ci				      match.key->vlan_priority) |
3762306a36Sopenharmony_ci			   FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID,
3862306a36Sopenharmony_ci				      match.key->vlan_id);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci		msk_tci = NFP_FLOWER_MASK_VLAN_PRESENT;
4162306a36Sopenharmony_ci		msk_tci |= FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO,
4262306a36Sopenharmony_ci				      match.mask->vlan_priority) |
4362306a36Sopenharmony_ci			   FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID,
4462306a36Sopenharmony_ci				      match.mask->vlan_id);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		ext->tci |= cpu_to_be16((key_tci & msk_tci));
4762306a36Sopenharmony_ci		msk->tci |= cpu_to_be16(msk_tci);
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void
5262306a36Sopenharmony_cinfp_flower_compile_meta_tci(struct nfp_flower_meta_tci *ext,
5362306a36Sopenharmony_ci			    struct nfp_flower_meta_tci *msk,
5462306a36Sopenharmony_ci			    struct flow_rule *rule, u8 key_type, bool qinq_sup)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	memset(ext, 0, sizeof(struct nfp_flower_meta_tci));
5762306a36Sopenharmony_ci	memset(msk, 0, sizeof(struct nfp_flower_meta_tci));
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	nfp_flower_compile_meta(ext, msk, key_type);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (!qinq_sup)
6262306a36Sopenharmony_ci		nfp_flower_compile_tci(ext, msk, rule);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_civoid
6662306a36Sopenharmony_cinfp_flower_compile_ext_meta(struct nfp_flower_ext_meta *frame, u32 key_ext)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	frame->nfp_flow_key_layer2 = cpu_to_be32(key_ext);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ciint
7262306a36Sopenharmony_cinfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
7362306a36Sopenharmony_ci			bool mask_version, enum nfp_flower_tun_type tun_type,
7462306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	if (mask_version) {
7762306a36Sopenharmony_ci		frame->in_port = cpu_to_be32(~0);
7862306a36Sopenharmony_ci		return 0;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (tun_type) {
8262306a36Sopenharmony_ci		frame->in_port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type);
8362306a36Sopenharmony_ci	} else {
8462306a36Sopenharmony_ci		if (!cmsg_port) {
8562306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid ingress interface for match offload");
8662306a36Sopenharmony_ci			return -EOPNOTSUPP;
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci		frame->in_port = cpu_to_be32(cmsg_port);
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_civoid
9562306a36Sopenharmony_cinfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
9662306a36Sopenharmony_ci		       struct nfp_flower_mac_mpls *msk,
9762306a36Sopenharmony_ci		       struct flow_rule *rule)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
10062306a36Sopenharmony_ci		struct flow_match_eth_addrs match;
10162306a36Sopenharmony_ci		u8 tmp;
10262306a36Sopenharmony_ci		int i;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		flow_rule_match_eth_addrs(rule, &match);
10562306a36Sopenharmony_ci		/* Populate mac frame. */
10662306a36Sopenharmony_ci		for (i = 0; i < ETH_ALEN; i++) {
10762306a36Sopenharmony_ci			tmp = match.key->dst[i] & match.mask->dst[i];
10862306a36Sopenharmony_ci			ext->mac_dst[i] |= tmp & (~msk->mac_dst[i]);
10962306a36Sopenharmony_ci			msk->mac_dst[i] |= match.mask->dst[i];
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci			tmp = match.key->src[i] & match.mask->src[i];
11262306a36Sopenharmony_ci			ext->mac_src[i] |= tmp & (~msk->mac_src[i]);
11362306a36Sopenharmony_ci			msk->mac_src[i] |= match.mask->src[i];
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciint
11962306a36Sopenharmony_cinfp_flower_compile_mpls(struct nfp_flower_mac_mpls *ext,
12062306a36Sopenharmony_ci			struct nfp_flower_mac_mpls *msk,
12162306a36Sopenharmony_ci			struct flow_rule *rule,
12262306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS)) {
12562306a36Sopenharmony_ci		struct flow_match_mpls match;
12662306a36Sopenharmony_ci		u32 key_mpls, msk_mpls;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		flow_rule_match_mpls(rule, &match);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		/* Only support matching the first LSE */
13162306a36Sopenharmony_ci		if (match.mask->used_lses != 1) {
13262306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack,
13362306a36Sopenharmony_ci					   "unsupported offload: invalid LSE depth for MPLS match offload");
13462306a36Sopenharmony_ci			return -EOPNOTSUPP;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		key_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB,
13862306a36Sopenharmony_ci				      match.key->ls[0].mpls_label) |
13962306a36Sopenharmony_ci			   FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC,
14062306a36Sopenharmony_ci				      match.key->ls[0].mpls_tc) |
14162306a36Sopenharmony_ci			   FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS,
14262306a36Sopenharmony_ci				      match.key->ls[0].mpls_bos) |
14362306a36Sopenharmony_ci			   NFP_FLOWER_MASK_MPLS_Q;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		msk_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB,
14662306a36Sopenharmony_ci				      match.mask->ls[0].mpls_label) |
14762306a36Sopenharmony_ci			   FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC,
14862306a36Sopenharmony_ci				      match.mask->ls[0].mpls_tc) |
14962306a36Sopenharmony_ci			   FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS,
15062306a36Sopenharmony_ci				      match.mask->ls[0].mpls_bos) |
15162306a36Sopenharmony_ci			   NFP_FLOWER_MASK_MPLS_Q;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		ext->mpls_lse |= cpu_to_be32((key_mpls & msk_mpls));
15462306a36Sopenharmony_ci		msk->mpls_lse |= cpu_to_be32(msk_mpls);
15562306a36Sopenharmony_ci	} else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
15662306a36Sopenharmony_ci		/* Check for mpls ether type and set NFP_FLOWER_MASK_MPLS_Q
15762306a36Sopenharmony_ci		 * bit, which indicates an mpls ether type but without any
15862306a36Sopenharmony_ci		 * mpls fields.
15962306a36Sopenharmony_ci		 */
16062306a36Sopenharmony_ci		struct flow_match_basic match;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		flow_rule_match_basic(rule, &match);
16362306a36Sopenharmony_ci		if (match.key->n_proto == cpu_to_be16(ETH_P_MPLS_UC) ||
16462306a36Sopenharmony_ci		    match.key->n_proto == cpu_to_be16(ETH_P_MPLS_MC)) {
16562306a36Sopenharmony_ci			ext->mpls_lse |= cpu_to_be32(NFP_FLOWER_MASK_MPLS_Q);
16662306a36Sopenharmony_ci			msk->mpls_lse |= cpu_to_be32(NFP_FLOWER_MASK_MPLS_Q);
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return 0;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int
17462306a36Sopenharmony_cinfp_flower_compile_mac_mpls(struct nfp_flower_mac_mpls *ext,
17562306a36Sopenharmony_ci			    struct nfp_flower_mac_mpls *msk,
17662306a36Sopenharmony_ci			    struct flow_rule *rule,
17762306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	memset(ext, 0, sizeof(struct nfp_flower_mac_mpls));
18062306a36Sopenharmony_ci	memset(msk, 0, sizeof(struct nfp_flower_mac_mpls));
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	nfp_flower_compile_mac(ext, msk, rule);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return nfp_flower_compile_mpls(ext, msk, rule, extack);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_civoid
18862306a36Sopenharmony_cinfp_flower_compile_tport(struct nfp_flower_tp_ports *ext,
18962306a36Sopenharmony_ci			 struct nfp_flower_tp_ports *msk,
19062306a36Sopenharmony_ci			 struct flow_rule *rule)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
19362306a36Sopenharmony_ci		struct flow_match_ports match;
19462306a36Sopenharmony_ci		__be16 tmp;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		flow_rule_match_ports(rule, &match);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		tmp = match.key->src & match.mask->src;
19962306a36Sopenharmony_ci		ext->port_src |= tmp & (~msk->port_src);
20062306a36Sopenharmony_ci		msk->port_src |= match.mask->src;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		tmp = match.key->dst & match.mask->dst;
20362306a36Sopenharmony_ci		ext->port_dst |= tmp & (~msk->port_dst);
20462306a36Sopenharmony_ci		msk->port_dst |= match.mask->dst;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void
20962306a36Sopenharmony_cinfp_flower_compile_ip_ext(struct nfp_flower_ip_ext *ext,
21062306a36Sopenharmony_ci			  struct nfp_flower_ip_ext *msk, struct flow_rule *rule)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
21362306a36Sopenharmony_ci		struct flow_match_basic match;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		flow_rule_match_basic(rule, &match);
21662306a36Sopenharmony_ci		ext->proto |= match.key->ip_proto & match.mask->ip_proto;
21762306a36Sopenharmony_ci		msk->proto |= match.mask->ip_proto;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
22162306a36Sopenharmony_ci		struct flow_match_ip match;
22262306a36Sopenharmony_ci		u8 tmp;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		flow_rule_match_ip(rule, &match);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		tmp = match.key->tos & match.mask->tos;
22762306a36Sopenharmony_ci		ext->tos |= tmp & (~msk->tos);
22862306a36Sopenharmony_ci		msk->tos |= match.mask->tos;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		tmp = match.key->ttl & match.mask->ttl;
23162306a36Sopenharmony_ci		ext->ttl |= tmp & (~msk->ttl);
23262306a36Sopenharmony_ci		msk->ttl |= match.mask->ttl;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP)) {
23662306a36Sopenharmony_ci		u16 tcp_flags, tcp_flags_mask;
23762306a36Sopenharmony_ci		struct flow_match_tcp match;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		flow_rule_match_tcp(rule, &match);
24062306a36Sopenharmony_ci		tcp_flags = be16_to_cpu(match.key->flags);
24162306a36Sopenharmony_ci		tcp_flags_mask = be16_to_cpu(match.mask->flags);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		if (tcp_flags & TCPHDR_FIN)
24462306a36Sopenharmony_ci			ext->flags |= NFP_FL_TCP_FLAG_FIN;
24562306a36Sopenharmony_ci		if (tcp_flags_mask & TCPHDR_FIN)
24662306a36Sopenharmony_ci			msk->flags |= NFP_FL_TCP_FLAG_FIN;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		if (tcp_flags & TCPHDR_SYN)
24962306a36Sopenharmony_ci			ext->flags |= NFP_FL_TCP_FLAG_SYN;
25062306a36Sopenharmony_ci		if (tcp_flags_mask & TCPHDR_SYN)
25162306a36Sopenharmony_ci			msk->flags |= NFP_FL_TCP_FLAG_SYN;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		if (tcp_flags & TCPHDR_RST)
25462306a36Sopenharmony_ci			ext->flags |= NFP_FL_TCP_FLAG_RST;
25562306a36Sopenharmony_ci		if (tcp_flags_mask & TCPHDR_RST)
25662306a36Sopenharmony_ci			msk->flags |= NFP_FL_TCP_FLAG_RST;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		if (tcp_flags & TCPHDR_PSH)
25962306a36Sopenharmony_ci			ext->flags |= NFP_FL_TCP_FLAG_PSH;
26062306a36Sopenharmony_ci		if (tcp_flags_mask & TCPHDR_PSH)
26162306a36Sopenharmony_ci			msk->flags |= NFP_FL_TCP_FLAG_PSH;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (tcp_flags & TCPHDR_URG)
26462306a36Sopenharmony_ci			ext->flags |= NFP_FL_TCP_FLAG_URG;
26562306a36Sopenharmony_ci		if (tcp_flags_mask & TCPHDR_URG)
26662306a36Sopenharmony_ci			msk->flags |= NFP_FL_TCP_FLAG_URG;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
27062306a36Sopenharmony_ci		struct flow_match_control match;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		flow_rule_match_control(rule, &match);
27362306a36Sopenharmony_ci		if (match.key->flags & FLOW_DIS_IS_FRAGMENT)
27462306a36Sopenharmony_ci			ext->flags |= NFP_FL_IP_FRAGMENTED;
27562306a36Sopenharmony_ci		if (match.mask->flags & FLOW_DIS_IS_FRAGMENT)
27662306a36Sopenharmony_ci			msk->flags |= NFP_FL_IP_FRAGMENTED;
27762306a36Sopenharmony_ci		if (match.key->flags & FLOW_DIS_FIRST_FRAG)
27862306a36Sopenharmony_ci			ext->flags |= NFP_FL_IP_FRAG_FIRST;
27962306a36Sopenharmony_ci		if (match.mask->flags & FLOW_DIS_FIRST_FRAG)
28062306a36Sopenharmony_ci			msk->flags |= NFP_FL_IP_FRAG_FIRST;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void
28562306a36Sopenharmony_cinfp_flower_fill_vlan(struct flow_match_vlan *match,
28662306a36Sopenharmony_ci		     struct nfp_flower_vlan *ext,
28762306a36Sopenharmony_ci		     struct nfp_flower_vlan *msk, bool outer_vlan)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct flow_dissector_key_vlan *mask = match->mask;
29062306a36Sopenharmony_ci	struct flow_dissector_key_vlan *key = match->key;
29162306a36Sopenharmony_ci	u16 msk_tci, key_tci;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	key_tci = NFP_FLOWER_MASK_VLAN_PRESENT;
29462306a36Sopenharmony_ci	key_tci |= FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO,
29562306a36Sopenharmony_ci			      key->vlan_priority) |
29662306a36Sopenharmony_ci		   FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID,
29762306a36Sopenharmony_ci			      key->vlan_id);
29862306a36Sopenharmony_ci	msk_tci = NFP_FLOWER_MASK_VLAN_PRESENT;
29962306a36Sopenharmony_ci	msk_tci |= FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO,
30062306a36Sopenharmony_ci			      mask->vlan_priority) |
30162306a36Sopenharmony_ci		   FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID,
30262306a36Sopenharmony_ci			      mask->vlan_id);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (outer_vlan) {
30562306a36Sopenharmony_ci		ext->outer_tci |= cpu_to_be16((key_tci & msk_tci));
30662306a36Sopenharmony_ci		ext->outer_tpid |= key->vlan_tpid & mask->vlan_tpid;
30762306a36Sopenharmony_ci		msk->outer_tci |= cpu_to_be16(msk_tci);
30862306a36Sopenharmony_ci		msk->outer_tpid |= mask->vlan_tpid;
30962306a36Sopenharmony_ci	} else {
31062306a36Sopenharmony_ci		ext->inner_tci |= cpu_to_be16((key_tci & msk_tci));
31162306a36Sopenharmony_ci		ext->inner_tpid |= key->vlan_tpid & mask->vlan_tpid;
31262306a36Sopenharmony_ci		msk->inner_tci |= cpu_to_be16(msk_tci);
31362306a36Sopenharmony_ci		msk->inner_tpid |= mask->vlan_tpid;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_civoid
31862306a36Sopenharmony_cinfp_flower_compile_vlan(struct nfp_flower_vlan *ext,
31962306a36Sopenharmony_ci			struct nfp_flower_vlan *msk,
32062306a36Sopenharmony_ci			struct flow_rule *rule)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct flow_match_vlan match;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
32562306a36Sopenharmony_ci		flow_rule_match_vlan(rule, &match);
32662306a36Sopenharmony_ci		nfp_flower_fill_vlan(&match, ext, msk, true);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
32962306a36Sopenharmony_ci		flow_rule_match_cvlan(rule, &match);
33062306a36Sopenharmony_ci		nfp_flower_fill_vlan(&match, ext, msk, false);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_civoid
33562306a36Sopenharmony_cinfp_flower_compile_ipv4(struct nfp_flower_ipv4 *ext,
33662306a36Sopenharmony_ci			struct nfp_flower_ipv4 *msk, struct flow_rule *rule)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
33962306a36Sopenharmony_ci		struct flow_match_ipv4_addrs match;
34062306a36Sopenharmony_ci		__be32 tmp;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		flow_rule_match_ipv4_addrs(rule, &match);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		tmp = match.key->src & match.mask->src;
34562306a36Sopenharmony_ci		ext->ipv4_src |= tmp & (~msk->ipv4_src);
34662306a36Sopenharmony_ci		msk->ipv4_src |= match.mask->src;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		tmp = match.key->dst & match.mask->dst;
34962306a36Sopenharmony_ci		ext->ipv4_dst |= tmp & (~msk->ipv4_dst);
35062306a36Sopenharmony_ci		msk->ipv4_dst |= match.mask->dst;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	nfp_flower_compile_ip_ext(&ext->ip_ext, &msk->ip_ext, rule);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_civoid
35762306a36Sopenharmony_cinfp_flower_compile_ipv6(struct nfp_flower_ipv6 *ext,
35862306a36Sopenharmony_ci			struct nfp_flower_ipv6 *msk, struct flow_rule *rule)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
36162306a36Sopenharmony_ci		struct flow_match_ipv6_addrs match;
36262306a36Sopenharmony_ci		u8 tmp;
36362306a36Sopenharmony_ci		int i;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		flow_rule_match_ipv6_addrs(rule, &match);
36662306a36Sopenharmony_ci		for (i = 0; i < sizeof(ext->ipv6_src); i++) {
36762306a36Sopenharmony_ci			tmp = match.key->src.s6_addr[i] &
36862306a36Sopenharmony_ci			      match.mask->src.s6_addr[i];
36962306a36Sopenharmony_ci			ext->ipv6_src.s6_addr[i] |= tmp &
37062306a36Sopenharmony_ci						    (~msk->ipv6_src.s6_addr[i]);
37162306a36Sopenharmony_ci			msk->ipv6_src.s6_addr[i] |= match.mask->src.s6_addr[i];
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci			tmp = match.key->dst.s6_addr[i] &
37462306a36Sopenharmony_ci			      match.mask->dst.s6_addr[i];
37562306a36Sopenharmony_ci			ext->ipv6_dst.s6_addr[i] |= tmp &
37662306a36Sopenharmony_ci						    (~msk->ipv6_dst.s6_addr[i]);
37762306a36Sopenharmony_ci			msk->ipv6_dst.s6_addr[i] |= match.mask->dst.s6_addr[i];
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	nfp_flower_compile_ip_ext(&ext->ip_ext, &msk->ip_ext, rule);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_civoid
38562306a36Sopenharmony_cinfp_flower_compile_geneve_opt(u8 *ext, u8 *msk, struct flow_rule *rule)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct flow_match_enc_opts match;
38862306a36Sopenharmony_ci	int i;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS)) {
39162306a36Sopenharmony_ci		flow_rule_match_enc_opts(rule, &match);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		for (i = 0; i < match.mask->len; i++) {
39462306a36Sopenharmony_ci			ext[i] |= match.key->data[i] & match.mask->data[i];
39562306a36Sopenharmony_ci			msk[i] |= match.mask->data[i];
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void
40162306a36Sopenharmony_cinfp_flower_compile_tun_ipv4_addrs(struct nfp_flower_tun_ipv4 *ext,
40262306a36Sopenharmony_ci				  struct nfp_flower_tun_ipv4 *msk,
40362306a36Sopenharmony_ci				  struct flow_rule *rule)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
40662306a36Sopenharmony_ci		struct flow_match_ipv4_addrs match;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		flow_rule_match_enc_ipv4_addrs(rule, &match);
40962306a36Sopenharmony_ci		ext->src |= match.key->src & match.mask->src;
41062306a36Sopenharmony_ci		ext->dst |= match.key->dst & match.mask->dst;
41162306a36Sopenharmony_ci		msk->src |= match.mask->src;
41262306a36Sopenharmony_ci		msk->dst |= match.mask->dst;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic void
41762306a36Sopenharmony_cinfp_flower_compile_tun_ipv6_addrs(struct nfp_flower_tun_ipv6 *ext,
41862306a36Sopenharmony_ci				  struct nfp_flower_tun_ipv6 *msk,
41962306a36Sopenharmony_ci				  struct flow_rule *rule)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
42262306a36Sopenharmony_ci		struct flow_match_ipv6_addrs match;
42362306a36Sopenharmony_ci		int i;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		flow_rule_match_enc_ipv6_addrs(rule, &match);
42662306a36Sopenharmony_ci		for (i = 0; i < sizeof(ext->src); i++) {
42762306a36Sopenharmony_ci			ext->src.s6_addr[i] |= match.key->src.s6_addr[i] &
42862306a36Sopenharmony_ci					       match.mask->src.s6_addr[i];
42962306a36Sopenharmony_ci			ext->dst.s6_addr[i] |= match.key->dst.s6_addr[i] &
43062306a36Sopenharmony_ci					       match.mask->dst.s6_addr[i];
43162306a36Sopenharmony_ci			msk->src.s6_addr[i] |= match.mask->src.s6_addr[i];
43262306a36Sopenharmony_ci			msk->dst.s6_addr[i] |= match.mask->dst.s6_addr[i];
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic void
43862306a36Sopenharmony_cinfp_flower_compile_tun_ip_ext(struct nfp_flower_tun_ip_ext *ext,
43962306a36Sopenharmony_ci			      struct nfp_flower_tun_ip_ext *msk,
44062306a36Sopenharmony_ci			      struct flow_rule *rule)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IP)) {
44362306a36Sopenharmony_ci		struct flow_match_ip match;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		flow_rule_match_enc_ip(rule, &match);
44662306a36Sopenharmony_ci		ext->tos |= match.key->tos & match.mask->tos;
44762306a36Sopenharmony_ci		ext->ttl |= match.key->ttl & match.mask->ttl;
44862306a36Sopenharmony_ci		msk->tos |= match.mask->tos;
44962306a36Sopenharmony_ci		msk->ttl |= match.mask->ttl;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic void
45462306a36Sopenharmony_cinfp_flower_compile_tun_udp_key(__be32 *key, __be32 *key_msk,
45562306a36Sopenharmony_ci			       struct flow_rule *rule)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
45862306a36Sopenharmony_ci		struct flow_match_enc_keyid match;
45962306a36Sopenharmony_ci		u32 vni;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		flow_rule_match_enc_keyid(rule, &match);
46262306a36Sopenharmony_ci		vni = be32_to_cpu((match.key->keyid & match.mask->keyid)) <<
46362306a36Sopenharmony_ci		      NFP_FL_TUN_VNI_OFFSET;
46462306a36Sopenharmony_ci		*key |= cpu_to_be32(vni);
46562306a36Sopenharmony_ci		vni = be32_to_cpu(match.mask->keyid) << NFP_FL_TUN_VNI_OFFSET;
46662306a36Sopenharmony_ci		*key_msk |= cpu_to_be32(vni);
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic void
47162306a36Sopenharmony_cinfp_flower_compile_tun_gre_key(__be32 *key, __be32 *key_msk, __be16 *flags,
47262306a36Sopenharmony_ci			       __be16 *flags_msk, struct flow_rule *rule)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
47562306a36Sopenharmony_ci		struct flow_match_enc_keyid match;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		flow_rule_match_enc_keyid(rule, &match);
47862306a36Sopenharmony_ci		*key |= match.key->keyid & match.mask->keyid;
47962306a36Sopenharmony_ci		*key_msk |= match.mask->keyid;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		*flags = cpu_to_be16(NFP_FL_GRE_FLAG_KEY);
48262306a36Sopenharmony_ci		*flags_msk = cpu_to_be16(NFP_FL_GRE_FLAG_KEY);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_civoid
48762306a36Sopenharmony_cinfp_flower_compile_ipv4_gre_tun(struct nfp_flower_ipv4_gre_tun *ext,
48862306a36Sopenharmony_ci				struct nfp_flower_ipv4_gre_tun *msk,
48962306a36Sopenharmony_ci				struct flow_rule *rule)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	/* NVGRE is the only supported GRE tunnel type */
49262306a36Sopenharmony_ci	ext->ethertype = cpu_to_be16(ETH_P_TEB);
49362306a36Sopenharmony_ci	msk->ethertype = cpu_to_be16(~0);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	nfp_flower_compile_tun_ipv4_addrs(&ext->ipv4, &msk->ipv4, rule);
49662306a36Sopenharmony_ci	nfp_flower_compile_tun_ip_ext(&ext->ip_ext, &msk->ip_ext, rule);
49762306a36Sopenharmony_ci	nfp_flower_compile_tun_gre_key(&ext->tun_key, &msk->tun_key,
49862306a36Sopenharmony_ci				       &ext->tun_flags, &msk->tun_flags, rule);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_civoid
50262306a36Sopenharmony_cinfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *ext,
50362306a36Sopenharmony_ci				struct nfp_flower_ipv4_udp_tun *msk,
50462306a36Sopenharmony_ci				struct flow_rule *rule)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	nfp_flower_compile_tun_ipv4_addrs(&ext->ipv4, &msk->ipv4, rule);
50762306a36Sopenharmony_ci	nfp_flower_compile_tun_ip_ext(&ext->ip_ext, &msk->ip_ext, rule);
50862306a36Sopenharmony_ci	nfp_flower_compile_tun_udp_key(&ext->tun_id, &msk->tun_id, rule);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_civoid
51262306a36Sopenharmony_cinfp_flower_compile_ipv6_udp_tun(struct nfp_flower_ipv6_udp_tun *ext,
51362306a36Sopenharmony_ci				struct nfp_flower_ipv6_udp_tun *msk,
51462306a36Sopenharmony_ci				struct flow_rule *rule)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	nfp_flower_compile_tun_ipv6_addrs(&ext->ipv6, &msk->ipv6, rule);
51762306a36Sopenharmony_ci	nfp_flower_compile_tun_ip_ext(&ext->ip_ext, &msk->ip_ext, rule);
51862306a36Sopenharmony_ci	nfp_flower_compile_tun_udp_key(&ext->tun_id, &msk->tun_id, rule);
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_civoid
52262306a36Sopenharmony_cinfp_flower_compile_ipv6_gre_tun(struct nfp_flower_ipv6_gre_tun *ext,
52362306a36Sopenharmony_ci				struct nfp_flower_ipv6_gre_tun *msk,
52462306a36Sopenharmony_ci				struct flow_rule *rule)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	/* NVGRE is the only supported GRE tunnel type */
52762306a36Sopenharmony_ci	ext->ethertype = cpu_to_be16(ETH_P_TEB);
52862306a36Sopenharmony_ci	msk->ethertype = cpu_to_be16(~0);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	nfp_flower_compile_tun_ipv6_addrs(&ext->ipv6, &msk->ipv6, rule);
53162306a36Sopenharmony_ci	nfp_flower_compile_tun_ip_ext(&ext->ip_ext, &msk->ip_ext, rule);
53262306a36Sopenharmony_ci	nfp_flower_compile_tun_gre_key(&ext->tun_key, &msk->tun_key,
53362306a36Sopenharmony_ci				       &ext->tun_flags, &msk->tun_flags, rule);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ciint nfp_flower_compile_flow_match(struct nfp_app *app,
53762306a36Sopenharmony_ci				  struct flow_rule *rule,
53862306a36Sopenharmony_ci				  struct nfp_fl_key_ls *key_ls,
53962306a36Sopenharmony_ci				  struct net_device *netdev,
54062306a36Sopenharmony_ci				  struct nfp_fl_payload *nfp_flow,
54162306a36Sopenharmony_ci				  enum nfp_flower_tun_type tun_type,
54262306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct nfp_flower_priv *priv = app->priv;
54562306a36Sopenharmony_ci	bool qinq_sup;
54662306a36Sopenharmony_ci	u32 port_id;
54762306a36Sopenharmony_ci	int ext_len;
54862306a36Sopenharmony_ci	int err;
54962306a36Sopenharmony_ci	u8 *ext;
55062306a36Sopenharmony_ci	u8 *msk;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	memset(nfp_flow->unmasked_data, 0, key_ls->key_size);
55562306a36Sopenharmony_ci	memset(nfp_flow->mask_data, 0, key_ls->key_size);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	ext = nfp_flow->unmasked_data;
55862306a36Sopenharmony_ci	msk = nfp_flow->mask_data;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	qinq_sup = !!(priv->flower_ext_feats & NFP_FL_FEATS_VLAN_QINQ);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	nfp_flower_compile_meta_tci((struct nfp_flower_meta_tci *)ext,
56362306a36Sopenharmony_ci				    (struct nfp_flower_meta_tci *)msk,
56462306a36Sopenharmony_ci				    rule, key_ls->key_layer, qinq_sup);
56562306a36Sopenharmony_ci	ext += sizeof(struct nfp_flower_meta_tci);
56662306a36Sopenharmony_ci	msk += sizeof(struct nfp_flower_meta_tci);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/* Populate Extended Metadata if Required. */
56962306a36Sopenharmony_ci	if (NFP_FLOWER_LAYER_EXT_META & key_ls->key_layer) {
57062306a36Sopenharmony_ci		nfp_flower_compile_ext_meta((struct nfp_flower_ext_meta *)ext,
57162306a36Sopenharmony_ci					    key_ls->key_layer_two);
57262306a36Sopenharmony_ci		nfp_flower_compile_ext_meta((struct nfp_flower_ext_meta *)msk,
57362306a36Sopenharmony_ci					    key_ls->key_layer_two);
57462306a36Sopenharmony_ci		ext += sizeof(struct nfp_flower_ext_meta);
57562306a36Sopenharmony_ci		msk += sizeof(struct nfp_flower_ext_meta);
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* Populate Exact Port data. */
57962306a36Sopenharmony_ci	err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext,
58062306a36Sopenharmony_ci				      port_id, false, tun_type, extack);
58162306a36Sopenharmony_ci	if (err)
58262306a36Sopenharmony_ci		return err;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* Populate Mask Port Data. */
58562306a36Sopenharmony_ci	err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk,
58662306a36Sopenharmony_ci				      port_id, true, tun_type, extack);
58762306a36Sopenharmony_ci	if (err)
58862306a36Sopenharmony_ci		return err;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	ext += sizeof(struct nfp_flower_in_port);
59162306a36Sopenharmony_ci	msk += sizeof(struct nfp_flower_in_port);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (NFP_FLOWER_LAYER_MAC & key_ls->key_layer) {
59462306a36Sopenharmony_ci		err = nfp_flower_compile_mac_mpls((struct nfp_flower_mac_mpls *)ext,
59562306a36Sopenharmony_ci						  (struct nfp_flower_mac_mpls *)msk,
59662306a36Sopenharmony_ci						  rule, extack);
59762306a36Sopenharmony_ci		if (err)
59862306a36Sopenharmony_ci			return err;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		ext += sizeof(struct nfp_flower_mac_mpls);
60162306a36Sopenharmony_ci		msk += sizeof(struct nfp_flower_mac_mpls);
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (NFP_FLOWER_LAYER_TP & key_ls->key_layer) {
60562306a36Sopenharmony_ci		nfp_flower_compile_tport((struct nfp_flower_tp_ports *)ext,
60662306a36Sopenharmony_ci					 (struct nfp_flower_tp_ports *)msk,
60762306a36Sopenharmony_ci					 rule);
60862306a36Sopenharmony_ci		ext += sizeof(struct nfp_flower_tp_ports);
60962306a36Sopenharmony_ci		msk += sizeof(struct nfp_flower_tp_ports);
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (NFP_FLOWER_LAYER_IPV4 & key_ls->key_layer) {
61362306a36Sopenharmony_ci		nfp_flower_compile_ipv4((struct nfp_flower_ipv4 *)ext,
61462306a36Sopenharmony_ci					(struct nfp_flower_ipv4 *)msk,
61562306a36Sopenharmony_ci					rule);
61662306a36Sopenharmony_ci		ext += sizeof(struct nfp_flower_ipv4);
61762306a36Sopenharmony_ci		msk += sizeof(struct nfp_flower_ipv4);
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (NFP_FLOWER_LAYER_IPV6 & key_ls->key_layer) {
62162306a36Sopenharmony_ci		nfp_flower_compile_ipv6((struct nfp_flower_ipv6 *)ext,
62262306a36Sopenharmony_ci					(struct nfp_flower_ipv6 *)msk,
62362306a36Sopenharmony_ci					rule);
62462306a36Sopenharmony_ci		ext += sizeof(struct nfp_flower_ipv6);
62562306a36Sopenharmony_ci		msk += sizeof(struct nfp_flower_ipv6);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (NFP_FLOWER_LAYER2_QINQ & key_ls->key_layer_two) {
62962306a36Sopenharmony_ci		nfp_flower_compile_vlan((struct nfp_flower_vlan *)ext,
63062306a36Sopenharmony_ci					(struct nfp_flower_vlan *)msk,
63162306a36Sopenharmony_ci					rule);
63262306a36Sopenharmony_ci		ext += sizeof(struct nfp_flower_vlan);
63362306a36Sopenharmony_ci		msk += sizeof(struct nfp_flower_vlan);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_GRE) {
63762306a36Sopenharmony_ci		if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_TUN_IPV6) {
63862306a36Sopenharmony_ci			struct nfp_flower_ipv6_gre_tun *gre_match;
63962306a36Sopenharmony_ci			struct nfp_ipv6_addr_entry *entry;
64062306a36Sopenharmony_ci			struct in6_addr *dst;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci			nfp_flower_compile_ipv6_gre_tun((void *)ext,
64362306a36Sopenharmony_ci							(void *)msk, rule);
64462306a36Sopenharmony_ci			gre_match = (struct nfp_flower_ipv6_gre_tun *)ext;
64562306a36Sopenharmony_ci			dst = &gre_match->ipv6.dst;
64662306a36Sopenharmony_ci			ext += sizeof(struct nfp_flower_ipv6_gre_tun);
64762306a36Sopenharmony_ci			msk += sizeof(struct nfp_flower_ipv6_gre_tun);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci			entry = nfp_tunnel_add_ipv6_off(app, dst);
65062306a36Sopenharmony_ci			if (!entry)
65162306a36Sopenharmony_ci				return -EOPNOTSUPP;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci			nfp_flow->nfp_tun_ipv6 = entry;
65462306a36Sopenharmony_ci		} else {
65562306a36Sopenharmony_ci			__be32 dst;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci			nfp_flower_compile_ipv4_gre_tun((void *)ext,
65862306a36Sopenharmony_ci							(void *)msk, rule);
65962306a36Sopenharmony_ci			dst = ((struct nfp_flower_ipv4_gre_tun *)ext)->ipv4.dst;
66062306a36Sopenharmony_ci			ext += sizeof(struct nfp_flower_ipv4_gre_tun);
66162306a36Sopenharmony_ci			msk += sizeof(struct nfp_flower_ipv4_gre_tun);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci			/* Store the tunnel destination in the rule data.
66462306a36Sopenharmony_ci			 * This must be present and be an exact match.
66562306a36Sopenharmony_ci			 */
66662306a36Sopenharmony_ci			nfp_flow->nfp_tun_ipv4_addr = dst;
66762306a36Sopenharmony_ci			nfp_tunnel_add_ipv4_off(app, dst);
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN ||
67262306a36Sopenharmony_ci	    key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE) {
67362306a36Sopenharmony_ci		if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_TUN_IPV6) {
67462306a36Sopenharmony_ci			struct nfp_flower_ipv6_udp_tun *udp_match;
67562306a36Sopenharmony_ci			struct nfp_ipv6_addr_entry *entry;
67662306a36Sopenharmony_ci			struct in6_addr *dst;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci			nfp_flower_compile_ipv6_udp_tun((void *)ext,
67962306a36Sopenharmony_ci							(void *)msk, rule);
68062306a36Sopenharmony_ci			udp_match = (struct nfp_flower_ipv6_udp_tun *)ext;
68162306a36Sopenharmony_ci			dst = &udp_match->ipv6.dst;
68262306a36Sopenharmony_ci			ext += sizeof(struct nfp_flower_ipv6_udp_tun);
68362306a36Sopenharmony_ci			msk += sizeof(struct nfp_flower_ipv6_udp_tun);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci			entry = nfp_tunnel_add_ipv6_off(app, dst);
68662306a36Sopenharmony_ci			if (!entry)
68762306a36Sopenharmony_ci				return -EOPNOTSUPP;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci			nfp_flow->nfp_tun_ipv6 = entry;
69062306a36Sopenharmony_ci		} else {
69162306a36Sopenharmony_ci			__be32 dst;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci			nfp_flower_compile_ipv4_udp_tun((void *)ext,
69462306a36Sopenharmony_ci							(void *)msk, rule);
69562306a36Sopenharmony_ci			dst = ((struct nfp_flower_ipv4_udp_tun *)ext)->ipv4.dst;
69662306a36Sopenharmony_ci			ext += sizeof(struct nfp_flower_ipv4_udp_tun);
69762306a36Sopenharmony_ci			msk += sizeof(struct nfp_flower_ipv4_udp_tun);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci			/* Store the tunnel destination in the rule data.
70062306a36Sopenharmony_ci			 * This must be present and be an exact match.
70162306a36Sopenharmony_ci			 */
70262306a36Sopenharmony_ci			nfp_flow->nfp_tun_ipv4_addr = dst;
70362306a36Sopenharmony_ci			nfp_tunnel_add_ipv4_off(app, dst);
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE_OP) {
70762306a36Sopenharmony_ci			nfp_flower_compile_geneve_opt(ext, msk, rule);
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/* Check that the flow key does not exceed the maximum limit.
71262306a36Sopenharmony_ci	 * All structures in the key is multiples of 4 bytes, so use u32.
71362306a36Sopenharmony_ci	 */
71462306a36Sopenharmony_ci	ext_len = (u32 *)ext - (u32 *)nfp_flow->unmasked_data;
71562306a36Sopenharmony_ci	if (ext_len > NFP_FLOWER_KEY_MAX_LW) {
71662306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack,
71762306a36Sopenharmony_ci				   "unsupported offload: flow key too long");
71862306a36Sopenharmony_ci		return -EOPNOTSUPP;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	return 0;
72262306a36Sopenharmony_ci}
723