1e8f887acSAmir Vadai /*
2e8f887acSAmir Vadai  * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3e8f887acSAmir Vadai  *
4e8f887acSAmir Vadai  * This software is available to you under a choice of one of two
5e8f887acSAmir Vadai  * licenses.  You may choose to be licensed under the terms of the GNU
6e8f887acSAmir Vadai  * General Public License (GPL) Version 2, available from the file
7e8f887acSAmir Vadai  * COPYING in the main directory of this source tree, or the
8e8f887acSAmir Vadai  * OpenIB.org BSD license below:
9e8f887acSAmir Vadai  *
10e8f887acSAmir Vadai  *     Redistribution and use in source and binary forms, with or
11e8f887acSAmir Vadai  *     without modification, are permitted provided that the following
12e8f887acSAmir Vadai  *     conditions are met:
13e8f887acSAmir Vadai  *
14e8f887acSAmir Vadai  *      - Redistributions of source code must retain the above
15e8f887acSAmir Vadai  *        copyright notice, this list of conditions and the following
16e8f887acSAmir Vadai  *        disclaimer.
17e8f887acSAmir Vadai  *
18e8f887acSAmir Vadai  *      - Redistributions in binary form must reproduce the above
19e8f887acSAmir Vadai  *        copyright notice, this list of conditions and the following
20e8f887acSAmir Vadai  *        disclaimer in the documentation and/or other materials
21e8f887acSAmir Vadai  *        provided with the distribution.
22e8f887acSAmir Vadai  *
23e8f887acSAmir Vadai  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24e8f887acSAmir Vadai  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25e8f887acSAmir Vadai  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26e8f887acSAmir Vadai  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27e8f887acSAmir Vadai  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28e8f887acSAmir Vadai  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29e8f887acSAmir Vadai  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30e8f887acSAmir Vadai  * SOFTWARE.
31e8f887acSAmir Vadai  */
32e8f887acSAmir Vadai 
33e3a2b7edSAmir Vadai #include <net/flow_dissector.h>
343f7d0eb4SOr Gerlitz #include <net/sch_generic.h>
35e3a2b7edSAmir Vadai #include <net/pkt_cls.h>
36e3a2b7edSAmir Vadai #include <net/tc_act/tc_gact.h>
3712185a9fSAmir Vadai #include <net/tc_act/tc_skbedit.h>
38e8f887acSAmir Vadai #include <linux/mlx5/fs.h>
39e8f887acSAmir Vadai #include <linux/mlx5/device.h>
40e8f887acSAmir Vadai #include <linux/rhashtable.h>
4103a9d11eSOr Gerlitz #include <net/switchdev.h>
4203a9d11eSOr Gerlitz #include <net/tc_act/tc_mirred.h>
43776b12b6SOr Gerlitz #include <net/tc_act/tc_vlan.h>
44bbd00f7eSHadar Hen Zion #include <net/tc_act/tc_tunnel_key.h>
45a54e20b4SHadar Hen Zion #include <net/vxlan.h>
46e8f887acSAmir Vadai #include "en.h"
47e8f887acSAmir Vadai #include "en_tc.h"
4803a9d11eSOr Gerlitz #include "eswitch.h"
49bbd00f7eSHadar Hen Zion #include "vxlan.h"
50e8f887acSAmir Vadai 
513bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr {
523bc4b7bfSOr Gerlitz 	u32 action;
533bc4b7bfSOr Gerlitz 	u32 flow_tag;
543bc4b7bfSOr Gerlitz };
553bc4b7bfSOr Gerlitz 
5665ba8fb7SOr Gerlitz enum {
5765ba8fb7SOr Gerlitz 	MLX5E_TC_FLOW_ESWITCH	= BIT(0),
583bc4b7bfSOr Gerlitz 	MLX5E_TC_FLOW_NIC	= BIT(1),
5965ba8fb7SOr Gerlitz };
6065ba8fb7SOr Gerlitz 
61e8f887acSAmir Vadai struct mlx5e_tc_flow {
62e8f887acSAmir Vadai 	struct rhash_head	node;
63e8f887acSAmir Vadai 	u64			cookie;
6465ba8fb7SOr Gerlitz 	u8			flags;
6574491de9SMark Bloch 	struct mlx5_flow_handle *rule;
66a54e20b4SHadar Hen Zion 	struct list_head	encap; /* flows sharing the same encap */
673bc4b7bfSOr Gerlitz 	union {
68ecf5bb79SOr Gerlitz 		struct mlx5_esw_flow_attr esw_attr[0];
693bc4b7bfSOr Gerlitz 		struct mlx5_nic_flow_attr nic_attr[0];
703bc4b7bfSOr Gerlitz 	};
71e8f887acSAmir Vadai };
72e8f887acSAmir Vadai 
7317091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr {
7417091853SOr Gerlitz 	struct mlx5_flow_spec spec;
7517091853SOr Gerlitz };
7617091853SOr Gerlitz 
77a54e20b4SHadar Hen Zion enum {
78a54e20b4SHadar Hen Zion 	MLX5_HEADER_TYPE_VXLAN = 0x0,
79a54e20b4SHadar Hen Zion 	MLX5_HEADER_TYPE_NVGRE = 0x1,
80a54e20b4SHadar Hen Zion };
81a54e20b4SHadar Hen Zion 
82acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_ENTRIES 1024
83acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_GROUPS 4
84e8f887acSAmir Vadai 
8574491de9SMark Bloch static struct mlx5_flow_handle *
8674491de9SMark Bloch mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
8717091853SOr Gerlitz 		      struct mlx5e_tc_flow_parse_attr *parse_attr,
883bc4b7bfSOr Gerlitz 		      struct mlx5_nic_flow_attr *attr)
89e8f887acSAmir Vadai {
90aad7e08dSAmir Vadai 	struct mlx5_core_dev *dev = priv->mdev;
91aad7e08dSAmir Vadai 	struct mlx5_flow_destination dest = { 0 };
9266958ed9SHadar Hen Zion 	struct mlx5_flow_act flow_act = {
933bc4b7bfSOr Gerlitz 		.action = attr->action,
943bc4b7bfSOr Gerlitz 		.flow_tag = attr->flow_tag,
9566958ed9SHadar Hen Zion 		.encap_id = 0,
9666958ed9SHadar Hen Zion 	};
97aad7e08dSAmir Vadai 	struct mlx5_fc *counter = NULL;
9874491de9SMark Bloch 	struct mlx5_flow_handle *rule;
99e8f887acSAmir Vadai 	bool table_created = false;
100e8f887acSAmir Vadai 
1013bc4b7bfSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
102aad7e08dSAmir Vadai 		dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
103aad7e08dSAmir Vadai 		dest.ft = priv->fs.vlan.ft.t;
1043bc4b7bfSOr Gerlitz 	} else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
105aad7e08dSAmir Vadai 		counter = mlx5_fc_create(dev, true);
106aad7e08dSAmir Vadai 		if (IS_ERR(counter))
107aad7e08dSAmir Vadai 			return ERR_CAST(counter);
108aad7e08dSAmir Vadai 
109aad7e08dSAmir Vadai 		dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
110aad7e08dSAmir Vadai 		dest.counter = counter;
111aad7e08dSAmir Vadai 	}
112aad7e08dSAmir Vadai 
113acff797cSMaor Gottlieb 	if (IS_ERR_OR_NULL(priv->fs.tc.t)) {
114acff797cSMaor Gottlieb 		priv->fs.tc.t =
115acff797cSMaor Gottlieb 			mlx5_create_auto_grouped_flow_table(priv->fs.ns,
116acff797cSMaor Gottlieb 							    MLX5E_TC_PRIO,
117acff797cSMaor Gottlieb 							    MLX5E_TC_TABLE_NUM_ENTRIES,
118acff797cSMaor Gottlieb 							    MLX5E_TC_TABLE_NUM_GROUPS,
119c9f1b073SHadar Hen Zion 							    0, 0);
120acff797cSMaor Gottlieb 		if (IS_ERR(priv->fs.tc.t)) {
121e8f887acSAmir Vadai 			netdev_err(priv->netdev,
122e8f887acSAmir Vadai 				   "Failed to create tc offload table\n");
123aad7e08dSAmir Vadai 			rule = ERR_CAST(priv->fs.tc.t);
124aad7e08dSAmir Vadai 			goto err_create_ft;
125e8f887acSAmir Vadai 		}
126e8f887acSAmir Vadai 
127e8f887acSAmir Vadai 		table_created = true;
128e8f887acSAmir Vadai 	}
129e8f887acSAmir Vadai 
13017091853SOr Gerlitz 	parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
13117091853SOr Gerlitz 	rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
13217091853SOr Gerlitz 				   &flow_act, &dest, 1);
133e8f887acSAmir Vadai 
134aad7e08dSAmir Vadai 	if (IS_ERR(rule))
135aad7e08dSAmir Vadai 		goto err_add_rule;
136aad7e08dSAmir Vadai 
137aad7e08dSAmir Vadai 	return rule;
138aad7e08dSAmir Vadai 
139aad7e08dSAmir Vadai err_add_rule:
140aad7e08dSAmir Vadai 	if (table_created) {
141acff797cSMaor Gottlieb 		mlx5_destroy_flow_table(priv->fs.tc.t);
142acff797cSMaor Gottlieb 		priv->fs.tc.t = NULL;
143e8f887acSAmir Vadai 	}
144aad7e08dSAmir Vadai err_create_ft:
145aad7e08dSAmir Vadai 	mlx5_fc_destroy(dev, counter);
146e8f887acSAmir Vadai 
147e8f887acSAmir Vadai 	return rule;
148e8f887acSAmir Vadai }
149e8f887acSAmir Vadai 
150d85cdccbSOr Gerlitz static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
151d85cdccbSOr Gerlitz 				  struct mlx5e_tc_flow *flow)
152d85cdccbSOr Gerlitz {
153d85cdccbSOr Gerlitz 	struct mlx5_fc *counter = NULL;
154d85cdccbSOr Gerlitz 
155d85cdccbSOr Gerlitz 	if (!IS_ERR(flow->rule)) {
156d85cdccbSOr Gerlitz 		counter = mlx5_flow_rule_counter(flow->rule);
157d85cdccbSOr Gerlitz 		mlx5_del_flow_rules(flow->rule);
158d85cdccbSOr Gerlitz 		mlx5_fc_destroy(priv->mdev, counter);
159d85cdccbSOr Gerlitz 	}
160d85cdccbSOr Gerlitz 
161d85cdccbSOr Gerlitz 	if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) {
162d85cdccbSOr Gerlitz 		mlx5_destroy_flow_table(priv->fs.tc.t);
163d85cdccbSOr Gerlitz 		priv->fs.tc.t = NULL;
164d85cdccbSOr Gerlitz 	}
165d85cdccbSOr Gerlitz }
166d85cdccbSOr Gerlitz 
16774491de9SMark Bloch static struct mlx5_flow_handle *
16874491de9SMark Bloch mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
16917091853SOr Gerlitz 		      struct mlx5e_tc_flow_parse_attr *parse_attr,
170776b12b6SOr Gerlitz 		      struct mlx5_esw_flow_attr *attr)
171adb4c123SOr Gerlitz {
172adb4c123SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
1738b32580dSOr Gerlitz 	int err;
1748b32580dSOr Gerlitz 
1758b32580dSOr Gerlitz 	err = mlx5_eswitch_add_vlan_action(esw, attr);
1768b32580dSOr Gerlitz 	if (err)
1778b32580dSOr Gerlitz 		return ERR_PTR(err);
178adb4c123SOr Gerlitz 
17917091853SOr Gerlitz 	return mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr);
180adb4c123SOr Gerlitz }
181adb4c123SOr Gerlitz 
1825067b602SRoi Dayan static void mlx5e_detach_encap(struct mlx5e_priv *priv,
183d85cdccbSOr Gerlitz 			       struct mlx5e_tc_flow *flow);
184d85cdccbSOr Gerlitz 
185d85cdccbSOr Gerlitz static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
186d85cdccbSOr Gerlitz 				  struct mlx5e_tc_flow *flow)
187d85cdccbSOr Gerlitz {
188d85cdccbSOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
189d85cdccbSOr Gerlitz 
190ecf5bb79SOr Gerlitz 	mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr);
191d85cdccbSOr Gerlitz 
192ecf5bb79SOr Gerlitz 	mlx5_eswitch_del_vlan_action(esw, flow->esw_attr);
193d85cdccbSOr Gerlitz 
194ecf5bb79SOr Gerlitz 	if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
195d85cdccbSOr Gerlitz 		mlx5e_detach_encap(priv, flow);
196d85cdccbSOr Gerlitz }
197d85cdccbSOr Gerlitz 
198d85cdccbSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv,
199d85cdccbSOr Gerlitz 			       struct mlx5e_tc_flow *flow)
200d85cdccbSOr Gerlitz {
2015067b602SRoi Dayan 	struct list_head *next = flow->encap.next;
2025067b602SRoi Dayan 
2035067b602SRoi Dayan 	list_del(&flow->encap);
2045067b602SRoi Dayan 	if (list_empty(next)) {
2055067b602SRoi Dayan 		struct mlx5_encap_entry *e;
2065067b602SRoi Dayan 
2075067b602SRoi Dayan 		e = list_entry(next, struct mlx5_encap_entry, flows);
2085067b602SRoi Dayan 		if (e->n) {
2095067b602SRoi Dayan 			mlx5_encap_dealloc(priv->mdev, e->encap_id);
2105067b602SRoi Dayan 			neigh_release(e->n);
2115067b602SRoi Dayan 		}
2125067b602SRoi Dayan 		hlist_del_rcu(&e->encap_hlist);
2135067b602SRoi Dayan 		kfree(e);
2145067b602SRoi Dayan 	}
2155067b602SRoi Dayan }
2165067b602SRoi Dayan 
2175e86397aSOr Gerlitz /* we get here also when setting rule to the FW failed, etc. It means that the
2185e86397aSOr Gerlitz  * flow rule itself might not exist, but some offloading related to the actions
2195e86397aSOr Gerlitz  * should be cleaned.
2205e86397aSOr Gerlitz  */
221e8f887acSAmir Vadai static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
222961e8979SRoi Dayan 			      struct mlx5e_tc_flow *flow)
223e8f887acSAmir Vadai {
224d85cdccbSOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
225d85cdccbSOr Gerlitz 		mlx5e_tc_del_fdb_flow(priv, flow);
226d85cdccbSOr Gerlitz 	else
227d85cdccbSOr Gerlitz 		mlx5e_tc_del_nic_flow(priv, flow);
228e8f887acSAmir Vadai }
229e8f887acSAmir Vadai 
230bbd00f7eSHadar Hen Zion static void parse_vxlan_attr(struct mlx5_flow_spec *spec,
231bbd00f7eSHadar Hen Zion 			     struct tc_cls_flower_offload *f)
232bbd00f7eSHadar Hen Zion {
233bbd00f7eSHadar Hen Zion 	void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
234bbd00f7eSHadar Hen Zion 				       outer_headers);
235bbd00f7eSHadar Hen Zion 	void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
236bbd00f7eSHadar Hen Zion 				       outer_headers);
237bbd00f7eSHadar Hen Zion 	void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
238bbd00f7eSHadar Hen Zion 				    misc_parameters);
239bbd00f7eSHadar Hen Zion 	void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
240bbd00f7eSHadar Hen Zion 				    misc_parameters);
241bbd00f7eSHadar Hen Zion 
242bbd00f7eSHadar Hen Zion 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
243bbd00f7eSHadar Hen Zion 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
244bbd00f7eSHadar Hen Zion 
245bbd00f7eSHadar Hen Zion 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
246bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_keyid *key =
247bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
248bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_KEYID,
249bbd00f7eSHadar Hen Zion 						  f->key);
250bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_keyid *mask =
251bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
252bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_KEYID,
253bbd00f7eSHadar Hen Zion 						  f->mask);
254bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
255bbd00f7eSHadar Hen Zion 			 be32_to_cpu(mask->keyid));
256bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
257bbd00f7eSHadar Hen Zion 			 be32_to_cpu(key->keyid));
258bbd00f7eSHadar Hen Zion 	}
259bbd00f7eSHadar Hen Zion }
260bbd00f7eSHadar Hen Zion 
261bbd00f7eSHadar Hen Zion static int parse_tunnel_attr(struct mlx5e_priv *priv,
262bbd00f7eSHadar Hen Zion 			     struct mlx5_flow_spec *spec,
263bbd00f7eSHadar Hen Zion 			     struct tc_cls_flower_offload *f)
264bbd00f7eSHadar Hen Zion {
265bbd00f7eSHadar Hen Zion 	void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
266bbd00f7eSHadar Hen Zion 				       outer_headers);
267bbd00f7eSHadar Hen Zion 	void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
268bbd00f7eSHadar Hen Zion 				       outer_headers);
269bbd00f7eSHadar Hen Zion 
2702e72eb43SOr Gerlitz 	struct flow_dissector_key_control *enc_control =
2712e72eb43SOr Gerlitz 		skb_flow_dissector_target(f->dissector,
2722e72eb43SOr Gerlitz 					  FLOW_DISSECTOR_KEY_ENC_CONTROL,
2732e72eb43SOr Gerlitz 					  f->key);
2742e72eb43SOr Gerlitz 
275bbd00f7eSHadar Hen Zion 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
276bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ports *key =
277bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
278bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_PORTS,
279bbd00f7eSHadar Hen Zion 						  f->key);
280bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ports *mask =
281bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
282bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_PORTS,
283bbd00f7eSHadar Hen Zion 						  f->mask);
2841ad9a00aSPaul Blakey 		struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
2851ad9a00aSPaul Blakey 		struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw);
2861ad9a00aSPaul Blakey 		struct mlx5e_priv *up_priv = netdev_priv(up_dev);
287bbd00f7eSHadar Hen Zion 
288bbd00f7eSHadar Hen Zion 		/* Full udp dst port must be given */
289bbd00f7eSHadar Hen Zion 		if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst)))
2902fcd82e9SOr Gerlitz 			goto vxlan_match_offload_err;
291bbd00f7eSHadar Hen Zion 
2921ad9a00aSPaul Blakey 		if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->dst)) &&
293bbd00f7eSHadar Hen Zion 		    MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
294bbd00f7eSHadar Hen Zion 			parse_vxlan_attr(spec, f);
2952fcd82e9SOr Gerlitz 		else {
2962fcd82e9SOr Gerlitz 			netdev_warn(priv->netdev,
2972fcd82e9SOr Gerlitz 				    "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst));
298bbd00f7eSHadar Hen Zion 			return -EOPNOTSUPP;
2992fcd82e9SOr Gerlitz 		}
300bbd00f7eSHadar Hen Zion 
301bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
302bbd00f7eSHadar Hen Zion 			 udp_dport, ntohs(mask->dst));
303bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
304bbd00f7eSHadar Hen Zion 			 udp_dport, ntohs(key->dst));
305bbd00f7eSHadar Hen Zion 
306cd377663SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
307cd377663SOr Gerlitz 			 udp_sport, ntohs(mask->src));
308cd377663SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
309cd377663SOr Gerlitz 			 udp_sport, ntohs(key->src));
310bbd00f7eSHadar Hen Zion 	} else { /* udp dst port must be given */
3112fcd82e9SOr Gerlitz vxlan_match_offload_err:
3122fcd82e9SOr Gerlitz 		netdev_warn(priv->netdev,
3132fcd82e9SOr Gerlitz 			    "IP tunnel decap offload supported only for vxlan, must set UDP dport\n");
314bbd00f7eSHadar Hen Zion 		return -EOPNOTSUPP;
315bbd00f7eSHadar Hen Zion 	}
316bbd00f7eSHadar Hen Zion 
3172e72eb43SOr Gerlitz 	if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
318bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ipv4_addrs *key =
319bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
320bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
321bbd00f7eSHadar Hen Zion 						  f->key);
322bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ipv4_addrs *mask =
323bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
324bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
325bbd00f7eSHadar Hen Zion 						  f->mask);
326bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
327bbd00f7eSHadar Hen Zion 			 src_ipv4_src_ipv6.ipv4_layout.ipv4,
328bbd00f7eSHadar Hen Zion 			 ntohl(mask->src));
329bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
330bbd00f7eSHadar Hen Zion 			 src_ipv4_src_ipv6.ipv4_layout.ipv4,
331bbd00f7eSHadar Hen Zion 			 ntohl(key->src));
332bbd00f7eSHadar Hen Zion 
333bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
334bbd00f7eSHadar Hen Zion 			 dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
335bbd00f7eSHadar Hen Zion 			 ntohl(mask->dst));
336bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
337bbd00f7eSHadar Hen Zion 			 dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
338bbd00f7eSHadar Hen Zion 			 ntohl(key->dst));
339bbd00f7eSHadar Hen Zion 
340bbd00f7eSHadar Hen Zion 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
341bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
34219f44401SOr Gerlitz 	} else if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
34319f44401SOr Gerlitz 		struct flow_dissector_key_ipv6_addrs *key =
34419f44401SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
34519f44401SOr Gerlitz 						  FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
34619f44401SOr Gerlitz 						  f->key);
34719f44401SOr Gerlitz 		struct flow_dissector_key_ipv6_addrs *mask =
34819f44401SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
34919f44401SOr Gerlitz 						  FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
35019f44401SOr Gerlitz 						  f->mask);
35119f44401SOr Gerlitz 
35219f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
35319f44401SOr Gerlitz 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
35419f44401SOr Gerlitz 		       &mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
35519f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
35619f44401SOr Gerlitz 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
35719f44401SOr Gerlitz 		       &key->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
35819f44401SOr Gerlitz 
35919f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
36019f44401SOr Gerlitz 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
36119f44401SOr Gerlitz 		       &mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
36219f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
36319f44401SOr Gerlitz 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
36419f44401SOr Gerlitz 		       &key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
36519f44401SOr Gerlitz 
36619f44401SOr Gerlitz 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
36719f44401SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6);
3682e72eb43SOr Gerlitz 	}
369bbd00f7eSHadar Hen Zion 
370bbd00f7eSHadar Hen Zion 	/* Enforce DMAC when offloading incoming tunneled flows.
371bbd00f7eSHadar Hen Zion 	 * Flow counters require a match on the DMAC.
372bbd00f7eSHadar Hen Zion 	 */
373bbd00f7eSHadar Hen Zion 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_47_16);
374bbd00f7eSHadar Hen Zion 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_15_0);
375bbd00f7eSHadar Hen Zion 	ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
376bbd00f7eSHadar Hen Zion 				     dmac_47_16), priv->netdev->dev_addr);
377bbd00f7eSHadar Hen Zion 
378bbd00f7eSHadar Hen Zion 	/* let software handle IP fragments */
379bbd00f7eSHadar Hen Zion 	MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1);
380bbd00f7eSHadar Hen Zion 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 0);
381bbd00f7eSHadar Hen Zion 
382bbd00f7eSHadar Hen Zion 	return 0;
383bbd00f7eSHadar Hen Zion }
384bbd00f7eSHadar Hen Zion 
385de0af0bfSRoi Dayan static int __parse_cls_flower(struct mlx5e_priv *priv,
386de0af0bfSRoi Dayan 			      struct mlx5_flow_spec *spec,
387de0af0bfSRoi Dayan 			      struct tc_cls_flower_offload *f,
388de0af0bfSRoi Dayan 			      u8 *min_inline)
389e3a2b7edSAmir Vadai {
390c5bb1730SMaor Gottlieb 	void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
391c5bb1730SMaor Gottlieb 				       outer_headers);
392c5bb1730SMaor Gottlieb 	void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
393c5bb1730SMaor Gottlieb 				       outer_headers);
394e3a2b7edSAmir Vadai 	u16 addr_type = 0;
395e3a2b7edSAmir Vadai 	u8 ip_proto = 0;
396e3a2b7edSAmir Vadai 
397de0af0bfSRoi Dayan 	*min_inline = MLX5_INLINE_MODE_L2;
398de0af0bfSRoi Dayan 
399e3a2b7edSAmir Vadai 	if (f->dissector->used_keys &
400e3a2b7edSAmir Vadai 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
401e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
402e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
403095b6cfdSOr Gerlitz 	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
404e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
405e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
406bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
407bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
408bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
409bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
410bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_PORTS)	|
411bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL))) {
412e3a2b7edSAmir Vadai 		netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
413e3a2b7edSAmir Vadai 			    f->dissector->used_keys);
414e3a2b7edSAmir Vadai 		return -EOPNOTSUPP;
415e3a2b7edSAmir Vadai 	}
416e3a2b7edSAmir Vadai 
417bbd00f7eSHadar Hen Zion 	if ((dissector_uses_key(f->dissector,
418bbd00f7eSHadar Hen Zion 				FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) ||
419bbd00f7eSHadar Hen Zion 	     dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID) ||
420bbd00f7eSHadar Hen Zion 	     dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) &&
421bbd00f7eSHadar Hen Zion 	    dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
422bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_control *key =
423bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
424bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_CONTROL,
425bbd00f7eSHadar Hen Zion 						  f->key);
426bbd00f7eSHadar Hen Zion 		switch (key->addr_type) {
427bbd00f7eSHadar Hen Zion 		case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
42819f44401SOr Gerlitz 		case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
429bbd00f7eSHadar Hen Zion 			if (parse_tunnel_attr(priv, spec, f))
430bbd00f7eSHadar Hen Zion 				return -EOPNOTSUPP;
431bbd00f7eSHadar Hen Zion 			break;
432bbd00f7eSHadar Hen Zion 		default:
433bbd00f7eSHadar Hen Zion 			return -EOPNOTSUPP;
434bbd00f7eSHadar Hen Zion 		}
435bbd00f7eSHadar Hen Zion 
436bbd00f7eSHadar Hen Zion 		/* In decap flow, header pointers should point to the inner
437bbd00f7eSHadar Hen Zion 		 * headers, outer header were already set by parse_tunnel_attr
438bbd00f7eSHadar Hen Zion 		 */
439bbd00f7eSHadar Hen Zion 		headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
440bbd00f7eSHadar Hen Zion 					 inner_headers);
441bbd00f7eSHadar Hen Zion 		headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
442bbd00f7eSHadar Hen Zion 					 inner_headers);
443bbd00f7eSHadar Hen Zion 	}
444bbd00f7eSHadar Hen Zion 
445e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
446e3a2b7edSAmir Vadai 		struct flow_dissector_key_control *key =
447e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
4481dbd0d37SHadar Hen Zion 						  FLOW_DISSECTOR_KEY_CONTROL,
449e3a2b7edSAmir Vadai 						  f->key);
4503f7d0eb4SOr Gerlitz 
4513f7d0eb4SOr Gerlitz 		struct flow_dissector_key_control *mask =
4523f7d0eb4SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
4533f7d0eb4SOr Gerlitz 						  FLOW_DISSECTOR_KEY_CONTROL,
4543f7d0eb4SOr Gerlitz 						  f->mask);
455e3a2b7edSAmir Vadai 		addr_type = key->addr_type;
4563f7d0eb4SOr Gerlitz 
4573f7d0eb4SOr Gerlitz 		if (mask->flags & FLOW_DIS_IS_FRAGMENT) {
4583f7d0eb4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1);
4593f7d0eb4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
4603f7d0eb4SOr Gerlitz 				 key->flags & FLOW_DIS_IS_FRAGMENT);
4610827444dSOr Gerlitz 
4620827444dSOr Gerlitz 			/* the HW doesn't need L3 inline to match on frag=no */
4630827444dSOr Gerlitz 			if (key->flags & FLOW_DIS_IS_FRAGMENT)
4640827444dSOr Gerlitz 				*min_inline = MLX5_INLINE_MODE_IP;
4653f7d0eb4SOr Gerlitz 		}
466e3a2b7edSAmir Vadai 	}
467e3a2b7edSAmir Vadai 
468e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
469e3a2b7edSAmir Vadai 		struct flow_dissector_key_basic *key =
470e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
471e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_BASIC,
472e3a2b7edSAmir Vadai 						  f->key);
473e3a2b7edSAmir Vadai 		struct flow_dissector_key_basic *mask =
474e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
475e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_BASIC,
476e3a2b7edSAmir Vadai 						  f->mask);
477e3a2b7edSAmir Vadai 		ip_proto = key->ip_proto;
478e3a2b7edSAmir Vadai 
479e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype,
480e3a2b7edSAmir Vadai 			 ntohs(mask->n_proto));
481e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
482e3a2b7edSAmir Vadai 			 ntohs(key->n_proto));
483e3a2b7edSAmir Vadai 
484e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol,
485e3a2b7edSAmir Vadai 			 mask->ip_proto);
486e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
487e3a2b7edSAmir Vadai 			 key->ip_proto);
488de0af0bfSRoi Dayan 
489de0af0bfSRoi Dayan 		if (mask->ip_proto)
490de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_IP;
491e3a2b7edSAmir Vadai 	}
492e3a2b7edSAmir Vadai 
493e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
494e3a2b7edSAmir Vadai 		struct flow_dissector_key_eth_addrs *key =
495e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
496e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
497e3a2b7edSAmir Vadai 						  f->key);
498e3a2b7edSAmir Vadai 		struct flow_dissector_key_eth_addrs *mask =
499e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
500e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
501e3a2b7edSAmir Vadai 						  f->mask);
502e3a2b7edSAmir Vadai 
503e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
504e3a2b7edSAmir Vadai 					     dmac_47_16),
505e3a2b7edSAmir Vadai 				mask->dst);
506e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
507e3a2b7edSAmir Vadai 					     dmac_47_16),
508e3a2b7edSAmir Vadai 				key->dst);
509e3a2b7edSAmir Vadai 
510e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
511e3a2b7edSAmir Vadai 					     smac_47_16),
512e3a2b7edSAmir Vadai 				mask->src);
513e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
514e3a2b7edSAmir Vadai 					     smac_47_16),
515e3a2b7edSAmir Vadai 				key->src);
516e3a2b7edSAmir Vadai 	}
517e3a2b7edSAmir Vadai 
518095b6cfdSOr Gerlitz 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
519095b6cfdSOr Gerlitz 		struct flow_dissector_key_vlan *key =
520095b6cfdSOr Gerlitz 			skb_flow_dissector_target(f->dissector,
521095b6cfdSOr Gerlitz 						  FLOW_DISSECTOR_KEY_VLAN,
522095b6cfdSOr Gerlitz 						  f->key);
523095b6cfdSOr Gerlitz 		struct flow_dissector_key_vlan *mask =
524095b6cfdSOr Gerlitz 			skb_flow_dissector_target(f->dissector,
525095b6cfdSOr Gerlitz 						  FLOW_DISSECTOR_KEY_VLAN,
526095b6cfdSOr Gerlitz 						  f->mask);
527358d79a4SOr Gerlitz 		if (mask->vlan_id || mask->vlan_priority) {
52810543365SMohamad Haj Yahia 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1);
52910543365SMohamad Haj Yahia 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1);
530095b6cfdSOr Gerlitz 
531095b6cfdSOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id);
532095b6cfdSOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id);
533358d79a4SOr Gerlitz 
534358d79a4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, mask->vlan_priority);
535358d79a4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, key->vlan_priority);
536095b6cfdSOr Gerlitz 		}
537095b6cfdSOr Gerlitz 	}
538095b6cfdSOr Gerlitz 
539e3a2b7edSAmir Vadai 	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
540e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv4_addrs *key =
541e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
542e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
543e3a2b7edSAmir Vadai 						  f->key);
544e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv4_addrs *mask =
545e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
546e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
547e3a2b7edSAmir Vadai 						  f->mask);
548e3a2b7edSAmir Vadai 
549e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
550e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv4_layout.ipv4),
551e3a2b7edSAmir Vadai 		       &mask->src, sizeof(mask->src));
552e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
553e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv4_layout.ipv4),
554e3a2b7edSAmir Vadai 		       &key->src, sizeof(key->src));
555e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
556e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
557e3a2b7edSAmir Vadai 		       &mask->dst, sizeof(mask->dst));
558e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
559e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
560e3a2b7edSAmir Vadai 		       &key->dst, sizeof(key->dst));
561de0af0bfSRoi Dayan 
562de0af0bfSRoi Dayan 		if (mask->src || mask->dst)
563de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_IP;
564e3a2b7edSAmir Vadai 	}
565e3a2b7edSAmir Vadai 
566e3a2b7edSAmir Vadai 	if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
567e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv6_addrs *key =
568e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
569e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
570e3a2b7edSAmir Vadai 						  f->key);
571e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv6_addrs *mask =
572e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
573e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
574e3a2b7edSAmir Vadai 						  f->mask);
575e3a2b7edSAmir Vadai 
576e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
577e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
578e3a2b7edSAmir Vadai 		       &mask->src, sizeof(mask->src));
579e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
580e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
581e3a2b7edSAmir Vadai 		       &key->src, sizeof(key->src));
582e3a2b7edSAmir Vadai 
583e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
584e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
585e3a2b7edSAmir Vadai 		       &mask->dst, sizeof(mask->dst));
586e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
587e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
588e3a2b7edSAmir Vadai 		       &key->dst, sizeof(key->dst));
589de0af0bfSRoi Dayan 
590de0af0bfSRoi Dayan 		if (ipv6_addr_type(&mask->src) != IPV6_ADDR_ANY ||
591de0af0bfSRoi Dayan 		    ipv6_addr_type(&mask->dst) != IPV6_ADDR_ANY)
592de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_IP;
593e3a2b7edSAmir Vadai 	}
594e3a2b7edSAmir Vadai 
595e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
596e3a2b7edSAmir Vadai 		struct flow_dissector_key_ports *key =
597e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
598e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_PORTS,
599e3a2b7edSAmir Vadai 						  f->key);
600e3a2b7edSAmir Vadai 		struct flow_dissector_key_ports *mask =
601e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
602e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_PORTS,
603e3a2b7edSAmir Vadai 						  f->mask);
604e3a2b7edSAmir Vadai 		switch (ip_proto) {
605e3a2b7edSAmir Vadai 		case IPPROTO_TCP:
606e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
607e3a2b7edSAmir Vadai 				 tcp_sport, ntohs(mask->src));
608e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
609e3a2b7edSAmir Vadai 				 tcp_sport, ntohs(key->src));
610e3a2b7edSAmir Vadai 
611e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
612e3a2b7edSAmir Vadai 				 tcp_dport, ntohs(mask->dst));
613e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
614e3a2b7edSAmir Vadai 				 tcp_dport, ntohs(key->dst));
615e3a2b7edSAmir Vadai 			break;
616e3a2b7edSAmir Vadai 
617e3a2b7edSAmir Vadai 		case IPPROTO_UDP:
618e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
619e3a2b7edSAmir Vadai 				 udp_sport, ntohs(mask->src));
620e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
621e3a2b7edSAmir Vadai 				 udp_sport, ntohs(key->src));
622e3a2b7edSAmir Vadai 
623e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
624e3a2b7edSAmir Vadai 				 udp_dport, ntohs(mask->dst));
625e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
626e3a2b7edSAmir Vadai 				 udp_dport, ntohs(key->dst));
627e3a2b7edSAmir Vadai 			break;
628e3a2b7edSAmir Vadai 		default:
629e3a2b7edSAmir Vadai 			netdev_err(priv->netdev,
630e3a2b7edSAmir Vadai 				   "Only UDP and TCP transport are supported\n");
631e3a2b7edSAmir Vadai 			return -EINVAL;
632e3a2b7edSAmir Vadai 		}
633de0af0bfSRoi Dayan 
634de0af0bfSRoi Dayan 		if (mask->src || mask->dst)
635de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_TCP_UDP;
636e3a2b7edSAmir Vadai 	}
637e3a2b7edSAmir Vadai 
638e3a2b7edSAmir Vadai 	return 0;
639e3a2b7edSAmir Vadai }
640e3a2b7edSAmir Vadai 
641de0af0bfSRoi Dayan static int parse_cls_flower(struct mlx5e_priv *priv,
64265ba8fb7SOr Gerlitz 			    struct mlx5e_tc_flow *flow,
643de0af0bfSRoi Dayan 			    struct mlx5_flow_spec *spec,
644de0af0bfSRoi Dayan 			    struct tc_cls_flower_offload *f)
645de0af0bfSRoi Dayan {
646de0af0bfSRoi Dayan 	struct mlx5_core_dev *dev = priv->mdev;
647de0af0bfSRoi Dayan 	struct mlx5_eswitch *esw = dev->priv.eswitch;
648de0af0bfSRoi Dayan 	struct mlx5_eswitch_rep *rep = priv->ppriv;
649de0af0bfSRoi Dayan 	u8 min_inline;
650de0af0bfSRoi Dayan 	int err;
651de0af0bfSRoi Dayan 
652de0af0bfSRoi Dayan 	err = __parse_cls_flower(priv, spec, f, &min_inline);
653de0af0bfSRoi Dayan 
65465ba8fb7SOr Gerlitz 	if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH) &&
655de0af0bfSRoi Dayan 	    rep->vport != FDB_UPLINK_VPORT) {
656de0af0bfSRoi Dayan 		if (min_inline > esw->offloads.inline_mode) {
657de0af0bfSRoi Dayan 			netdev_warn(priv->netdev,
658de0af0bfSRoi Dayan 				    "Flow is not offloaded due to min inline setting, required %d actual %d\n",
659de0af0bfSRoi Dayan 				    min_inline, esw->offloads.inline_mode);
660de0af0bfSRoi Dayan 			return -EOPNOTSUPP;
661de0af0bfSRoi Dayan 		}
662de0af0bfSRoi Dayan 	}
663de0af0bfSRoi Dayan 
664de0af0bfSRoi Dayan 	return err;
665de0af0bfSRoi Dayan }
666de0af0bfSRoi Dayan 
6675c40348cSOr Gerlitz static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
6683bc4b7bfSOr Gerlitz 				struct mlx5_nic_flow_attr *attr)
669e3a2b7edSAmir Vadai {
670e3a2b7edSAmir Vadai 	const struct tc_action *a;
67122dc13c8SWANG Cong 	LIST_HEAD(actions);
672e3a2b7edSAmir Vadai 
673e3a2b7edSAmir Vadai 	if (tc_no_actions(exts))
674e3a2b7edSAmir Vadai 		return -EINVAL;
675e3a2b7edSAmir Vadai 
6763bc4b7bfSOr Gerlitz 	attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
6773bc4b7bfSOr Gerlitz 	attr->action = 0;
678e3a2b7edSAmir Vadai 
67922dc13c8SWANG Cong 	tcf_exts_to_list(exts, &actions);
68022dc13c8SWANG Cong 	list_for_each_entry(a, &actions, list) {
681e3a2b7edSAmir Vadai 		/* Only support a single action per rule */
6823bc4b7bfSOr Gerlitz 		if (attr->action)
683e3a2b7edSAmir Vadai 			return -EINVAL;
684e3a2b7edSAmir Vadai 
685e3a2b7edSAmir Vadai 		if (is_tcf_gact_shot(a)) {
6863bc4b7bfSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
687aad7e08dSAmir Vadai 			if (MLX5_CAP_FLOWTABLE(priv->mdev,
688aad7e08dSAmir Vadai 					       flow_table_properties_nic_receive.flow_counter))
6893bc4b7bfSOr Gerlitz 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
690e3a2b7edSAmir Vadai 			continue;
691e3a2b7edSAmir Vadai 		}
692e3a2b7edSAmir Vadai 
693e3a2b7edSAmir Vadai 		if (is_tcf_skbedit_mark(a)) {
694e3a2b7edSAmir Vadai 			u32 mark = tcf_skbedit_mark(a);
695e3a2b7edSAmir Vadai 
696e3a2b7edSAmir Vadai 			if (mark & ~MLX5E_TC_FLOW_ID_MASK) {
697e3a2b7edSAmir Vadai 				netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n",
698e3a2b7edSAmir Vadai 					    mark);
699e3a2b7edSAmir Vadai 				return -EINVAL;
700e3a2b7edSAmir Vadai 			}
701e3a2b7edSAmir Vadai 
7023bc4b7bfSOr Gerlitz 			attr->flow_tag = mark;
7033bc4b7bfSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
704e3a2b7edSAmir Vadai 			continue;
705e3a2b7edSAmir Vadai 		}
706e3a2b7edSAmir Vadai 
707e3a2b7edSAmir Vadai 		return -EINVAL;
708e3a2b7edSAmir Vadai 	}
709e3a2b7edSAmir Vadai 
710e3a2b7edSAmir Vadai 	return 0;
711e3a2b7edSAmir Vadai }
712e3a2b7edSAmir Vadai 
71376f7444dSOr Gerlitz static inline int cmp_encap_info(struct ip_tunnel_key *a,
71476f7444dSOr Gerlitz 				 struct ip_tunnel_key *b)
715a54e20b4SHadar Hen Zion {
716a54e20b4SHadar Hen Zion 	return memcmp(a, b, sizeof(*a));
717a54e20b4SHadar Hen Zion }
718a54e20b4SHadar Hen Zion 
71976f7444dSOr Gerlitz static inline int hash_encap_info(struct ip_tunnel_key *key)
720a54e20b4SHadar Hen Zion {
72176f7444dSOr Gerlitz 	return jhash(key, sizeof(*key), 0);
722a54e20b4SHadar Hen Zion }
723a54e20b4SHadar Hen Zion 
724a54e20b4SHadar Hen Zion static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
725a54e20b4SHadar Hen Zion 				   struct net_device *mirred_dev,
726a54e20b4SHadar Hen Zion 				   struct net_device **out_dev,
727a54e20b4SHadar Hen Zion 				   struct flowi4 *fl4,
728a54e20b4SHadar Hen Zion 				   struct neighbour **out_n,
729a54e20b4SHadar Hen Zion 				   int *out_ttl)
730a54e20b4SHadar Hen Zion {
7313e621b19SHadar Hen Zion 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
732a54e20b4SHadar Hen Zion 	struct rtable *rt;
733a54e20b4SHadar Hen Zion 	struct neighbour *n = NULL;
734a54e20b4SHadar Hen Zion 
735a54e20b4SHadar Hen Zion #if IS_ENABLED(CONFIG_INET)
736abeffce9SArnd Bergmann 	int ret;
737abeffce9SArnd Bergmann 
738a54e20b4SHadar Hen Zion 	rt = ip_route_output_key(dev_net(mirred_dev), fl4);
739abeffce9SArnd Bergmann 	ret = PTR_ERR_OR_ZERO(rt);
740abeffce9SArnd Bergmann 	if (ret)
741abeffce9SArnd Bergmann 		return ret;
742a54e20b4SHadar Hen Zion #else
743a54e20b4SHadar Hen Zion 	return -EOPNOTSUPP;
744a54e20b4SHadar Hen Zion #endif
7453e621b19SHadar Hen Zion 	/* if the egress device isn't on the same HW e-switch, we use the uplink */
7463e621b19SHadar Hen Zion 	if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev))
7473e621b19SHadar Hen Zion 		*out_dev = mlx5_eswitch_get_uplink_netdev(esw);
7483e621b19SHadar Hen Zion 	else
7493e621b19SHadar Hen Zion 		*out_dev = rt->dst.dev;
750a54e20b4SHadar Hen Zion 
75175c33da8SOr Gerlitz 	*out_ttl = ip4_dst_hoplimit(&rt->dst);
752a54e20b4SHadar Hen Zion 	n = dst_neigh_lookup(&rt->dst, &fl4->daddr);
753a54e20b4SHadar Hen Zion 	ip_rt_put(rt);
754a54e20b4SHadar Hen Zion 	if (!n)
755a54e20b4SHadar Hen Zion 		return -ENOMEM;
756a54e20b4SHadar Hen Zion 
757a54e20b4SHadar Hen Zion 	*out_n = n;
758a54e20b4SHadar Hen Zion 	return 0;
759a54e20b4SHadar Hen Zion }
760a54e20b4SHadar Hen Zion 
761ce99f6b9SOr Gerlitz static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
762ce99f6b9SOr Gerlitz 				   struct net_device *mirred_dev,
763ce99f6b9SOr Gerlitz 				   struct net_device **out_dev,
764ce99f6b9SOr Gerlitz 				   struct flowi6 *fl6,
765ce99f6b9SOr Gerlitz 				   struct neighbour **out_n,
766ce99f6b9SOr Gerlitz 				   int *out_ttl)
767ce99f6b9SOr Gerlitz {
768ce99f6b9SOr Gerlitz 	struct neighbour *n = NULL;
769ce99f6b9SOr Gerlitz 	struct dst_entry *dst;
770ce99f6b9SOr Gerlitz 
771ce99f6b9SOr Gerlitz #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
772ce99f6b9SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
773ce99f6b9SOr Gerlitz 	int ret;
774ce99f6b9SOr Gerlitz 
775ce99f6b9SOr Gerlitz 	dst = ip6_route_output(dev_net(mirred_dev), NULL, fl6);
776ce99f6b9SOr Gerlitz 	ret = dst->error;
777321fa4ffSArnd Bergmann 	if (ret) {
778ce99f6b9SOr Gerlitz 		dst_release(dst);
779ce99f6b9SOr Gerlitz 		return ret;
780ce99f6b9SOr Gerlitz 	}
781ce99f6b9SOr Gerlitz 
782ce99f6b9SOr Gerlitz 	*out_ttl = ip6_dst_hoplimit(dst);
783ce99f6b9SOr Gerlitz 
784ce99f6b9SOr Gerlitz 	/* if the egress device isn't on the same HW e-switch, we use the uplink */
785ce99f6b9SOr Gerlitz 	if (!switchdev_port_same_parent_id(priv->netdev, dst->dev))
786ce99f6b9SOr Gerlitz 		*out_dev = mlx5_eswitch_get_uplink_netdev(esw);
787ce99f6b9SOr Gerlitz 	else
788ce99f6b9SOr Gerlitz 		*out_dev = dst->dev;
789ce99f6b9SOr Gerlitz #else
790ce99f6b9SOr Gerlitz 	return -EOPNOTSUPP;
791ce99f6b9SOr Gerlitz #endif
792ce99f6b9SOr Gerlitz 
793ce99f6b9SOr Gerlitz 	n = dst_neigh_lookup(dst, &fl6->daddr);
794ce99f6b9SOr Gerlitz 	dst_release(dst);
795ce99f6b9SOr Gerlitz 	if (!n)
796ce99f6b9SOr Gerlitz 		return -ENOMEM;
797ce99f6b9SOr Gerlitz 
798ce99f6b9SOr Gerlitz 	*out_n = n;
799ce99f6b9SOr Gerlitz 	return 0;
800ce99f6b9SOr Gerlitz }
801ce99f6b9SOr Gerlitz 
802a54e20b4SHadar Hen Zion static int gen_vxlan_header_ipv4(struct net_device *out_dev,
803a54e20b4SHadar Hen Zion 				 char buf[],
804a54e20b4SHadar Hen Zion 				 unsigned char h_dest[ETH_ALEN],
805a54e20b4SHadar Hen Zion 				 int ttl,
806a54e20b4SHadar Hen Zion 				 __be32 daddr,
807a54e20b4SHadar Hen Zion 				 __be32 saddr,
808a54e20b4SHadar Hen Zion 				 __be16 udp_dst_port,
809a54e20b4SHadar Hen Zion 				 __be32 vx_vni)
810a54e20b4SHadar Hen Zion {
811a54e20b4SHadar Hen Zion 	int encap_size = VXLAN_HLEN + sizeof(struct iphdr) + ETH_HLEN;
812a54e20b4SHadar Hen Zion 	struct ethhdr *eth = (struct ethhdr *)buf;
813a54e20b4SHadar Hen Zion 	struct iphdr  *ip = (struct iphdr *)((char *)eth + sizeof(struct ethhdr));
814a54e20b4SHadar Hen Zion 	struct udphdr *udp = (struct udphdr *)((char *)ip + sizeof(struct iphdr));
815a54e20b4SHadar Hen Zion 	struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
816a54e20b4SHadar Hen Zion 
817a54e20b4SHadar Hen Zion 	memset(buf, 0, encap_size);
818a54e20b4SHadar Hen Zion 
819a54e20b4SHadar Hen Zion 	ether_addr_copy(eth->h_dest, h_dest);
820a54e20b4SHadar Hen Zion 	ether_addr_copy(eth->h_source, out_dev->dev_addr);
821a54e20b4SHadar Hen Zion 	eth->h_proto = htons(ETH_P_IP);
822a54e20b4SHadar Hen Zion 
823a54e20b4SHadar Hen Zion 	ip->daddr = daddr;
824a54e20b4SHadar Hen Zion 	ip->saddr = saddr;
825a54e20b4SHadar Hen Zion 
826a54e20b4SHadar Hen Zion 	ip->ttl = ttl;
827a54e20b4SHadar Hen Zion 	ip->protocol = IPPROTO_UDP;
828a54e20b4SHadar Hen Zion 	ip->version = 0x4;
829a54e20b4SHadar Hen Zion 	ip->ihl = 0x5;
830a54e20b4SHadar Hen Zion 
831a54e20b4SHadar Hen Zion 	udp->dest = udp_dst_port;
832a54e20b4SHadar Hen Zion 	vxh->vx_flags = VXLAN_HF_VNI;
833a54e20b4SHadar Hen Zion 	vxh->vx_vni = vxlan_vni_field(vx_vni);
834a54e20b4SHadar Hen Zion 
835a54e20b4SHadar Hen Zion 	return encap_size;
836a54e20b4SHadar Hen Zion }
837a54e20b4SHadar Hen Zion 
838ce99f6b9SOr Gerlitz static int gen_vxlan_header_ipv6(struct net_device *out_dev,
839ce99f6b9SOr Gerlitz 				 char buf[],
840ce99f6b9SOr Gerlitz 				 unsigned char h_dest[ETH_ALEN],
841ce99f6b9SOr Gerlitz 				 int ttl,
842ce99f6b9SOr Gerlitz 				 struct in6_addr *daddr,
843ce99f6b9SOr Gerlitz 				 struct in6_addr *saddr,
844ce99f6b9SOr Gerlitz 				 __be16 udp_dst_port,
845ce99f6b9SOr Gerlitz 				 __be32 vx_vni)
846ce99f6b9SOr Gerlitz {
847ce99f6b9SOr Gerlitz 	int encap_size = VXLAN_HLEN + sizeof(struct ipv6hdr) + ETH_HLEN;
848ce99f6b9SOr Gerlitz 	struct ethhdr *eth = (struct ethhdr *)buf;
849ce99f6b9SOr Gerlitz 	struct ipv6hdr *ip6h = (struct ipv6hdr *)((char *)eth + sizeof(struct ethhdr));
850ce99f6b9SOr Gerlitz 	struct udphdr *udp = (struct udphdr *)((char *)ip6h + sizeof(struct ipv6hdr));
851ce99f6b9SOr Gerlitz 	struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
852ce99f6b9SOr Gerlitz 
853ce99f6b9SOr Gerlitz 	memset(buf, 0, encap_size);
854ce99f6b9SOr Gerlitz 
855ce99f6b9SOr Gerlitz 	ether_addr_copy(eth->h_dest, h_dest);
856ce99f6b9SOr Gerlitz 	ether_addr_copy(eth->h_source, out_dev->dev_addr);
857ce99f6b9SOr Gerlitz 	eth->h_proto = htons(ETH_P_IPV6);
858ce99f6b9SOr Gerlitz 
859ce99f6b9SOr Gerlitz 	ip6_flow_hdr(ip6h, 0, 0);
860ce99f6b9SOr Gerlitz 	/* the HW fills up ipv6 payload len */
861ce99f6b9SOr Gerlitz 	ip6h->nexthdr     = IPPROTO_UDP;
862ce99f6b9SOr Gerlitz 	ip6h->hop_limit   = ttl;
863ce99f6b9SOr Gerlitz 	ip6h->daddr	  = *daddr;
864ce99f6b9SOr Gerlitz 	ip6h->saddr	  = *saddr;
865ce99f6b9SOr Gerlitz 
866ce99f6b9SOr Gerlitz 	udp->dest = udp_dst_port;
867ce99f6b9SOr Gerlitz 	vxh->vx_flags = VXLAN_HF_VNI;
868ce99f6b9SOr Gerlitz 	vxh->vx_vni = vxlan_vni_field(vx_vni);
869ce99f6b9SOr Gerlitz 
870ce99f6b9SOr Gerlitz 	return encap_size;
871ce99f6b9SOr Gerlitz }
872ce99f6b9SOr Gerlitz 
873a54e20b4SHadar Hen Zion static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
874a54e20b4SHadar Hen Zion 					  struct net_device *mirred_dev,
875a54e20b4SHadar Hen Zion 					  struct mlx5_encap_entry *e,
876a54e20b4SHadar Hen Zion 					  struct net_device **out_dev)
877a54e20b4SHadar Hen Zion {
878a54e20b4SHadar Hen Zion 	int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
87976f7444dSOr Gerlitz 	struct ip_tunnel_key *tun_key = &e->tun_info.key;
8809a941117SOr Gerlitz 	int encap_size, ttl, err;
881a42485ebSOr Gerlitz 	struct neighbour *n = NULL;
882a54e20b4SHadar Hen Zion 	struct flowi4 fl4 = {};
883a54e20b4SHadar Hen Zion 	char *encap_header;
884a54e20b4SHadar Hen Zion 
885a54e20b4SHadar Hen Zion 	encap_header = kzalloc(max_encap_size, GFP_KERNEL);
886a54e20b4SHadar Hen Zion 	if (!encap_header)
887a54e20b4SHadar Hen Zion 		return -ENOMEM;
888a54e20b4SHadar Hen Zion 
889a54e20b4SHadar Hen Zion 	switch (e->tunnel_type) {
890a54e20b4SHadar Hen Zion 	case MLX5_HEADER_TYPE_VXLAN:
891a54e20b4SHadar Hen Zion 		fl4.flowi4_proto = IPPROTO_UDP;
89276f7444dSOr Gerlitz 		fl4.fl4_dport = tun_key->tp_dst;
893a54e20b4SHadar Hen Zion 		break;
894a54e20b4SHadar Hen Zion 	default:
895a54e20b4SHadar Hen Zion 		err = -EOPNOTSUPP;
896a54e20b4SHadar Hen Zion 		goto out;
897a54e20b4SHadar Hen Zion 	}
8989a941117SOr Gerlitz 	fl4.flowi4_tos = tun_key->tos;
89976f7444dSOr Gerlitz 	fl4.daddr = tun_key->u.ipv4.dst;
9009a941117SOr Gerlitz 	fl4.saddr = tun_key->u.ipv4.src;
901a54e20b4SHadar Hen Zion 
902a54e20b4SHadar Hen Zion 	err = mlx5e_route_lookup_ipv4(priv, mirred_dev, out_dev,
9039a941117SOr Gerlitz 				      &fl4, &n, &ttl);
904a54e20b4SHadar Hen Zion 	if (err)
905a54e20b4SHadar Hen Zion 		goto out;
906a54e20b4SHadar Hen Zion 
907a54e20b4SHadar Hen Zion 	if (!(n->nud_state & NUD_VALID)) {
908a42485ebSOr Gerlitz 		pr_warn("%s: can't offload, neighbour to %pI4 invalid\n", __func__, &fl4.daddr);
909a42485ebSOr Gerlitz 		err = -EOPNOTSUPP;
910a54e20b4SHadar Hen Zion 		goto out;
911a54e20b4SHadar Hen Zion 	}
912a54e20b4SHadar Hen Zion 
91375c33da8SOr Gerlitz 	e->n = n;
91475c33da8SOr Gerlitz 	e->out_dev = *out_dev;
91575c33da8SOr Gerlitz 
916a54e20b4SHadar Hen Zion 	neigh_ha_snapshot(e->h_dest, n, *out_dev);
917a54e20b4SHadar Hen Zion 
918a54e20b4SHadar Hen Zion 	switch (e->tunnel_type) {
919a54e20b4SHadar Hen Zion 	case MLX5_HEADER_TYPE_VXLAN:
920a54e20b4SHadar Hen Zion 		encap_size = gen_vxlan_header_ipv4(*out_dev, encap_header,
921a54e20b4SHadar Hen Zion 						   e->h_dest, ttl,
9229a941117SOr Gerlitz 						   fl4.daddr,
9239a941117SOr Gerlitz 						   fl4.saddr, tun_key->tp_dst,
92476f7444dSOr Gerlitz 						   tunnel_id_to_key32(tun_key->tun_id));
925a54e20b4SHadar Hen Zion 		break;
926a54e20b4SHadar Hen Zion 	default:
927a54e20b4SHadar Hen Zion 		err = -EOPNOTSUPP;
928a54e20b4SHadar Hen Zion 		goto out;
929a54e20b4SHadar Hen Zion 	}
930a54e20b4SHadar Hen Zion 
931a54e20b4SHadar Hen Zion 	err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
932a54e20b4SHadar Hen Zion 			       encap_size, encap_header, &e->encap_id);
933a54e20b4SHadar Hen Zion out:
934a42485ebSOr Gerlitz 	if (err && n)
935a42485ebSOr Gerlitz 		neigh_release(n);
936a54e20b4SHadar Hen Zion 	kfree(encap_header);
937a54e20b4SHadar Hen Zion 	return err;
938a54e20b4SHadar Hen Zion }
939a54e20b4SHadar Hen Zion 
940ce99f6b9SOr Gerlitz static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
941ce99f6b9SOr Gerlitz 					  struct net_device *mirred_dev,
942ce99f6b9SOr Gerlitz 					  struct mlx5_encap_entry *e,
943ce99f6b9SOr Gerlitz 					  struct net_device **out_dev)
944ce99f6b9SOr Gerlitz 
945ce99f6b9SOr Gerlitz {
946ce99f6b9SOr Gerlitz 	int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
947ce99f6b9SOr Gerlitz 	struct ip_tunnel_key *tun_key = &e->tun_info.key;
948ce99f6b9SOr Gerlitz 	int encap_size, err, ttl = 0;
949ce99f6b9SOr Gerlitz 	struct neighbour *n = NULL;
950ce99f6b9SOr Gerlitz 	struct flowi6 fl6 = {};
951ce99f6b9SOr Gerlitz 	char *encap_header;
952ce99f6b9SOr Gerlitz 
953ce99f6b9SOr Gerlitz 	encap_header = kzalloc(max_encap_size, GFP_KERNEL);
954ce99f6b9SOr Gerlitz 	if (!encap_header)
955ce99f6b9SOr Gerlitz 		return -ENOMEM;
956ce99f6b9SOr Gerlitz 
957ce99f6b9SOr Gerlitz 	switch (e->tunnel_type) {
958ce99f6b9SOr Gerlitz 	case MLX5_HEADER_TYPE_VXLAN:
959ce99f6b9SOr Gerlitz 		fl6.flowi6_proto = IPPROTO_UDP;
960ce99f6b9SOr Gerlitz 		fl6.fl6_dport = tun_key->tp_dst;
961ce99f6b9SOr Gerlitz 		break;
962ce99f6b9SOr Gerlitz 	default:
963ce99f6b9SOr Gerlitz 		err = -EOPNOTSUPP;
964ce99f6b9SOr Gerlitz 		goto out;
965ce99f6b9SOr Gerlitz 	}
966ce99f6b9SOr Gerlitz 
967ce99f6b9SOr Gerlitz 	fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tun_key->tos), tun_key->label);
968ce99f6b9SOr Gerlitz 	fl6.daddr = tun_key->u.ipv6.dst;
969ce99f6b9SOr Gerlitz 	fl6.saddr = tun_key->u.ipv6.src;
970ce99f6b9SOr Gerlitz 
971ce99f6b9SOr Gerlitz 	err = mlx5e_route_lookup_ipv6(priv, mirred_dev, out_dev,
972ce99f6b9SOr Gerlitz 				      &fl6, &n, &ttl);
973ce99f6b9SOr Gerlitz 	if (err)
974ce99f6b9SOr Gerlitz 		goto out;
975ce99f6b9SOr Gerlitz 
976ce99f6b9SOr Gerlitz 	if (!(n->nud_state & NUD_VALID)) {
977ce99f6b9SOr Gerlitz 		pr_warn("%s: can't offload, neighbour to %pI6 invalid\n", __func__, &fl6.daddr);
978ce99f6b9SOr Gerlitz 		err = -EOPNOTSUPP;
979ce99f6b9SOr Gerlitz 		goto out;
980ce99f6b9SOr Gerlitz 	}
981ce99f6b9SOr Gerlitz 
982ce99f6b9SOr Gerlitz 	e->n = n;
983ce99f6b9SOr Gerlitz 	e->out_dev = *out_dev;
984ce99f6b9SOr Gerlitz 
985ce99f6b9SOr Gerlitz 	neigh_ha_snapshot(e->h_dest, n, *out_dev);
986ce99f6b9SOr Gerlitz 
987ce99f6b9SOr Gerlitz 	switch (e->tunnel_type) {
988ce99f6b9SOr Gerlitz 	case MLX5_HEADER_TYPE_VXLAN:
989ce99f6b9SOr Gerlitz 		encap_size = gen_vxlan_header_ipv6(*out_dev, encap_header,
990ce99f6b9SOr Gerlitz 						   e->h_dest, ttl,
991ce99f6b9SOr Gerlitz 						   &fl6.daddr,
992ce99f6b9SOr Gerlitz 						   &fl6.saddr, tun_key->tp_dst,
993ce99f6b9SOr Gerlitz 						   tunnel_id_to_key32(tun_key->tun_id));
994ce99f6b9SOr Gerlitz 		break;
995ce99f6b9SOr Gerlitz 	default:
996ce99f6b9SOr Gerlitz 		err = -EOPNOTSUPP;
997ce99f6b9SOr Gerlitz 		goto out;
998ce99f6b9SOr Gerlitz 	}
999ce99f6b9SOr Gerlitz 
1000ce99f6b9SOr Gerlitz 	err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
1001ce99f6b9SOr Gerlitz 			       encap_size, encap_header, &e->encap_id);
1002ce99f6b9SOr Gerlitz out:
1003ce99f6b9SOr Gerlitz 	if (err && n)
1004ce99f6b9SOr Gerlitz 		neigh_release(n);
1005ce99f6b9SOr Gerlitz 	kfree(encap_header);
1006ce99f6b9SOr Gerlitz 	return err;
1007ce99f6b9SOr Gerlitz }
1008ce99f6b9SOr Gerlitz 
1009a54e20b4SHadar Hen Zion static int mlx5e_attach_encap(struct mlx5e_priv *priv,
1010a54e20b4SHadar Hen Zion 			      struct ip_tunnel_info *tun_info,
1011a54e20b4SHadar Hen Zion 			      struct net_device *mirred_dev,
1012776b12b6SOr Gerlitz 			      struct mlx5_esw_flow_attr *attr)
101303a9d11eSOr Gerlitz {
1014a54e20b4SHadar Hen Zion 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
10151ad9a00aSPaul Blakey 	struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw);
10161ad9a00aSPaul Blakey 	struct mlx5e_priv *up_priv = netdev_priv(up_dev);
1017a54e20b4SHadar Hen Zion 	unsigned short family = ip_tunnel_info_af(tun_info);
1018a54e20b4SHadar Hen Zion 	struct ip_tunnel_key *key = &tun_info->key;
1019a54e20b4SHadar Hen Zion 	struct mlx5_encap_entry *e;
1020a54e20b4SHadar Hen Zion 	struct net_device *out_dev;
1021ce99f6b9SOr Gerlitz 	int tunnel_type, err = -EOPNOTSUPP;
1022a54e20b4SHadar Hen Zion 	uintptr_t hash_key;
1023a54e20b4SHadar Hen Zion 	bool found = false;
1024a54e20b4SHadar Hen Zion 
10252fcd82e9SOr Gerlitz 	/* udp dst port must be set */
1026a54e20b4SHadar Hen Zion 	if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst)))
10272fcd82e9SOr Gerlitz 		goto vxlan_encap_offload_err;
1028a54e20b4SHadar Hen Zion 
1029cd377663SOr Gerlitz 	/* setting udp src port isn't supported */
10302fcd82e9SOr Gerlitz 	if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) {
10312fcd82e9SOr Gerlitz vxlan_encap_offload_err:
10322fcd82e9SOr Gerlitz 		netdev_warn(priv->netdev,
10332fcd82e9SOr Gerlitz 			    "must set udp dst port and not set udp src port\n");
1034cd377663SOr Gerlitz 		return -EOPNOTSUPP;
10352fcd82e9SOr Gerlitz 	}
1036cd377663SOr Gerlitz 
10371ad9a00aSPaul Blakey 	if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->tp_dst)) &&
1038a54e20b4SHadar Hen Zion 	    MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) {
1039a54e20b4SHadar Hen Zion 		tunnel_type = MLX5_HEADER_TYPE_VXLAN;
1040a54e20b4SHadar Hen Zion 	} else {
10412fcd82e9SOr Gerlitz 		netdev_warn(priv->netdev,
10422fcd82e9SOr Gerlitz 			    "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst));
1043a54e20b4SHadar Hen Zion 		return -EOPNOTSUPP;
1044a54e20b4SHadar Hen Zion 	}
1045a54e20b4SHadar Hen Zion 
104676f7444dSOr Gerlitz 	hash_key = hash_encap_info(key);
1047a54e20b4SHadar Hen Zion 
1048a54e20b4SHadar Hen Zion 	hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
1049a54e20b4SHadar Hen Zion 				   encap_hlist, hash_key) {
105076f7444dSOr Gerlitz 		if (!cmp_encap_info(&e->tun_info.key, key)) {
1051a54e20b4SHadar Hen Zion 			found = true;
1052a54e20b4SHadar Hen Zion 			break;
1053a54e20b4SHadar Hen Zion 		}
1054a54e20b4SHadar Hen Zion 	}
1055a54e20b4SHadar Hen Zion 
1056a54e20b4SHadar Hen Zion 	if (found) {
1057a54e20b4SHadar Hen Zion 		attr->encap = e;
1058a54e20b4SHadar Hen Zion 		return 0;
1059a54e20b4SHadar Hen Zion 	}
1060a54e20b4SHadar Hen Zion 
1061a54e20b4SHadar Hen Zion 	e = kzalloc(sizeof(*e), GFP_KERNEL);
1062a54e20b4SHadar Hen Zion 	if (!e)
1063a54e20b4SHadar Hen Zion 		return -ENOMEM;
1064a54e20b4SHadar Hen Zion 
106576f7444dSOr Gerlitz 	e->tun_info = *tun_info;
1066a54e20b4SHadar Hen Zion 	e->tunnel_type = tunnel_type;
1067a54e20b4SHadar Hen Zion 	INIT_LIST_HEAD(&e->flows);
1068a54e20b4SHadar Hen Zion 
1069ce99f6b9SOr Gerlitz 	if (family == AF_INET)
1070a54e20b4SHadar Hen Zion 		err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e, &out_dev);
1071ce99f6b9SOr Gerlitz 	else if (family == AF_INET6)
1072ce99f6b9SOr Gerlitz 		err = mlx5e_create_encap_header_ipv6(priv, mirred_dev, e, &out_dev);
1073ce99f6b9SOr Gerlitz 
1074a54e20b4SHadar Hen Zion 	if (err)
1075a54e20b4SHadar Hen Zion 		goto out_err;
1076a54e20b4SHadar Hen Zion 
1077a54e20b4SHadar Hen Zion 	attr->encap = e;
1078a54e20b4SHadar Hen Zion 	hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key);
1079a54e20b4SHadar Hen Zion 
1080a54e20b4SHadar Hen Zion 	return err;
1081a54e20b4SHadar Hen Zion 
1082a54e20b4SHadar Hen Zion out_err:
1083a54e20b4SHadar Hen Zion 	kfree(e);
1084a54e20b4SHadar Hen Zion 	return err;
1085a54e20b4SHadar Hen Zion }
1086a54e20b4SHadar Hen Zion 
1087a54e20b4SHadar Hen Zion static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
1088a54e20b4SHadar Hen Zion 				struct mlx5e_tc_flow *flow)
1089a54e20b4SHadar Hen Zion {
1090ecf5bb79SOr Gerlitz 	struct mlx5_esw_flow_attr *attr = flow->esw_attr;
1091a54e20b4SHadar Hen Zion 	struct ip_tunnel_info *info = NULL;
109203a9d11eSOr Gerlitz 	const struct tc_action *a;
109322dc13c8SWANG Cong 	LIST_HEAD(actions);
1094a54e20b4SHadar Hen Zion 	bool encap = false;
1095a54e20b4SHadar Hen Zion 	int err;
109603a9d11eSOr Gerlitz 
109703a9d11eSOr Gerlitz 	if (tc_no_actions(exts))
109803a9d11eSOr Gerlitz 		return -EINVAL;
109903a9d11eSOr Gerlitz 
1100776b12b6SOr Gerlitz 	memset(attr, 0, sizeof(*attr));
1101776b12b6SOr Gerlitz 	attr->in_rep = priv->ppriv;
110203a9d11eSOr Gerlitz 
110322dc13c8SWANG Cong 	tcf_exts_to_list(exts, &actions);
110422dc13c8SWANG Cong 	list_for_each_entry(a, &actions, list) {
110503a9d11eSOr Gerlitz 		if (is_tcf_gact_shot(a)) {
11068b32580dSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP |
110703a9d11eSOr Gerlitz 					MLX5_FLOW_CONTEXT_ACTION_COUNT;
110803a9d11eSOr Gerlitz 			continue;
110903a9d11eSOr Gerlitz 		}
111003a9d11eSOr Gerlitz 
11115724b8b5SShmulik Ladkani 		if (is_tcf_mirred_egress_redirect(a)) {
111203a9d11eSOr Gerlitz 			int ifindex = tcf_mirred_ifindex(a);
111303a9d11eSOr Gerlitz 			struct net_device *out_dev;
111403a9d11eSOr Gerlitz 			struct mlx5e_priv *out_priv;
111503a9d11eSOr Gerlitz 
111603a9d11eSOr Gerlitz 			out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex);
111703a9d11eSOr Gerlitz 
1118a54e20b4SHadar Hen Zion 			if (switchdev_port_same_parent_id(priv->netdev,
1119a54e20b4SHadar Hen Zion 							  out_dev)) {
1120e37a79e5SMark Bloch 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1121e37a79e5SMark Bloch 					MLX5_FLOW_CONTEXT_ACTION_COUNT;
112203a9d11eSOr Gerlitz 				out_priv = netdev_priv(out_dev);
1123776b12b6SOr Gerlitz 				attr->out_rep = out_priv->ppriv;
1124a54e20b4SHadar Hen Zion 			} else if (encap) {
1125a54e20b4SHadar Hen Zion 				err = mlx5e_attach_encap(priv, info,
1126a54e20b4SHadar Hen Zion 							 out_dev, attr);
1127a54e20b4SHadar Hen Zion 				if (err)
1128a54e20b4SHadar Hen Zion 					return err;
1129a54e20b4SHadar Hen Zion 				list_add(&flow->encap, &attr->encap->flows);
1130a54e20b4SHadar Hen Zion 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP |
1131a54e20b4SHadar Hen Zion 					MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1132a54e20b4SHadar Hen Zion 					MLX5_FLOW_CONTEXT_ACTION_COUNT;
1133a54e20b4SHadar Hen Zion 				out_priv = netdev_priv(attr->encap->out_dev);
1134a54e20b4SHadar Hen Zion 				attr->out_rep = out_priv->ppriv;
1135a54e20b4SHadar Hen Zion 			} else {
1136a54e20b4SHadar Hen Zion 				pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
1137a54e20b4SHadar Hen Zion 				       priv->netdev->name, out_dev->name);
1138a54e20b4SHadar Hen Zion 				return -EINVAL;
1139a54e20b4SHadar Hen Zion 			}
1140a54e20b4SHadar Hen Zion 			continue;
1141a54e20b4SHadar Hen Zion 		}
1142a54e20b4SHadar Hen Zion 
1143a54e20b4SHadar Hen Zion 		if (is_tcf_tunnel_set(a)) {
1144a54e20b4SHadar Hen Zion 			info = tcf_tunnel_info(a);
1145a54e20b4SHadar Hen Zion 			if (info)
1146a54e20b4SHadar Hen Zion 				encap = true;
1147a54e20b4SHadar Hen Zion 			else
1148a54e20b4SHadar Hen Zion 				return -EOPNOTSUPP;
114903a9d11eSOr Gerlitz 			continue;
115003a9d11eSOr Gerlitz 		}
115103a9d11eSOr Gerlitz 
11528b32580dSOr Gerlitz 		if (is_tcf_vlan(a)) {
115309c91ddfSOr Gerlitz 			if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) {
11548b32580dSOr Gerlitz 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
115509c91ddfSOr Gerlitz 			} else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) {
11568b32580dSOr Gerlitz 				if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q))
11578b32580dSOr Gerlitz 					return -EOPNOTSUPP;
11588b32580dSOr Gerlitz 
11598b32580dSOr Gerlitz 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
11608b32580dSOr Gerlitz 				attr->vlan = tcf_vlan_push_vid(a);
116109c91ddfSOr Gerlitz 			} else { /* action is TCA_VLAN_ACT_MODIFY */
116209c91ddfSOr Gerlitz 				return -EOPNOTSUPP;
11638b32580dSOr Gerlitz 			}
11648b32580dSOr Gerlitz 			continue;
11658b32580dSOr Gerlitz 		}
11668b32580dSOr Gerlitz 
1167bbd00f7eSHadar Hen Zion 		if (is_tcf_tunnel_release(a)) {
1168bbd00f7eSHadar Hen Zion 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
1169bbd00f7eSHadar Hen Zion 			continue;
1170bbd00f7eSHadar Hen Zion 		}
1171bbd00f7eSHadar Hen Zion 
117203a9d11eSOr Gerlitz 		return -EINVAL;
117303a9d11eSOr Gerlitz 	}
117403a9d11eSOr Gerlitz 	return 0;
117503a9d11eSOr Gerlitz }
117603a9d11eSOr Gerlitz 
1177e3a2b7edSAmir Vadai int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
1178e3a2b7edSAmir Vadai 			   struct tc_cls_flower_offload *f)
1179e3a2b7edSAmir Vadai {
1180adb4c123SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
118117091853SOr Gerlitz 	struct mlx5e_tc_flow_parse_attr *parse_attr;
11823bc4b7bfSOr Gerlitz 	struct mlx5e_tc_table *tc = &priv->fs.tc;
11833bc4b7bfSOr Gerlitz 	struct mlx5e_tc_flow *flow;
11843bc4b7bfSOr Gerlitz 	int attr_size, err = 0;
118565ba8fb7SOr Gerlitz 	u8 flow_flags = 0;
1186e3a2b7edSAmir Vadai 
118765ba8fb7SOr Gerlitz 	if (esw && esw->mode == SRIOV_OFFLOADS) {
118865ba8fb7SOr Gerlitz 		flow_flags = MLX5E_TC_FLOW_ESWITCH;
118965ba8fb7SOr Gerlitz 		attr_size  = sizeof(struct mlx5_esw_flow_attr);
11903bc4b7bfSOr Gerlitz 	} else {
11913bc4b7bfSOr Gerlitz 		flow_flags = MLX5E_TC_FLOW_NIC;
11923bc4b7bfSOr Gerlitz 		attr_size  = sizeof(struct mlx5_nic_flow_attr);
119365ba8fb7SOr Gerlitz 	}
1194776b12b6SOr Gerlitz 
119565ba8fb7SOr Gerlitz 	flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL);
119617091853SOr Gerlitz 	parse_attr = mlx5_vzalloc(sizeof(*parse_attr));
119717091853SOr Gerlitz 	if (!parse_attr || !flow) {
1198e3a2b7edSAmir Vadai 		err = -ENOMEM;
1199e3a2b7edSAmir Vadai 		goto err_free;
1200e3a2b7edSAmir Vadai 	}
1201e3a2b7edSAmir Vadai 
1202e3a2b7edSAmir Vadai 	flow->cookie = f->cookie;
120365ba8fb7SOr Gerlitz 	flow->flags = flow_flags;
1204e3a2b7edSAmir Vadai 
120517091853SOr Gerlitz 	err = parse_cls_flower(priv, flow, &parse_attr->spec, f);
1206e3a2b7edSAmir Vadai 	if (err < 0)
1207e3a2b7edSAmir Vadai 		goto err_free;
1208e3a2b7edSAmir Vadai 
120965ba8fb7SOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
1210a54e20b4SHadar Hen Zion 		err = parse_tc_fdb_actions(priv, f->exts, flow);
1211adb4c123SOr Gerlitz 		if (err < 0)
1212adb4c123SOr Gerlitz 			goto err_free;
121317091853SOr Gerlitz 		flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow->esw_attr);
1214adb4c123SOr Gerlitz 	} else {
12153bc4b7bfSOr Gerlitz 		err = parse_tc_nic_actions(priv, f->exts, flow->nic_attr);
1216e3a2b7edSAmir Vadai 		if (err < 0)
1217e3a2b7edSAmir Vadai 			goto err_free;
121817091853SOr Gerlitz 		flow->rule = mlx5e_tc_add_nic_flow(priv, parse_attr, flow->nic_attr);
1219adb4c123SOr Gerlitz 	}
1220adb4c123SOr Gerlitz 
12215c40348cSOr Gerlitz 	if (IS_ERR(flow->rule)) {
12225c40348cSOr Gerlitz 		err = PTR_ERR(flow->rule);
12235e86397aSOr Gerlitz 		goto err_del_rule;
12245c40348cSOr Gerlitz 	}
12255c40348cSOr Gerlitz 
1226e3a2b7edSAmir Vadai 	err = rhashtable_insert_fast(&tc->ht, &flow->node,
1227e3a2b7edSAmir Vadai 				     tc->ht_params);
1228e3a2b7edSAmir Vadai 	if (err)
12295c40348cSOr Gerlitz 		goto err_del_rule;
1230e3a2b7edSAmir Vadai 
1231e3a2b7edSAmir Vadai 	goto out;
1232e3a2b7edSAmir Vadai 
12335c40348cSOr Gerlitz err_del_rule:
12345e86397aSOr Gerlitz 	mlx5e_tc_del_flow(priv, flow);
1235e3a2b7edSAmir Vadai 
1236e3a2b7edSAmir Vadai err_free:
1237e3a2b7edSAmir Vadai 	kfree(flow);
1238e3a2b7edSAmir Vadai out:
123917091853SOr Gerlitz 	kvfree(parse_attr);
1240e3a2b7edSAmir Vadai 	return err;
1241e3a2b7edSAmir Vadai }
1242e3a2b7edSAmir Vadai 
1243e3a2b7edSAmir Vadai int mlx5e_delete_flower(struct mlx5e_priv *priv,
1244e3a2b7edSAmir Vadai 			struct tc_cls_flower_offload *f)
1245e3a2b7edSAmir Vadai {
1246e3a2b7edSAmir Vadai 	struct mlx5e_tc_flow *flow;
1247acff797cSMaor Gottlieb 	struct mlx5e_tc_table *tc = &priv->fs.tc;
1248e3a2b7edSAmir Vadai 
1249e3a2b7edSAmir Vadai 	flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
1250e3a2b7edSAmir Vadai 				      tc->ht_params);
1251e3a2b7edSAmir Vadai 	if (!flow)
1252e3a2b7edSAmir Vadai 		return -EINVAL;
1253e3a2b7edSAmir Vadai 
1254e3a2b7edSAmir Vadai 	rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
1255e3a2b7edSAmir Vadai 
1256961e8979SRoi Dayan 	mlx5e_tc_del_flow(priv, flow);
1257e3a2b7edSAmir Vadai 
1258a54e20b4SHadar Hen Zion 
1259e3a2b7edSAmir Vadai 	kfree(flow);
1260e3a2b7edSAmir Vadai 
1261e3a2b7edSAmir Vadai 	return 0;
1262e3a2b7edSAmir Vadai }
1263e3a2b7edSAmir Vadai 
1264aad7e08dSAmir Vadai int mlx5e_stats_flower(struct mlx5e_priv *priv,
1265aad7e08dSAmir Vadai 		       struct tc_cls_flower_offload *f)
1266aad7e08dSAmir Vadai {
1267aad7e08dSAmir Vadai 	struct mlx5e_tc_table *tc = &priv->fs.tc;
1268aad7e08dSAmir Vadai 	struct mlx5e_tc_flow *flow;
1269aad7e08dSAmir Vadai 	struct tc_action *a;
1270aad7e08dSAmir Vadai 	struct mlx5_fc *counter;
127122dc13c8SWANG Cong 	LIST_HEAD(actions);
1272aad7e08dSAmir Vadai 	u64 bytes;
1273aad7e08dSAmir Vadai 	u64 packets;
1274aad7e08dSAmir Vadai 	u64 lastuse;
1275aad7e08dSAmir Vadai 
1276aad7e08dSAmir Vadai 	flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
1277aad7e08dSAmir Vadai 				      tc->ht_params);
1278aad7e08dSAmir Vadai 	if (!flow)
1279aad7e08dSAmir Vadai 		return -EINVAL;
1280aad7e08dSAmir Vadai 
1281aad7e08dSAmir Vadai 	counter = mlx5_flow_rule_counter(flow->rule);
1282aad7e08dSAmir Vadai 	if (!counter)
1283aad7e08dSAmir Vadai 		return 0;
1284aad7e08dSAmir Vadai 
1285aad7e08dSAmir Vadai 	mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
1286aad7e08dSAmir Vadai 
1287fed06ee8SOr Gerlitz 	preempt_disable();
1288fed06ee8SOr Gerlitz 
128922dc13c8SWANG Cong 	tcf_exts_to_list(f->exts, &actions);
129022dc13c8SWANG Cong 	list_for_each_entry(a, &actions, list)
1291aad7e08dSAmir Vadai 		tcf_action_stats_update(a, bytes, packets, lastuse);
1292aad7e08dSAmir Vadai 
1293fed06ee8SOr Gerlitz 	preempt_enable();
1294fed06ee8SOr Gerlitz 
1295aad7e08dSAmir Vadai 	return 0;
1296aad7e08dSAmir Vadai }
1297aad7e08dSAmir Vadai 
1298e8f887acSAmir Vadai static const struct rhashtable_params mlx5e_tc_flow_ht_params = {
1299e8f887acSAmir Vadai 	.head_offset = offsetof(struct mlx5e_tc_flow, node),
1300e8f887acSAmir Vadai 	.key_offset = offsetof(struct mlx5e_tc_flow, cookie),
1301e8f887acSAmir Vadai 	.key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie),
1302e8f887acSAmir Vadai 	.automatic_shrinking = true,
1303e8f887acSAmir Vadai };
1304e8f887acSAmir Vadai 
1305e8f887acSAmir Vadai int mlx5e_tc_init(struct mlx5e_priv *priv)
1306e8f887acSAmir Vadai {
1307acff797cSMaor Gottlieb 	struct mlx5e_tc_table *tc = &priv->fs.tc;
1308e8f887acSAmir Vadai 
1309e8f887acSAmir Vadai 	tc->ht_params = mlx5e_tc_flow_ht_params;
1310e8f887acSAmir Vadai 	return rhashtable_init(&tc->ht, &tc->ht_params);
1311e8f887acSAmir Vadai }
1312e8f887acSAmir Vadai 
1313e8f887acSAmir Vadai static void _mlx5e_tc_del_flow(void *ptr, void *arg)
1314e8f887acSAmir Vadai {
1315e8f887acSAmir Vadai 	struct mlx5e_tc_flow *flow = ptr;
1316e8f887acSAmir Vadai 	struct mlx5e_priv *priv = arg;
1317e8f887acSAmir Vadai 
1318961e8979SRoi Dayan 	mlx5e_tc_del_flow(priv, flow);
1319e8f887acSAmir Vadai 	kfree(flow);
1320e8f887acSAmir Vadai }
1321e8f887acSAmir Vadai 
1322e8f887acSAmir Vadai void mlx5e_tc_cleanup(struct mlx5e_priv *priv)
1323e8f887acSAmir Vadai {
1324acff797cSMaor Gottlieb 	struct mlx5e_tc_table *tc = &priv->fs.tc;
1325e8f887acSAmir Vadai 
1326e8f887acSAmir Vadai 	rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv);
1327e8f887acSAmir Vadai 
1328acff797cSMaor Gottlieb 	if (!IS_ERR_OR_NULL(tc->t)) {
1329acff797cSMaor Gottlieb 		mlx5_destroy_flow_table(tc->t);
1330acff797cSMaor Gottlieb 		tc->t = NULL;
1331e8f887acSAmir Vadai 	}
1332e8f887acSAmir Vadai }
1333