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>
45d79b6df6SOr Gerlitz #include <net/tc_act/tc_pedit.h>
4626c02749SOr Gerlitz #include <net/tc_act/tc_csum.h>
47a54e20b4SHadar Hen Zion #include <net/vxlan.h>
48f6dfb4c3SHadar Hen Zion #include <net/arp.h>
49e8f887acSAmir Vadai #include "en.h"
501d447a39SSaeed Mahameed #include "en_rep.h"
51232c0013SHadar Hen Zion #include "en_tc.h"
5203a9d11eSOr Gerlitz #include "eswitch.h"
53bbd00f7eSHadar Hen Zion #include "vxlan.h"
54e8f887acSAmir Vadai 
553bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr {
563bc4b7bfSOr Gerlitz 	u32 action;
573bc4b7bfSOr Gerlitz 	u32 flow_tag;
582f4fe4caSOr Gerlitz 	u32 mod_hdr_id;
593bc4b7bfSOr Gerlitz };
603bc4b7bfSOr Gerlitz 
6165ba8fb7SOr Gerlitz enum {
6265ba8fb7SOr Gerlitz 	MLX5E_TC_FLOW_ESWITCH	= BIT(0),
633bc4b7bfSOr Gerlitz 	MLX5E_TC_FLOW_NIC	= BIT(1),
640b67a38fSHadar Hen Zion 	MLX5E_TC_FLOW_OFFLOADED	= BIT(2),
6565ba8fb7SOr Gerlitz };
6665ba8fb7SOr Gerlitz 
67e8f887acSAmir Vadai struct mlx5e_tc_flow {
68e8f887acSAmir Vadai 	struct rhash_head	node;
69e8f887acSAmir Vadai 	u64			cookie;
7065ba8fb7SOr Gerlitz 	u8			flags;
7174491de9SMark Bloch 	struct mlx5_flow_handle *rule;
7211c9c548SOr Gerlitz 	struct list_head	encap;   /* flows sharing the same encap ID */
7311c9c548SOr Gerlitz 	struct list_head	mod_hdr; /* flows sharing the same mod hdr ID */
743bc4b7bfSOr Gerlitz 	union {
75ecf5bb79SOr Gerlitz 		struct mlx5_esw_flow_attr esw_attr[0];
763bc4b7bfSOr Gerlitz 		struct mlx5_nic_flow_attr nic_attr[0];
773bc4b7bfSOr Gerlitz 	};
78e8f887acSAmir Vadai };
79e8f887acSAmir Vadai 
8017091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr {
8117091853SOr Gerlitz 	struct mlx5_flow_spec spec;
82d79b6df6SOr Gerlitz 	int num_mod_hdr_actions;
83d79b6df6SOr Gerlitz 	void *mod_hdr_actions;
8417091853SOr Gerlitz };
8517091853SOr Gerlitz 
86a54e20b4SHadar Hen Zion enum {
87a54e20b4SHadar Hen Zion 	MLX5_HEADER_TYPE_VXLAN = 0x0,
88a54e20b4SHadar Hen Zion 	MLX5_HEADER_TYPE_NVGRE = 0x1,
89a54e20b4SHadar Hen Zion };
90a54e20b4SHadar Hen Zion 
91acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_ENTRIES 1024
92acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_GROUPS 4
93e8f887acSAmir Vadai 
9411c9c548SOr Gerlitz struct mod_hdr_key {
9511c9c548SOr Gerlitz 	int num_actions;
9611c9c548SOr Gerlitz 	void *actions;
9711c9c548SOr Gerlitz };
9811c9c548SOr Gerlitz 
9911c9c548SOr Gerlitz struct mlx5e_mod_hdr_entry {
10011c9c548SOr Gerlitz 	/* a node of a hash table which keeps all the mod_hdr entries */
10111c9c548SOr Gerlitz 	struct hlist_node mod_hdr_hlist;
10211c9c548SOr Gerlitz 
10311c9c548SOr Gerlitz 	/* flows sharing the same mod_hdr entry */
10411c9c548SOr Gerlitz 	struct list_head flows;
10511c9c548SOr Gerlitz 
10611c9c548SOr Gerlitz 	struct mod_hdr_key key;
10711c9c548SOr Gerlitz 
10811c9c548SOr Gerlitz 	u32 mod_hdr_id;
10911c9c548SOr Gerlitz };
11011c9c548SOr Gerlitz 
11111c9c548SOr Gerlitz #define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)
11211c9c548SOr Gerlitz 
11311c9c548SOr Gerlitz static inline u32 hash_mod_hdr_info(struct mod_hdr_key *key)
11411c9c548SOr Gerlitz {
11511c9c548SOr Gerlitz 	return jhash(key->actions,
11611c9c548SOr Gerlitz 		     key->num_actions * MLX5_MH_ACT_SZ, 0);
11711c9c548SOr Gerlitz }
11811c9c548SOr Gerlitz 
11911c9c548SOr Gerlitz static inline int cmp_mod_hdr_info(struct mod_hdr_key *a,
12011c9c548SOr Gerlitz 				   struct mod_hdr_key *b)
12111c9c548SOr Gerlitz {
12211c9c548SOr Gerlitz 	if (a->num_actions != b->num_actions)
12311c9c548SOr Gerlitz 		return 1;
12411c9c548SOr Gerlitz 
12511c9c548SOr Gerlitz 	return memcmp(a->actions, b->actions, a->num_actions * MLX5_MH_ACT_SZ);
12611c9c548SOr Gerlitz }
12711c9c548SOr Gerlitz 
12811c9c548SOr Gerlitz static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
12911c9c548SOr Gerlitz 				struct mlx5e_tc_flow *flow,
13011c9c548SOr Gerlitz 				struct mlx5e_tc_flow_parse_attr *parse_attr)
13111c9c548SOr Gerlitz {
13211c9c548SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
13311c9c548SOr Gerlitz 	int num_actions, actions_size, namespace, err;
13411c9c548SOr Gerlitz 	struct mlx5e_mod_hdr_entry *mh;
13511c9c548SOr Gerlitz 	struct mod_hdr_key key;
13611c9c548SOr Gerlitz 	bool found = false;
13711c9c548SOr Gerlitz 	u32 hash_key;
13811c9c548SOr Gerlitz 
13911c9c548SOr Gerlitz 	num_actions  = parse_attr->num_mod_hdr_actions;
14011c9c548SOr Gerlitz 	actions_size = MLX5_MH_ACT_SZ * num_actions;
14111c9c548SOr Gerlitz 
14211c9c548SOr Gerlitz 	key.actions = parse_attr->mod_hdr_actions;
14311c9c548SOr Gerlitz 	key.num_actions = num_actions;
14411c9c548SOr Gerlitz 
14511c9c548SOr Gerlitz 	hash_key = hash_mod_hdr_info(&key);
14611c9c548SOr Gerlitz 
14711c9c548SOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
14811c9c548SOr Gerlitz 		namespace = MLX5_FLOW_NAMESPACE_FDB;
14911c9c548SOr Gerlitz 		hash_for_each_possible(esw->offloads.mod_hdr_tbl, mh,
15011c9c548SOr Gerlitz 				       mod_hdr_hlist, hash_key) {
15111c9c548SOr Gerlitz 			if (!cmp_mod_hdr_info(&mh->key, &key)) {
15211c9c548SOr Gerlitz 				found = true;
15311c9c548SOr Gerlitz 				break;
15411c9c548SOr Gerlitz 			}
15511c9c548SOr Gerlitz 		}
15611c9c548SOr Gerlitz 	} else {
15711c9c548SOr Gerlitz 		namespace = MLX5_FLOW_NAMESPACE_KERNEL;
15811c9c548SOr Gerlitz 		hash_for_each_possible(priv->fs.tc.mod_hdr_tbl, mh,
15911c9c548SOr Gerlitz 				       mod_hdr_hlist, hash_key) {
16011c9c548SOr Gerlitz 			if (!cmp_mod_hdr_info(&mh->key, &key)) {
16111c9c548SOr Gerlitz 				found = true;
16211c9c548SOr Gerlitz 				break;
16311c9c548SOr Gerlitz 			}
16411c9c548SOr Gerlitz 		}
16511c9c548SOr Gerlitz 	}
16611c9c548SOr Gerlitz 
16711c9c548SOr Gerlitz 	if (found)
16811c9c548SOr Gerlitz 		goto attach_flow;
16911c9c548SOr Gerlitz 
17011c9c548SOr Gerlitz 	mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL);
17111c9c548SOr Gerlitz 	if (!mh)
17211c9c548SOr Gerlitz 		return -ENOMEM;
17311c9c548SOr Gerlitz 
17411c9c548SOr Gerlitz 	mh->key.actions = (void *)mh + sizeof(*mh);
17511c9c548SOr Gerlitz 	memcpy(mh->key.actions, key.actions, actions_size);
17611c9c548SOr Gerlitz 	mh->key.num_actions = num_actions;
17711c9c548SOr Gerlitz 	INIT_LIST_HEAD(&mh->flows);
17811c9c548SOr Gerlitz 
17911c9c548SOr Gerlitz 	err = mlx5_modify_header_alloc(priv->mdev, namespace,
18011c9c548SOr Gerlitz 				       mh->key.num_actions,
18111c9c548SOr Gerlitz 				       mh->key.actions,
18211c9c548SOr Gerlitz 				       &mh->mod_hdr_id);
18311c9c548SOr Gerlitz 	if (err)
18411c9c548SOr Gerlitz 		goto out_err;
18511c9c548SOr Gerlitz 
18611c9c548SOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
18711c9c548SOr Gerlitz 		hash_add(esw->offloads.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key);
18811c9c548SOr Gerlitz 	else
18911c9c548SOr Gerlitz 		hash_add(priv->fs.tc.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key);
19011c9c548SOr Gerlitz 
19111c9c548SOr Gerlitz attach_flow:
19211c9c548SOr Gerlitz 	list_add(&flow->mod_hdr, &mh->flows);
19311c9c548SOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
19411c9c548SOr Gerlitz 		flow->esw_attr->mod_hdr_id = mh->mod_hdr_id;
19511c9c548SOr Gerlitz 	else
19611c9c548SOr Gerlitz 		flow->nic_attr->mod_hdr_id = mh->mod_hdr_id;
19711c9c548SOr Gerlitz 
19811c9c548SOr Gerlitz 	return 0;
19911c9c548SOr Gerlitz 
20011c9c548SOr Gerlitz out_err:
20111c9c548SOr Gerlitz 	kfree(mh);
20211c9c548SOr Gerlitz 	return err;
20311c9c548SOr Gerlitz }
20411c9c548SOr Gerlitz 
20511c9c548SOr Gerlitz static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
20611c9c548SOr Gerlitz 				 struct mlx5e_tc_flow *flow)
20711c9c548SOr Gerlitz {
20811c9c548SOr Gerlitz 	struct list_head *next = flow->mod_hdr.next;
20911c9c548SOr Gerlitz 
21011c9c548SOr Gerlitz 	list_del(&flow->mod_hdr);
21111c9c548SOr Gerlitz 
21211c9c548SOr Gerlitz 	if (list_empty(next)) {
21311c9c548SOr Gerlitz 		struct mlx5e_mod_hdr_entry *mh;
21411c9c548SOr Gerlitz 
21511c9c548SOr Gerlitz 		mh = list_entry(next, struct mlx5e_mod_hdr_entry, flows);
21611c9c548SOr Gerlitz 
21711c9c548SOr Gerlitz 		mlx5_modify_header_dealloc(priv->mdev, mh->mod_hdr_id);
21811c9c548SOr Gerlitz 		hash_del(&mh->mod_hdr_hlist);
21911c9c548SOr Gerlitz 		kfree(mh);
22011c9c548SOr Gerlitz 	}
22111c9c548SOr Gerlitz }
22211c9c548SOr Gerlitz 
22374491de9SMark Bloch static struct mlx5_flow_handle *
22474491de9SMark Bloch mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
22517091853SOr Gerlitz 		      struct mlx5e_tc_flow_parse_attr *parse_attr,
226aa0cbbaeSOr Gerlitz 		      struct mlx5e_tc_flow *flow)
227e8f887acSAmir Vadai {
228aa0cbbaeSOr Gerlitz 	struct mlx5_nic_flow_attr *attr = flow->nic_attr;
229aad7e08dSAmir Vadai 	struct mlx5_core_dev *dev = priv->mdev;
230aa0cbbaeSOr Gerlitz 	struct mlx5_flow_destination dest = {};
23166958ed9SHadar Hen Zion 	struct mlx5_flow_act flow_act = {
2323bc4b7bfSOr Gerlitz 		.action = attr->action,
2333bc4b7bfSOr Gerlitz 		.flow_tag = attr->flow_tag,
23466958ed9SHadar Hen Zion 		.encap_id = 0,
23566958ed9SHadar Hen Zion 	};
236aad7e08dSAmir Vadai 	struct mlx5_fc *counter = NULL;
23774491de9SMark Bloch 	struct mlx5_flow_handle *rule;
238e8f887acSAmir Vadai 	bool table_created = false;
2392f4fe4caSOr Gerlitz 	int err;
240e8f887acSAmir Vadai 
2413bc4b7bfSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
242aad7e08dSAmir Vadai 		dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
243aad7e08dSAmir Vadai 		dest.ft = priv->fs.vlan.ft.t;
2443bc4b7bfSOr Gerlitz 	} else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
245aad7e08dSAmir Vadai 		counter = mlx5_fc_create(dev, true);
246aad7e08dSAmir Vadai 		if (IS_ERR(counter))
247aad7e08dSAmir Vadai 			return ERR_CAST(counter);
248aad7e08dSAmir Vadai 
249aad7e08dSAmir Vadai 		dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
250aad7e08dSAmir Vadai 		dest.counter = counter;
251aad7e08dSAmir Vadai 	}
252aad7e08dSAmir Vadai 
2532f4fe4caSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
2543099eb5aSOr Gerlitz 		err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
255d7e75a32SOr Gerlitz 		flow_act.modify_id = attr->mod_hdr_id;
2562f4fe4caSOr Gerlitz 		kfree(parse_attr->mod_hdr_actions);
2572f4fe4caSOr Gerlitz 		if (err) {
2582f4fe4caSOr Gerlitz 			rule = ERR_PTR(err);
2592f4fe4caSOr Gerlitz 			goto err_create_mod_hdr_id;
2602f4fe4caSOr Gerlitz 		}
2612f4fe4caSOr Gerlitz 	}
2622f4fe4caSOr Gerlitz 
263acff797cSMaor Gottlieb 	if (IS_ERR_OR_NULL(priv->fs.tc.t)) {
264acff797cSMaor Gottlieb 		priv->fs.tc.t =
265acff797cSMaor Gottlieb 			mlx5_create_auto_grouped_flow_table(priv->fs.ns,
266acff797cSMaor Gottlieb 							    MLX5E_TC_PRIO,
267acff797cSMaor Gottlieb 							    MLX5E_TC_TABLE_NUM_ENTRIES,
268acff797cSMaor Gottlieb 							    MLX5E_TC_TABLE_NUM_GROUPS,
269c9f1b073SHadar Hen Zion 							    0, 0);
270acff797cSMaor Gottlieb 		if (IS_ERR(priv->fs.tc.t)) {
271e8f887acSAmir Vadai 			netdev_err(priv->netdev,
272e8f887acSAmir Vadai 				   "Failed to create tc offload table\n");
273aad7e08dSAmir Vadai 			rule = ERR_CAST(priv->fs.tc.t);
274aad7e08dSAmir Vadai 			goto err_create_ft;
275e8f887acSAmir Vadai 		}
276e8f887acSAmir Vadai 
277e8f887acSAmir Vadai 		table_created = true;
278e8f887acSAmir Vadai 	}
279e8f887acSAmir Vadai 
28017091853SOr Gerlitz 	parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
28117091853SOr Gerlitz 	rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
28217091853SOr Gerlitz 				   &flow_act, &dest, 1);
283e8f887acSAmir Vadai 
284aad7e08dSAmir Vadai 	if (IS_ERR(rule))
285aad7e08dSAmir Vadai 		goto err_add_rule;
286aad7e08dSAmir Vadai 
287aad7e08dSAmir Vadai 	return rule;
288aad7e08dSAmir Vadai 
289aad7e08dSAmir Vadai err_add_rule:
290aad7e08dSAmir Vadai 	if (table_created) {
291acff797cSMaor Gottlieb 		mlx5_destroy_flow_table(priv->fs.tc.t);
292acff797cSMaor Gottlieb 		priv->fs.tc.t = NULL;
293e8f887acSAmir Vadai 	}
294aad7e08dSAmir Vadai err_create_ft:
2952f4fe4caSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
2963099eb5aSOr Gerlitz 		mlx5e_detach_mod_hdr(priv, flow);
2972f4fe4caSOr Gerlitz err_create_mod_hdr_id:
298aad7e08dSAmir Vadai 	mlx5_fc_destroy(dev, counter);
299e8f887acSAmir Vadai 
300e8f887acSAmir Vadai 	return rule;
301e8f887acSAmir Vadai }
302e8f887acSAmir Vadai 
303d85cdccbSOr Gerlitz static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
304d85cdccbSOr Gerlitz 				  struct mlx5e_tc_flow *flow)
305d85cdccbSOr Gerlitz {
306513f8f7fSOr Gerlitz 	struct mlx5_nic_flow_attr *attr = flow->nic_attr;
307d85cdccbSOr Gerlitz 	struct mlx5_fc *counter = NULL;
308d85cdccbSOr Gerlitz 
309d85cdccbSOr Gerlitz 	counter = mlx5_flow_rule_counter(flow->rule);
310d85cdccbSOr Gerlitz 	mlx5_del_flow_rules(flow->rule);
311d85cdccbSOr Gerlitz 	mlx5_fc_destroy(priv->mdev, counter);
312d85cdccbSOr Gerlitz 
313d85cdccbSOr Gerlitz 	if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) {
314d85cdccbSOr Gerlitz 		mlx5_destroy_flow_table(priv->fs.tc.t);
315d85cdccbSOr Gerlitz 		priv->fs.tc.t = NULL;
316d85cdccbSOr Gerlitz 	}
3172f4fe4caSOr Gerlitz 
318513f8f7fSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
3193099eb5aSOr Gerlitz 		mlx5e_detach_mod_hdr(priv, flow);
320d85cdccbSOr Gerlitz }
321d85cdccbSOr Gerlitz 
322aa0cbbaeSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv,
323aa0cbbaeSOr Gerlitz 			       struct mlx5e_tc_flow *flow);
324aa0cbbaeSOr Gerlitz 
32574491de9SMark Bloch static struct mlx5_flow_handle *
32674491de9SMark Bloch mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
32717091853SOr Gerlitz 		      struct mlx5e_tc_flow_parse_attr *parse_attr,
328aa0cbbaeSOr Gerlitz 		      struct mlx5e_tc_flow *flow)
329adb4c123SOr Gerlitz {
330adb4c123SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
331aa0cbbaeSOr Gerlitz 	struct mlx5_esw_flow_attr *attr = flow->esw_attr;
332aa0cbbaeSOr Gerlitz 	struct mlx5_flow_handle *rule;
3338b32580dSOr Gerlitz 	int err;
3348b32580dSOr Gerlitz 
3358b32580dSOr Gerlitz 	err = mlx5_eswitch_add_vlan_action(esw, attr);
336aa0cbbaeSOr Gerlitz 	if (err) {
337aa0cbbaeSOr Gerlitz 		rule = ERR_PTR(err);
338aa0cbbaeSOr Gerlitz 		goto err_add_vlan;
339adb4c123SOr Gerlitz 	}
340adb4c123SOr Gerlitz 
341d7e75a32SOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
3421a9527bbSOr Gerlitz 		err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
343d7e75a32SOr Gerlitz 		kfree(parse_attr->mod_hdr_actions);
344d7e75a32SOr Gerlitz 		if (err) {
345d7e75a32SOr Gerlitz 			rule = ERR_PTR(err);
346d7e75a32SOr Gerlitz 			goto err_mod_hdr;
347d7e75a32SOr Gerlitz 		}
348d7e75a32SOr Gerlitz 	}
349d7e75a32SOr Gerlitz 
350aa0cbbaeSOr Gerlitz 	rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr);
351aa0cbbaeSOr Gerlitz 	if (IS_ERR(rule))
352aa0cbbaeSOr Gerlitz 		goto err_add_rule;
353aa0cbbaeSOr Gerlitz 
354aa0cbbaeSOr Gerlitz 	return rule;
355aa0cbbaeSOr Gerlitz 
356aa0cbbaeSOr Gerlitz err_add_rule:
357513f8f7fSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
3581a9527bbSOr Gerlitz 		mlx5e_detach_mod_hdr(priv, flow);
359d7e75a32SOr Gerlitz err_mod_hdr:
360aa0cbbaeSOr Gerlitz 	mlx5_eswitch_del_vlan_action(esw, attr);
361aa0cbbaeSOr Gerlitz err_add_vlan:
362aa0cbbaeSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
363aa0cbbaeSOr Gerlitz 		mlx5e_detach_encap(priv, flow);
364aa0cbbaeSOr Gerlitz 	return rule;
365aa0cbbaeSOr Gerlitz }
366d85cdccbSOr Gerlitz 
367d85cdccbSOr Gerlitz static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
368d85cdccbSOr Gerlitz 				  struct mlx5e_tc_flow *flow)
369d85cdccbSOr Gerlitz {
370d85cdccbSOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
371d7e75a32SOr Gerlitz 	struct mlx5_esw_flow_attr *attr = flow->esw_attr;
372d85cdccbSOr Gerlitz 
373232c0013SHadar Hen Zion 	if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
374232c0013SHadar Hen Zion 		flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
375513f8f7fSOr Gerlitz 		mlx5_eswitch_del_offloaded_rule(esw, flow->rule, attr);
376232c0013SHadar Hen Zion 	}
377d85cdccbSOr Gerlitz 
378513f8f7fSOr Gerlitz 	mlx5_eswitch_del_vlan_action(esw, attr);
379d85cdccbSOr Gerlitz 
380513f8f7fSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) {
381d85cdccbSOr Gerlitz 		mlx5e_detach_encap(priv, flow);
382513f8f7fSOr Gerlitz 		kvfree(attr->parse_attr);
383232c0013SHadar Hen Zion 	}
384d7e75a32SOr Gerlitz 
385513f8f7fSOr Gerlitz 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
3861a9527bbSOr Gerlitz 		mlx5e_detach_mod_hdr(priv, flow);
387d85cdccbSOr Gerlitz }
388d85cdccbSOr Gerlitz 
389232c0013SHadar Hen Zion void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
390232c0013SHadar Hen Zion 			      struct mlx5e_encap_entry *e)
391232c0013SHadar Hen Zion {
392232c0013SHadar Hen Zion 	struct mlx5e_tc_flow *flow;
393232c0013SHadar Hen Zion 	int err;
394232c0013SHadar Hen Zion 
395232c0013SHadar Hen Zion 	err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
396232c0013SHadar Hen Zion 			       e->encap_size, e->encap_header,
397232c0013SHadar Hen Zion 			       &e->encap_id);
398232c0013SHadar Hen Zion 	if (err) {
399232c0013SHadar Hen Zion 		mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %d\n",
400232c0013SHadar Hen Zion 			       err);
401232c0013SHadar Hen Zion 		return;
402232c0013SHadar Hen Zion 	}
403232c0013SHadar Hen Zion 	e->flags |= MLX5_ENCAP_ENTRY_VALID;
404f6dfb4c3SHadar Hen Zion 	mlx5e_rep_queue_neigh_stats_work(priv);
405232c0013SHadar Hen Zion 
406232c0013SHadar Hen Zion 	list_for_each_entry(flow, &e->flows, encap) {
407232c0013SHadar Hen Zion 		flow->esw_attr->encap_id = e->encap_id;
408232c0013SHadar Hen Zion 		flow->rule = mlx5e_tc_add_fdb_flow(priv,
409232c0013SHadar Hen Zion 						   flow->esw_attr->parse_attr,
410232c0013SHadar Hen Zion 						   flow);
411232c0013SHadar Hen Zion 		if (IS_ERR(flow->rule)) {
412232c0013SHadar Hen Zion 			err = PTR_ERR(flow->rule);
413232c0013SHadar Hen Zion 			mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
414232c0013SHadar Hen Zion 				       err);
415232c0013SHadar Hen Zion 			continue;
416232c0013SHadar Hen Zion 		}
417232c0013SHadar Hen Zion 		flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
418232c0013SHadar Hen Zion 	}
419232c0013SHadar Hen Zion }
420232c0013SHadar Hen Zion 
421232c0013SHadar Hen Zion void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
422232c0013SHadar Hen Zion 			      struct mlx5e_encap_entry *e)
423232c0013SHadar Hen Zion {
424232c0013SHadar Hen Zion 	struct mlx5e_tc_flow *flow;
425232c0013SHadar Hen Zion 	struct mlx5_fc *counter;
426232c0013SHadar Hen Zion 
427232c0013SHadar Hen Zion 	list_for_each_entry(flow, &e->flows, encap) {
428232c0013SHadar Hen Zion 		if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
429232c0013SHadar Hen Zion 			flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
430232c0013SHadar Hen Zion 			counter = mlx5_flow_rule_counter(flow->rule);
431232c0013SHadar Hen Zion 			mlx5_del_flow_rules(flow->rule);
432232c0013SHadar Hen Zion 			mlx5_fc_destroy(priv->mdev, counter);
433232c0013SHadar Hen Zion 		}
434232c0013SHadar Hen Zion 	}
435232c0013SHadar Hen Zion 
436232c0013SHadar Hen Zion 	if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
437232c0013SHadar Hen Zion 		e->flags &= ~MLX5_ENCAP_ENTRY_VALID;
438232c0013SHadar Hen Zion 		mlx5_encap_dealloc(priv->mdev, e->encap_id);
439232c0013SHadar Hen Zion 	}
440232c0013SHadar Hen Zion }
441232c0013SHadar Hen Zion 
442f6dfb4c3SHadar Hen Zion void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
443f6dfb4c3SHadar Hen Zion {
444f6dfb4c3SHadar Hen Zion 	struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
445f6dfb4c3SHadar Hen Zion 	u64 bytes, packets, lastuse = 0;
446f6dfb4c3SHadar Hen Zion 	struct mlx5e_tc_flow *flow;
447f6dfb4c3SHadar Hen Zion 	struct mlx5e_encap_entry *e;
448f6dfb4c3SHadar Hen Zion 	struct mlx5_fc *counter;
449f6dfb4c3SHadar Hen Zion 	struct neigh_table *tbl;
450f6dfb4c3SHadar Hen Zion 	bool neigh_used = false;
451f6dfb4c3SHadar Hen Zion 	struct neighbour *n;
452f6dfb4c3SHadar Hen Zion 
453f6dfb4c3SHadar Hen Zion 	if (m_neigh->family == AF_INET)
454f6dfb4c3SHadar Hen Zion 		tbl = &arp_tbl;
455f6dfb4c3SHadar Hen Zion #if IS_ENABLED(CONFIG_IPV6)
456f6dfb4c3SHadar Hen Zion 	else if (m_neigh->family == AF_INET6)
457f6dfb4c3SHadar Hen Zion 		tbl = ipv6_stub->nd_tbl;
458f6dfb4c3SHadar Hen Zion #endif
459f6dfb4c3SHadar Hen Zion 	else
460f6dfb4c3SHadar Hen Zion 		return;
461f6dfb4c3SHadar Hen Zion 
462f6dfb4c3SHadar Hen Zion 	list_for_each_entry(e, &nhe->encap_list, encap_list) {
463f6dfb4c3SHadar Hen Zion 		if (!(e->flags & MLX5_ENCAP_ENTRY_VALID))
464f6dfb4c3SHadar Hen Zion 			continue;
465f6dfb4c3SHadar Hen Zion 		list_for_each_entry(flow, &e->flows, encap) {
466f6dfb4c3SHadar Hen Zion 			if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
467f6dfb4c3SHadar Hen Zion 				counter = mlx5_flow_rule_counter(flow->rule);
468f6dfb4c3SHadar Hen Zion 				mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
469f6dfb4c3SHadar Hen Zion 				if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
470f6dfb4c3SHadar Hen Zion 					neigh_used = true;
471f6dfb4c3SHadar Hen Zion 					break;
472f6dfb4c3SHadar Hen Zion 				}
473f6dfb4c3SHadar Hen Zion 			}
474f6dfb4c3SHadar Hen Zion 		}
475f6dfb4c3SHadar Hen Zion 	}
476f6dfb4c3SHadar Hen Zion 
477f6dfb4c3SHadar Hen Zion 	if (neigh_used) {
478f6dfb4c3SHadar Hen Zion 		nhe->reported_lastuse = jiffies;
479f6dfb4c3SHadar Hen Zion 
480f6dfb4c3SHadar Hen Zion 		/* find the relevant neigh according to the cached device and
481f6dfb4c3SHadar Hen Zion 		 * dst ip pair
482f6dfb4c3SHadar Hen Zion 		 */
483f6dfb4c3SHadar Hen Zion 		n = neigh_lookup(tbl, &m_neigh->dst_ip, m_neigh->dev);
484f6dfb4c3SHadar Hen Zion 		if (!n) {
485f6dfb4c3SHadar Hen Zion 			WARN(1, "The neighbour already freed\n");
486f6dfb4c3SHadar Hen Zion 			return;
487f6dfb4c3SHadar Hen Zion 		}
488f6dfb4c3SHadar Hen Zion 
489f6dfb4c3SHadar Hen Zion 		neigh_event_send(n, NULL);
490f6dfb4c3SHadar Hen Zion 		neigh_release(n);
491f6dfb4c3SHadar Hen Zion 	}
492f6dfb4c3SHadar Hen Zion }
493f6dfb4c3SHadar Hen Zion 
494d85cdccbSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv,
495d85cdccbSOr Gerlitz 			       struct mlx5e_tc_flow *flow)
496d85cdccbSOr Gerlitz {
4975067b602SRoi Dayan 	struct list_head *next = flow->encap.next;
4985067b602SRoi Dayan 
4995067b602SRoi Dayan 	list_del(&flow->encap);
5005067b602SRoi Dayan 	if (list_empty(next)) {
501c1ae1152SOr Gerlitz 		struct mlx5e_encap_entry *e;
5025067b602SRoi Dayan 
503c1ae1152SOr Gerlitz 		e = list_entry(next, struct mlx5e_encap_entry, flows);
504232c0013SHadar Hen Zion 		mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e);
505232c0013SHadar Hen Zion 
506232c0013SHadar Hen Zion 		if (e->flags & MLX5_ENCAP_ENTRY_VALID)
5075067b602SRoi Dayan 			mlx5_encap_dealloc(priv->mdev, e->encap_id);
508232c0013SHadar Hen Zion 
509cdc5a7f3SOr Gerlitz 		hash_del_rcu(&e->encap_hlist);
510232c0013SHadar Hen Zion 		kfree(e->encap_header);
5115067b602SRoi Dayan 		kfree(e);
5125067b602SRoi Dayan 	}
5135067b602SRoi Dayan }
5145067b602SRoi Dayan 
515e8f887acSAmir Vadai static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
516961e8979SRoi Dayan 			      struct mlx5e_tc_flow *flow)
517e8f887acSAmir Vadai {
518d85cdccbSOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
519d85cdccbSOr Gerlitz 		mlx5e_tc_del_fdb_flow(priv, flow);
520d85cdccbSOr Gerlitz 	else
521d85cdccbSOr Gerlitz 		mlx5e_tc_del_nic_flow(priv, flow);
522e8f887acSAmir Vadai }
523e8f887acSAmir Vadai 
524bbd00f7eSHadar Hen Zion static void parse_vxlan_attr(struct mlx5_flow_spec *spec,
525bbd00f7eSHadar Hen Zion 			     struct tc_cls_flower_offload *f)
526bbd00f7eSHadar Hen Zion {
527bbd00f7eSHadar Hen Zion 	void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
528bbd00f7eSHadar Hen Zion 				       outer_headers);
529bbd00f7eSHadar Hen Zion 	void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
530bbd00f7eSHadar Hen Zion 				       outer_headers);
531bbd00f7eSHadar Hen Zion 	void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
532bbd00f7eSHadar Hen Zion 				    misc_parameters);
533bbd00f7eSHadar Hen Zion 	void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
534bbd00f7eSHadar Hen Zion 				    misc_parameters);
535bbd00f7eSHadar Hen Zion 
536bbd00f7eSHadar Hen Zion 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
537bbd00f7eSHadar Hen Zion 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
538bbd00f7eSHadar Hen Zion 
539bbd00f7eSHadar Hen Zion 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
540bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_keyid *key =
541bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
542bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_KEYID,
543bbd00f7eSHadar Hen Zion 						  f->key);
544bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_keyid *mask =
545bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
546bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_KEYID,
547bbd00f7eSHadar Hen Zion 						  f->mask);
548bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
549bbd00f7eSHadar Hen Zion 			 be32_to_cpu(mask->keyid));
550bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
551bbd00f7eSHadar Hen Zion 			 be32_to_cpu(key->keyid));
552bbd00f7eSHadar Hen Zion 	}
553bbd00f7eSHadar Hen Zion }
554bbd00f7eSHadar Hen Zion 
555bbd00f7eSHadar Hen Zion static int parse_tunnel_attr(struct mlx5e_priv *priv,
556bbd00f7eSHadar Hen Zion 			     struct mlx5_flow_spec *spec,
557bbd00f7eSHadar Hen Zion 			     struct tc_cls_flower_offload *f)
558bbd00f7eSHadar Hen Zion {
559bbd00f7eSHadar Hen Zion 	void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
560bbd00f7eSHadar Hen Zion 				       outer_headers);
561bbd00f7eSHadar Hen Zion 	void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
562bbd00f7eSHadar Hen Zion 				       outer_headers);
563bbd00f7eSHadar Hen Zion 
5642e72eb43SOr Gerlitz 	struct flow_dissector_key_control *enc_control =
5652e72eb43SOr Gerlitz 		skb_flow_dissector_target(f->dissector,
5662e72eb43SOr Gerlitz 					  FLOW_DISSECTOR_KEY_ENC_CONTROL,
5672e72eb43SOr Gerlitz 					  f->key);
5682e72eb43SOr Gerlitz 
569bbd00f7eSHadar Hen Zion 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
570bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ports *key =
571bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
572bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_PORTS,
573bbd00f7eSHadar Hen Zion 						  f->key);
574bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ports *mask =
575bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
576bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_PORTS,
577bbd00f7eSHadar Hen Zion 						  f->mask);
5781ad9a00aSPaul Blakey 		struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
5791ad9a00aSPaul Blakey 		struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw);
5801ad9a00aSPaul Blakey 		struct mlx5e_priv *up_priv = netdev_priv(up_dev);
581bbd00f7eSHadar Hen Zion 
582bbd00f7eSHadar Hen Zion 		/* Full udp dst port must be given */
583bbd00f7eSHadar Hen Zion 		if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst)))
5842fcd82e9SOr Gerlitz 			goto vxlan_match_offload_err;
585bbd00f7eSHadar Hen Zion 
5861ad9a00aSPaul Blakey 		if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->dst)) &&
587bbd00f7eSHadar Hen Zion 		    MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
588bbd00f7eSHadar Hen Zion 			parse_vxlan_attr(spec, f);
5892fcd82e9SOr Gerlitz 		else {
5902fcd82e9SOr Gerlitz 			netdev_warn(priv->netdev,
5912fcd82e9SOr Gerlitz 				    "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst));
592bbd00f7eSHadar Hen Zion 			return -EOPNOTSUPP;
5932fcd82e9SOr Gerlitz 		}
594bbd00f7eSHadar Hen Zion 
595bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
596bbd00f7eSHadar Hen Zion 			 udp_dport, ntohs(mask->dst));
597bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
598bbd00f7eSHadar Hen Zion 			 udp_dport, ntohs(key->dst));
599bbd00f7eSHadar Hen Zion 
600cd377663SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
601cd377663SOr Gerlitz 			 udp_sport, ntohs(mask->src));
602cd377663SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
603cd377663SOr Gerlitz 			 udp_sport, ntohs(key->src));
604bbd00f7eSHadar Hen Zion 	} else { /* udp dst port must be given */
6052fcd82e9SOr Gerlitz vxlan_match_offload_err:
6062fcd82e9SOr Gerlitz 		netdev_warn(priv->netdev,
6072fcd82e9SOr Gerlitz 			    "IP tunnel decap offload supported only for vxlan, must set UDP dport\n");
608bbd00f7eSHadar Hen Zion 		return -EOPNOTSUPP;
609bbd00f7eSHadar Hen Zion 	}
610bbd00f7eSHadar Hen Zion 
6112e72eb43SOr Gerlitz 	if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
612bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ipv4_addrs *key =
613bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
614bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
615bbd00f7eSHadar Hen Zion 						  f->key);
616bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_ipv4_addrs *mask =
617bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
618bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
619bbd00f7eSHadar Hen Zion 						  f->mask);
620bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
621bbd00f7eSHadar Hen Zion 			 src_ipv4_src_ipv6.ipv4_layout.ipv4,
622bbd00f7eSHadar Hen Zion 			 ntohl(mask->src));
623bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
624bbd00f7eSHadar Hen Zion 			 src_ipv4_src_ipv6.ipv4_layout.ipv4,
625bbd00f7eSHadar Hen Zion 			 ntohl(key->src));
626bbd00f7eSHadar Hen Zion 
627bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_c,
628bbd00f7eSHadar Hen Zion 			 dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
629bbd00f7eSHadar Hen Zion 			 ntohl(mask->dst));
630bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
631bbd00f7eSHadar Hen Zion 			 dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
632bbd00f7eSHadar Hen Zion 			 ntohl(key->dst));
633bbd00f7eSHadar Hen Zion 
634bbd00f7eSHadar Hen Zion 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
635bbd00f7eSHadar Hen Zion 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
63619f44401SOr Gerlitz 	} else if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
63719f44401SOr Gerlitz 		struct flow_dissector_key_ipv6_addrs *key =
63819f44401SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
63919f44401SOr Gerlitz 						  FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
64019f44401SOr Gerlitz 						  f->key);
64119f44401SOr Gerlitz 		struct flow_dissector_key_ipv6_addrs *mask =
64219f44401SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
64319f44401SOr Gerlitz 						  FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
64419f44401SOr Gerlitz 						  f->mask);
64519f44401SOr Gerlitz 
64619f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
64719f44401SOr Gerlitz 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
64819f44401SOr Gerlitz 		       &mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
64919f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
65019f44401SOr Gerlitz 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
65119f44401SOr Gerlitz 		       &key->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
65219f44401SOr Gerlitz 
65319f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
65419f44401SOr Gerlitz 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
65519f44401SOr Gerlitz 		       &mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
65619f44401SOr Gerlitz 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
65719f44401SOr Gerlitz 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
65819f44401SOr Gerlitz 		       &key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
65919f44401SOr Gerlitz 
66019f44401SOr Gerlitz 		MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
66119f44401SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6);
6622e72eb43SOr Gerlitz 	}
663bbd00f7eSHadar Hen Zion 
664bbd00f7eSHadar Hen Zion 	/* Enforce DMAC when offloading incoming tunneled flows.
665bbd00f7eSHadar Hen Zion 	 * Flow counters require a match on the DMAC.
666bbd00f7eSHadar Hen Zion 	 */
667bbd00f7eSHadar Hen Zion 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_47_16);
668bbd00f7eSHadar Hen Zion 	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_15_0);
669bbd00f7eSHadar Hen Zion 	ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
670bbd00f7eSHadar Hen Zion 				     dmac_47_16), priv->netdev->dev_addr);
671bbd00f7eSHadar Hen Zion 
672bbd00f7eSHadar Hen Zion 	/* let software handle IP fragments */
673bbd00f7eSHadar Hen Zion 	MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1);
674bbd00f7eSHadar Hen Zion 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 0);
675bbd00f7eSHadar Hen Zion 
676bbd00f7eSHadar Hen Zion 	return 0;
677bbd00f7eSHadar Hen Zion }
678bbd00f7eSHadar Hen Zion 
679de0af0bfSRoi Dayan static int __parse_cls_flower(struct mlx5e_priv *priv,
680de0af0bfSRoi Dayan 			      struct mlx5_flow_spec *spec,
681de0af0bfSRoi Dayan 			      struct tc_cls_flower_offload *f,
682de0af0bfSRoi Dayan 			      u8 *min_inline)
683e3a2b7edSAmir Vadai {
684c5bb1730SMaor Gottlieb 	void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
685c5bb1730SMaor Gottlieb 				       outer_headers);
686c5bb1730SMaor Gottlieb 	void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
687c5bb1730SMaor Gottlieb 				       outer_headers);
688e3a2b7edSAmir Vadai 	u16 addr_type = 0;
689e3a2b7edSAmir Vadai 	u8 ip_proto = 0;
690e3a2b7edSAmir Vadai 
691de0af0bfSRoi Dayan 	*min_inline = MLX5_INLINE_MODE_L2;
692de0af0bfSRoi Dayan 
693e3a2b7edSAmir Vadai 	if (f->dissector->used_keys &
694e3a2b7edSAmir Vadai 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
695e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
696e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
697095b6cfdSOr Gerlitz 	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
698e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
699e3a2b7edSAmir Vadai 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
700bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
701bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
702bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
703bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
704bbd00f7eSHadar Hen Zion 	      BIT(FLOW_DISSECTOR_KEY_ENC_PORTS)	|
705e77834ecSOr Gerlitz 	      BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
706fd7da28bSOr Gerlitz 	      BIT(FLOW_DISSECTOR_KEY_TCP) |
707fd7da28bSOr Gerlitz 	      BIT(FLOW_DISSECTOR_KEY_IP))) {
708e3a2b7edSAmir Vadai 		netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
709e3a2b7edSAmir Vadai 			    f->dissector->used_keys);
710e3a2b7edSAmir Vadai 		return -EOPNOTSUPP;
711e3a2b7edSAmir Vadai 	}
712e3a2b7edSAmir Vadai 
713bbd00f7eSHadar Hen Zion 	if ((dissector_uses_key(f->dissector,
714bbd00f7eSHadar Hen Zion 				FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) ||
715bbd00f7eSHadar Hen Zion 	     dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID) ||
716bbd00f7eSHadar Hen Zion 	     dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) &&
717bbd00f7eSHadar Hen Zion 	    dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
718bbd00f7eSHadar Hen Zion 		struct flow_dissector_key_control *key =
719bbd00f7eSHadar Hen Zion 			skb_flow_dissector_target(f->dissector,
720bbd00f7eSHadar Hen Zion 						  FLOW_DISSECTOR_KEY_ENC_CONTROL,
721bbd00f7eSHadar Hen Zion 						  f->key);
722bbd00f7eSHadar Hen Zion 		switch (key->addr_type) {
723bbd00f7eSHadar Hen Zion 		case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
72419f44401SOr Gerlitz 		case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
725bbd00f7eSHadar Hen Zion 			if (parse_tunnel_attr(priv, spec, f))
726bbd00f7eSHadar Hen Zion 				return -EOPNOTSUPP;
727bbd00f7eSHadar Hen Zion 			break;
728bbd00f7eSHadar Hen Zion 		default:
729bbd00f7eSHadar Hen Zion 			return -EOPNOTSUPP;
730bbd00f7eSHadar Hen Zion 		}
731bbd00f7eSHadar Hen Zion 
732bbd00f7eSHadar Hen Zion 		/* In decap flow, header pointers should point to the inner
733bbd00f7eSHadar Hen Zion 		 * headers, outer header were already set by parse_tunnel_attr
734bbd00f7eSHadar Hen Zion 		 */
735bbd00f7eSHadar Hen Zion 		headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
736bbd00f7eSHadar Hen Zion 					 inner_headers);
737bbd00f7eSHadar Hen Zion 		headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
738bbd00f7eSHadar Hen Zion 					 inner_headers);
739bbd00f7eSHadar Hen Zion 	}
740bbd00f7eSHadar Hen Zion 
741e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
742e3a2b7edSAmir Vadai 		struct flow_dissector_key_control *key =
743e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
7441dbd0d37SHadar Hen Zion 						  FLOW_DISSECTOR_KEY_CONTROL,
745e3a2b7edSAmir Vadai 						  f->key);
7463f7d0eb4SOr Gerlitz 
7473f7d0eb4SOr Gerlitz 		struct flow_dissector_key_control *mask =
7483f7d0eb4SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
7493f7d0eb4SOr Gerlitz 						  FLOW_DISSECTOR_KEY_CONTROL,
7503f7d0eb4SOr Gerlitz 						  f->mask);
751e3a2b7edSAmir Vadai 		addr_type = key->addr_type;
7523f7d0eb4SOr Gerlitz 
7533f7d0eb4SOr Gerlitz 		if (mask->flags & FLOW_DIS_IS_FRAGMENT) {
7543f7d0eb4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1);
7553f7d0eb4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
7563f7d0eb4SOr Gerlitz 				 key->flags & FLOW_DIS_IS_FRAGMENT);
7570827444dSOr Gerlitz 
7580827444dSOr Gerlitz 			/* the HW doesn't need L3 inline to match on frag=no */
7590827444dSOr Gerlitz 			if (key->flags & FLOW_DIS_IS_FRAGMENT)
7600827444dSOr Gerlitz 				*min_inline = MLX5_INLINE_MODE_IP;
7613f7d0eb4SOr Gerlitz 		}
762e3a2b7edSAmir Vadai 	}
763e3a2b7edSAmir Vadai 
764e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
765e3a2b7edSAmir Vadai 		struct flow_dissector_key_basic *key =
766e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
767e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_BASIC,
768e3a2b7edSAmir Vadai 						  f->key);
769e3a2b7edSAmir Vadai 		struct flow_dissector_key_basic *mask =
770e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
771e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_BASIC,
772e3a2b7edSAmir Vadai 						  f->mask);
773e3a2b7edSAmir Vadai 		ip_proto = key->ip_proto;
774e3a2b7edSAmir Vadai 
775e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype,
776e3a2b7edSAmir Vadai 			 ntohs(mask->n_proto));
777e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
778e3a2b7edSAmir Vadai 			 ntohs(key->n_proto));
779e3a2b7edSAmir Vadai 
780e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol,
781e3a2b7edSAmir Vadai 			 mask->ip_proto);
782e3a2b7edSAmir Vadai 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
783e3a2b7edSAmir Vadai 			 key->ip_proto);
784de0af0bfSRoi Dayan 
785de0af0bfSRoi Dayan 		if (mask->ip_proto)
786de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_IP;
787e3a2b7edSAmir Vadai 	}
788e3a2b7edSAmir Vadai 
789e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
790e3a2b7edSAmir Vadai 		struct flow_dissector_key_eth_addrs *key =
791e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
792e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
793e3a2b7edSAmir Vadai 						  f->key);
794e3a2b7edSAmir Vadai 		struct flow_dissector_key_eth_addrs *mask =
795e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
796e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
797e3a2b7edSAmir Vadai 						  f->mask);
798e3a2b7edSAmir Vadai 
799e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
800e3a2b7edSAmir Vadai 					     dmac_47_16),
801e3a2b7edSAmir Vadai 				mask->dst);
802e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
803e3a2b7edSAmir Vadai 					     dmac_47_16),
804e3a2b7edSAmir Vadai 				key->dst);
805e3a2b7edSAmir Vadai 
806e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
807e3a2b7edSAmir Vadai 					     smac_47_16),
808e3a2b7edSAmir Vadai 				mask->src);
809e3a2b7edSAmir Vadai 		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
810e3a2b7edSAmir Vadai 					     smac_47_16),
811e3a2b7edSAmir Vadai 				key->src);
812e3a2b7edSAmir Vadai 	}
813e3a2b7edSAmir Vadai 
814095b6cfdSOr Gerlitz 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
815095b6cfdSOr Gerlitz 		struct flow_dissector_key_vlan *key =
816095b6cfdSOr Gerlitz 			skb_flow_dissector_target(f->dissector,
817095b6cfdSOr Gerlitz 						  FLOW_DISSECTOR_KEY_VLAN,
818095b6cfdSOr Gerlitz 						  f->key);
819095b6cfdSOr Gerlitz 		struct flow_dissector_key_vlan *mask =
820095b6cfdSOr Gerlitz 			skb_flow_dissector_target(f->dissector,
821095b6cfdSOr Gerlitz 						  FLOW_DISSECTOR_KEY_VLAN,
822095b6cfdSOr Gerlitz 						  f->mask);
823358d79a4SOr Gerlitz 		if (mask->vlan_id || mask->vlan_priority) {
82410543365SMohamad Haj Yahia 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1);
82510543365SMohamad Haj Yahia 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1);
826095b6cfdSOr Gerlitz 
827095b6cfdSOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id);
828095b6cfdSOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id);
829358d79a4SOr Gerlitz 
830358d79a4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, mask->vlan_priority);
831358d79a4SOr Gerlitz 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, key->vlan_priority);
832095b6cfdSOr Gerlitz 		}
833095b6cfdSOr Gerlitz 	}
834095b6cfdSOr Gerlitz 
835e3a2b7edSAmir Vadai 	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
836e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv4_addrs *key =
837e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
838e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
839e3a2b7edSAmir Vadai 						  f->key);
840e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv4_addrs *mask =
841e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
842e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
843e3a2b7edSAmir Vadai 						  f->mask);
844e3a2b7edSAmir Vadai 
845e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
846e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv4_layout.ipv4),
847e3a2b7edSAmir Vadai 		       &mask->src, sizeof(mask->src));
848e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
849e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv4_layout.ipv4),
850e3a2b7edSAmir Vadai 		       &key->src, sizeof(key->src));
851e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
852e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
853e3a2b7edSAmir Vadai 		       &mask->dst, sizeof(mask->dst));
854e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
855e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
856e3a2b7edSAmir Vadai 		       &key->dst, sizeof(key->dst));
857de0af0bfSRoi Dayan 
858de0af0bfSRoi Dayan 		if (mask->src || mask->dst)
859de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_IP;
860e3a2b7edSAmir Vadai 	}
861e3a2b7edSAmir Vadai 
862e3a2b7edSAmir Vadai 	if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
863e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv6_addrs *key =
864e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
865e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
866e3a2b7edSAmir Vadai 						  f->key);
867e3a2b7edSAmir Vadai 		struct flow_dissector_key_ipv6_addrs *mask =
868e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
869e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
870e3a2b7edSAmir Vadai 						  f->mask);
871e3a2b7edSAmir Vadai 
872e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
873e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
874e3a2b7edSAmir Vadai 		       &mask->src, sizeof(mask->src));
875e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
876e3a2b7edSAmir Vadai 				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
877e3a2b7edSAmir Vadai 		       &key->src, sizeof(key->src));
878e3a2b7edSAmir Vadai 
879e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
880e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
881e3a2b7edSAmir Vadai 		       &mask->dst, sizeof(mask->dst));
882e3a2b7edSAmir Vadai 		memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
883e3a2b7edSAmir Vadai 				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
884e3a2b7edSAmir Vadai 		       &key->dst, sizeof(key->dst));
885de0af0bfSRoi Dayan 
886de0af0bfSRoi Dayan 		if (ipv6_addr_type(&mask->src) != IPV6_ADDR_ANY ||
887de0af0bfSRoi Dayan 		    ipv6_addr_type(&mask->dst) != IPV6_ADDR_ANY)
888de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_IP;
889e3a2b7edSAmir Vadai 	}
890e3a2b7edSAmir Vadai 
8911f97a526SOr Gerlitz 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) {
8921f97a526SOr Gerlitz 		struct flow_dissector_key_ip *key =
8931f97a526SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
8941f97a526SOr Gerlitz 						  FLOW_DISSECTOR_KEY_IP,
8951f97a526SOr Gerlitz 						  f->key);
8961f97a526SOr Gerlitz 		struct flow_dissector_key_ip *mask =
8971f97a526SOr Gerlitz 			skb_flow_dissector_target(f->dissector,
8981f97a526SOr Gerlitz 						  FLOW_DISSECTOR_KEY_IP,
8991f97a526SOr Gerlitz 						  f->mask);
9001f97a526SOr Gerlitz 
9011f97a526SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3);
9021f97a526SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3);
9031f97a526SOr Gerlitz 
9041f97a526SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2);
9051f97a526SOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos  >> 2);
9061f97a526SOr Gerlitz 
907a8ade55fSOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ttl_hoplimit, mask->ttl);
908a8ade55fSOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ttl_hoplimit, key->ttl);
9091f97a526SOr Gerlitz 
910a8ade55fSOr Gerlitz 		if (mask->ttl &&
911a8ade55fSOr Gerlitz 		    !MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
912a8ade55fSOr Gerlitz 						ft_field_support.outer_ipv4_ttl))
9131f97a526SOr Gerlitz 			return -EOPNOTSUPP;
914a8ade55fSOr Gerlitz 
915a8ade55fSOr Gerlitz 		if (mask->tos || mask->ttl)
916a8ade55fSOr Gerlitz 			*min_inline = MLX5_INLINE_MODE_IP;
9171f97a526SOr Gerlitz 	}
9181f97a526SOr Gerlitz 
919e3a2b7edSAmir Vadai 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
920e3a2b7edSAmir Vadai 		struct flow_dissector_key_ports *key =
921e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
922e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_PORTS,
923e3a2b7edSAmir Vadai 						  f->key);
924e3a2b7edSAmir Vadai 		struct flow_dissector_key_ports *mask =
925e3a2b7edSAmir Vadai 			skb_flow_dissector_target(f->dissector,
926e3a2b7edSAmir Vadai 						  FLOW_DISSECTOR_KEY_PORTS,
927e3a2b7edSAmir Vadai 						  f->mask);
928e3a2b7edSAmir Vadai 		switch (ip_proto) {
929e3a2b7edSAmir Vadai 		case IPPROTO_TCP:
930e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
931e3a2b7edSAmir Vadai 				 tcp_sport, ntohs(mask->src));
932e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
933e3a2b7edSAmir Vadai 				 tcp_sport, ntohs(key->src));
934e3a2b7edSAmir Vadai 
935e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
936e3a2b7edSAmir Vadai 				 tcp_dport, ntohs(mask->dst));
937e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
938e3a2b7edSAmir Vadai 				 tcp_dport, ntohs(key->dst));
939e3a2b7edSAmir Vadai 			break;
940e3a2b7edSAmir Vadai 
941e3a2b7edSAmir Vadai 		case IPPROTO_UDP:
942e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
943e3a2b7edSAmir Vadai 				 udp_sport, ntohs(mask->src));
944e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
945e3a2b7edSAmir Vadai 				 udp_sport, ntohs(key->src));
946e3a2b7edSAmir Vadai 
947e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_c,
948e3a2b7edSAmir Vadai 				 udp_dport, ntohs(mask->dst));
949e3a2b7edSAmir Vadai 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
950e3a2b7edSAmir Vadai 				 udp_dport, ntohs(key->dst));
951e3a2b7edSAmir Vadai 			break;
952e3a2b7edSAmir Vadai 		default:
953e3a2b7edSAmir Vadai 			netdev_err(priv->netdev,
954e3a2b7edSAmir Vadai 				   "Only UDP and TCP transport are supported\n");
955e3a2b7edSAmir Vadai 			return -EINVAL;
956e3a2b7edSAmir Vadai 		}
957de0af0bfSRoi Dayan 
958de0af0bfSRoi Dayan 		if (mask->src || mask->dst)
959de0af0bfSRoi Dayan 			*min_inline = MLX5_INLINE_MODE_TCP_UDP;
960e3a2b7edSAmir Vadai 	}
961e3a2b7edSAmir Vadai 
962e77834ecSOr Gerlitz 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) {
963e77834ecSOr Gerlitz 		struct flow_dissector_key_tcp *key =
964e77834ecSOr Gerlitz 			skb_flow_dissector_target(f->dissector,
965e77834ecSOr Gerlitz 						  FLOW_DISSECTOR_KEY_TCP,
966e77834ecSOr Gerlitz 						  f->key);
967e77834ecSOr Gerlitz 		struct flow_dissector_key_tcp *mask =
968e77834ecSOr Gerlitz 			skb_flow_dissector_target(f->dissector,
969e77834ecSOr Gerlitz 						  FLOW_DISSECTOR_KEY_TCP,
970e77834ecSOr Gerlitz 						  f->mask);
971e77834ecSOr Gerlitz 
972e77834ecSOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_flags,
973e77834ecSOr Gerlitz 			 ntohs(mask->flags));
974e77834ecSOr Gerlitz 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
975e77834ecSOr Gerlitz 			 ntohs(key->flags));
976e77834ecSOr Gerlitz 
977e77834ecSOr Gerlitz 		if (mask->flags)
978e77834ecSOr Gerlitz 			*min_inline = MLX5_INLINE_MODE_TCP_UDP;
979e77834ecSOr Gerlitz 	}
980e77834ecSOr Gerlitz 
981e3a2b7edSAmir Vadai 	return 0;
982e3a2b7edSAmir Vadai }
983e3a2b7edSAmir Vadai 
984de0af0bfSRoi Dayan static int parse_cls_flower(struct mlx5e_priv *priv,
98565ba8fb7SOr Gerlitz 			    struct mlx5e_tc_flow *flow,
986de0af0bfSRoi Dayan 			    struct mlx5_flow_spec *spec,
987de0af0bfSRoi Dayan 			    struct tc_cls_flower_offload *f)
988de0af0bfSRoi Dayan {
989de0af0bfSRoi Dayan 	struct mlx5_core_dev *dev = priv->mdev;
990de0af0bfSRoi Dayan 	struct mlx5_eswitch *esw = dev->priv.eswitch;
9911d447a39SSaeed Mahameed 	struct mlx5e_rep_priv *rpriv = priv->ppriv;
9921d447a39SSaeed Mahameed 	struct mlx5_eswitch_rep *rep;
993de0af0bfSRoi Dayan 	u8 min_inline;
994de0af0bfSRoi Dayan 	int err;
995de0af0bfSRoi Dayan 
996de0af0bfSRoi Dayan 	err = __parse_cls_flower(priv, spec, f, &min_inline);
997de0af0bfSRoi Dayan 
9981d447a39SSaeed Mahameed 	if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH)) {
9991d447a39SSaeed Mahameed 		rep = rpriv->rep;
10001d447a39SSaeed Mahameed 		if (rep->vport != FDB_UPLINK_VPORT &&
10011d447a39SSaeed Mahameed 		    (esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE &&
10021d447a39SSaeed Mahameed 		    esw->offloads.inline_mode < min_inline)) {
1003de0af0bfSRoi Dayan 			netdev_warn(priv->netdev,
1004de0af0bfSRoi Dayan 				    "Flow is not offloaded due to min inline setting, required %d actual %d\n",
1005de0af0bfSRoi Dayan 				    min_inline, esw->offloads.inline_mode);
1006de0af0bfSRoi Dayan 			return -EOPNOTSUPP;
1007de0af0bfSRoi Dayan 		}
1008de0af0bfSRoi Dayan 	}
1009de0af0bfSRoi Dayan 
1010de0af0bfSRoi Dayan 	return err;
1011de0af0bfSRoi Dayan }
1012de0af0bfSRoi Dayan 
1013d79b6df6SOr Gerlitz struct pedit_headers {
1014d79b6df6SOr Gerlitz 	struct ethhdr  eth;
1015d79b6df6SOr Gerlitz 	struct iphdr   ip4;
1016d79b6df6SOr Gerlitz 	struct ipv6hdr ip6;
1017d79b6df6SOr Gerlitz 	struct tcphdr  tcp;
1018d79b6df6SOr Gerlitz 	struct udphdr  udp;
1019d79b6df6SOr Gerlitz };
1020d79b6df6SOr Gerlitz 
1021d79b6df6SOr Gerlitz static int pedit_header_offsets[] = {
1022d79b6df6SOr Gerlitz 	[TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = offsetof(struct pedit_headers, eth),
1023d79b6df6SOr Gerlitz 	[TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = offsetof(struct pedit_headers, ip4),
1024d79b6df6SOr Gerlitz 	[TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = offsetof(struct pedit_headers, ip6),
1025d79b6df6SOr Gerlitz 	[TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = offsetof(struct pedit_headers, tcp),
1026d79b6df6SOr Gerlitz 	[TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = offsetof(struct pedit_headers, udp),
1027d79b6df6SOr Gerlitz };
1028d79b6df6SOr Gerlitz 
1029d79b6df6SOr Gerlitz #define pedit_header(_ph, _htype) ((void *)(_ph) + pedit_header_offsets[_htype])
1030d79b6df6SOr Gerlitz 
1031d79b6df6SOr Gerlitz static int set_pedit_val(u8 hdr_type, u32 mask, u32 val, u32 offset,
1032d79b6df6SOr Gerlitz 			 struct pedit_headers *masks,
1033d79b6df6SOr Gerlitz 			 struct pedit_headers *vals)
1034d79b6df6SOr Gerlitz {
1035d79b6df6SOr Gerlitz 	u32 *curr_pmask, *curr_pval;
1036d79b6df6SOr Gerlitz 
1037d79b6df6SOr Gerlitz 	if (hdr_type >= __PEDIT_HDR_TYPE_MAX)
1038d79b6df6SOr Gerlitz 		goto out_err;
1039d79b6df6SOr Gerlitz 
1040d79b6df6SOr Gerlitz 	curr_pmask = (u32 *)(pedit_header(masks, hdr_type) + offset);
1041d79b6df6SOr Gerlitz 	curr_pval  = (u32 *)(pedit_header(vals, hdr_type) + offset);
1042d79b6df6SOr Gerlitz 
1043d79b6df6SOr Gerlitz 	if (*curr_pmask & mask)  /* disallow acting twice on the same location */
1044d79b6df6SOr Gerlitz 		goto out_err;
1045d79b6df6SOr Gerlitz 
1046d79b6df6SOr Gerlitz 	*curr_pmask |= mask;
1047d79b6df6SOr Gerlitz 	*curr_pval  |= (val & mask);
1048d79b6df6SOr Gerlitz 
1049d79b6df6SOr Gerlitz 	return 0;
1050d79b6df6SOr Gerlitz 
1051d79b6df6SOr Gerlitz out_err:
1052d79b6df6SOr Gerlitz 	return -EOPNOTSUPP;
1053d79b6df6SOr Gerlitz }
1054d79b6df6SOr Gerlitz 
1055d79b6df6SOr Gerlitz struct mlx5_fields {
1056d79b6df6SOr Gerlitz 	u8  field;
1057d79b6df6SOr Gerlitz 	u8  size;
1058d79b6df6SOr Gerlitz 	u32 offset;
1059d79b6df6SOr Gerlitz };
1060d79b6df6SOr Gerlitz 
1061a8e4f0c4SOr Gerlitz #define OFFLOAD(fw_field, size, field, off) \
1062a8e4f0c4SOr Gerlitz 		{MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, size, offsetof(struct pedit_headers, field) + (off)}
1063a8e4f0c4SOr Gerlitz 
1064d79b6df6SOr Gerlitz static struct mlx5_fields fields[] = {
1065a8e4f0c4SOr Gerlitz 	OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0),
1066a8e4f0c4SOr Gerlitz 	OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0),
1067a8e4f0c4SOr Gerlitz 	OFFLOAD(DMAC_15_0,  2, eth.h_dest[4], 0),
1068a8e4f0c4SOr Gerlitz 	OFFLOAD(SMAC_47_16, 4, eth.h_source[0], 0),
1069a8e4f0c4SOr Gerlitz 	OFFLOAD(SMAC_15_0,  2, eth.h_source[4], 0),
1070a8e4f0c4SOr Gerlitz 	OFFLOAD(ETHERTYPE,  2, eth.h_proto, 0),
1071d79b6df6SOr Gerlitz 
1072a8e4f0c4SOr Gerlitz 	OFFLOAD(IP_TTL, 1, ip4.ttl,   0),
1073a8e4f0c4SOr Gerlitz 	OFFLOAD(SIPV4,  4, ip4.saddr, 0),
1074a8e4f0c4SOr Gerlitz 	OFFLOAD(DIPV4,  4, ip4.daddr, 0),
1075d79b6df6SOr Gerlitz 
1076a8e4f0c4SOr Gerlitz 	OFFLOAD(SIPV6_127_96, 4, ip6.saddr.s6_addr32[0], 0),
1077a8e4f0c4SOr Gerlitz 	OFFLOAD(SIPV6_95_64,  4, ip6.saddr.s6_addr32[1], 0),
1078a8e4f0c4SOr Gerlitz 	OFFLOAD(SIPV6_63_32,  4, ip6.saddr.s6_addr32[2], 0),
1079a8e4f0c4SOr Gerlitz 	OFFLOAD(SIPV6_31_0,   4, ip6.saddr.s6_addr32[3], 0),
1080a8e4f0c4SOr Gerlitz 	OFFLOAD(DIPV6_127_96, 4, ip6.daddr.s6_addr32[0], 0),
1081a8e4f0c4SOr Gerlitz 	OFFLOAD(DIPV6_95_64,  4, ip6.daddr.s6_addr32[1], 0),
1082a8e4f0c4SOr Gerlitz 	OFFLOAD(DIPV6_63_32,  4, ip6.daddr.s6_addr32[2], 0),
1083a8e4f0c4SOr Gerlitz 	OFFLOAD(DIPV6_31_0,   4, ip6.daddr.s6_addr32[3], 0),
10840c0316f5SOr Gerlitz 	OFFLOAD(IPV6_HOPLIMIT, 1, ip6.hop_limit, 0),
1085d79b6df6SOr Gerlitz 
1086a8e4f0c4SOr Gerlitz 	OFFLOAD(TCP_SPORT, 2, tcp.source,  0),
1087a8e4f0c4SOr Gerlitz 	OFFLOAD(TCP_DPORT, 2, tcp.dest,    0),
1088a8e4f0c4SOr Gerlitz 	OFFLOAD(TCP_FLAGS, 1, tcp.ack_seq, 5),
1089d79b6df6SOr Gerlitz 
1090a8e4f0c4SOr Gerlitz 	OFFLOAD(UDP_SPORT, 2, udp.source, 0),
1091a8e4f0c4SOr Gerlitz 	OFFLOAD(UDP_DPORT, 2, udp.dest,   0),
1092d79b6df6SOr Gerlitz };
1093d79b6df6SOr Gerlitz 
1094d79b6df6SOr Gerlitz /* On input attr->num_mod_hdr_actions tells how many HW actions can be parsed at
1095d79b6df6SOr Gerlitz  * max from the SW pedit action. On success, it says how many HW actions were
1096d79b6df6SOr Gerlitz  * actually parsed.
1097d79b6df6SOr Gerlitz  */
1098d79b6df6SOr Gerlitz static int offload_pedit_fields(struct pedit_headers *masks,
1099d79b6df6SOr Gerlitz 				struct pedit_headers *vals,
1100d79b6df6SOr Gerlitz 				struct mlx5e_tc_flow_parse_attr *parse_attr)
1101d79b6df6SOr Gerlitz {
1102d79b6df6SOr Gerlitz 	struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals;
11032b64bebaSOr Gerlitz 	int i, action_size, nactions, max_actions, first, last, next_z;
1104d79b6df6SOr Gerlitz 	void *s_masks_p, *a_masks_p, *vals_p;
1105d79b6df6SOr Gerlitz 	struct mlx5_fields *f;
1106d79b6df6SOr Gerlitz 	u8 cmd, field_bsize;
1107e3ca4e05SOr Gerlitz 	u32 s_mask, a_mask;
1108d79b6df6SOr Gerlitz 	unsigned long mask;
11092b64bebaSOr Gerlitz 	__be32 mask_be32;
11102b64bebaSOr Gerlitz 	__be16 mask_be16;
1111d79b6df6SOr Gerlitz 	void *action;
1112d79b6df6SOr Gerlitz 
1113d79b6df6SOr Gerlitz 	set_masks = &masks[TCA_PEDIT_KEY_EX_CMD_SET];
1114d79b6df6SOr Gerlitz 	add_masks = &masks[TCA_PEDIT_KEY_EX_CMD_ADD];
1115d79b6df6SOr Gerlitz 	set_vals = &vals[TCA_PEDIT_KEY_EX_CMD_SET];
1116d79b6df6SOr Gerlitz 	add_vals = &vals[TCA_PEDIT_KEY_EX_CMD_ADD];
1117d79b6df6SOr Gerlitz 
1118d79b6df6SOr Gerlitz 	action_size = MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto);
1119d79b6df6SOr Gerlitz 	action = parse_attr->mod_hdr_actions;
1120d79b6df6SOr Gerlitz 	max_actions = parse_attr->num_mod_hdr_actions;
1121d79b6df6SOr Gerlitz 	nactions = 0;
1122d79b6df6SOr Gerlitz 
1123d79b6df6SOr Gerlitz 	for (i = 0; i < ARRAY_SIZE(fields); i++) {
1124d79b6df6SOr Gerlitz 		f = &fields[i];
1125d79b6df6SOr Gerlitz 		/* avoid seeing bits set from previous iterations */
1126e3ca4e05SOr Gerlitz 		s_mask = 0;
1127e3ca4e05SOr Gerlitz 		a_mask = 0;
1128d79b6df6SOr Gerlitz 
1129d79b6df6SOr Gerlitz 		s_masks_p = (void *)set_masks + f->offset;
1130d79b6df6SOr Gerlitz 		a_masks_p = (void *)add_masks + f->offset;
1131d79b6df6SOr Gerlitz 
1132d79b6df6SOr Gerlitz 		memcpy(&s_mask, s_masks_p, f->size);
1133d79b6df6SOr Gerlitz 		memcpy(&a_mask, a_masks_p, f->size);
1134d79b6df6SOr Gerlitz 
1135d79b6df6SOr Gerlitz 		if (!s_mask && !a_mask) /* nothing to offload here */
1136d79b6df6SOr Gerlitz 			continue;
1137d79b6df6SOr Gerlitz 
1138d79b6df6SOr Gerlitz 		if (s_mask && a_mask) {
1139d79b6df6SOr Gerlitz 			printk(KERN_WARNING "mlx5: can't set and add to the same HW field (%x)\n", f->field);
1140d79b6df6SOr Gerlitz 			return -EOPNOTSUPP;
1141d79b6df6SOr Gerlitz 		}
1142d79b6df6SOr Gerlitz 
1143d79b6df6SOr Gerlitz 		if (nactions == max_actions) {
1144d79b6df6SOr Gerlitz 			printk(KERN_WARNING "mlx5: parsed %d pedit actions, can't do more\n", nactions);
1145d79b6df6SOr Gerlitz 			return -EOPNOTSUPP;
1146d79b6df6SOr Gerlitz 		}
1147d79b6df6SOr Gerlitz 
1148d79b6df6SOr Gerlitz 		if (s_mask) {
1149d79b6df6SOr Gerlitz 			cmd  = MLX5_ACTION_TYPE_SET;
1150d79b6df6SOr Gerlitz 			mask = s_mask;
1151d79b6df6SOr Gerlitz 			vals_p = (void *)set_vals + f->offset;
1152d79b6df6SOr Gerlitz 			/* clear to denote we consumed this field */
1153d79b6df6SOr Gerlitz 			memset(s_masks_p, 0, f->size);
1154d79b6df6SOr Gerlitz 		} else {
1155d79b6df6SOr Gerlitz 			cmd  = MLX5_ACTION_TYPE_ADD;
1156d79b6df6SOr Gerlitz 			mask = a_mask;
1157d79b6df6SOr Gerlitz 			vals_p = (void *)add_vals + f->offset;
1158d79b6df6SOr Gerlitz 			/* clear to denote we consumed this field */
1159d79b6df6SOr Gerlitz 			memset(a_masks_p, 0, f->size);
1160d79b6df6SOr Gerlitz 		}
1161d79b6df6SOr Gerlitz 
1162d79b6df6SOr Gerlitz 		field_bsize = f->size * BITS_PER_BYTE;
1163e3ca4e05SOr Gerlitz 
11642b64bebaSOr Gerlitz 		if (field_bsize == 32) {
11652b64bebaSOr Gerlitz 			mask_be32 = *(__be32 *)&mask;
11662b64bebaSOr Gerlitz 			mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32));
11672b64bebaSOr Gerlitz 		} else if (field_bsize == 16) {
11682b64bebaSOr Gerlitz 			mask_be16 = *(__be16 *)&mask;
11692b64bebaSOr Gerlitz 			mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16));
11702b64bebaSOr Gerlitz 		}
11712b64bebaSOr Gerlitz 
1172d79b6df6SOr Gerlitz 		first = find_first_bit(&mask, field_bsize);
11732b64bebaSOr Gerlitz 		next_z = find_next_zero_bit(&mask, field_bsize, first);
1174d79b6df6SOr Gerlitz 		last  = find_last_bit(&mask, field_bsize);
11752b64bebaSOr Gerlitz 		if (first < next_z && next_z < last) {
11762b64bebaSOr Gerlitz 			printk(KERN_WARNING "mlx5: rewrite of few sub-fields (mask %lx) isn't offloaded\n",
1177d79b6df6SOr Gerlitz 			       mask);
1178d79b6df6SOr Gerlitz 			return -EOPNOTSUPP;
1179d79b6df6SOr Gerlitz 		}
1180d79b6df6SOr Gerlitz 
1181d79b6df6SOr Gerlitz 		MLX5_SET(set_action_in, action, action_type, cmd);
1182d79b6df6SOr Gerlitz 		MLX5_SET(set_action_in, action, field, f->field);
1183d79b6df6SOr Gerlitz 
1184d79b6df6SOr Gerlitz 		if (cmd == MLX5_ACTION_TYPE_SET) {
11852b64bebaSOr Gerlitz 			MLX5_SET(set_action_in, action, offset, first);
1186d79b6df6SOr Gerlitz 			/* length is num of bits to be written, zero means length of 32 */
11872b64bebaSOr Gerlitz 			MLX5_SET(set_action_in, action, length, (last - first + 1));
1188d79b6df6SOr Gerlitz 		}
1189d79b6df6SOr Gerlitz 
1190d79b6df6SOr Gerlitz 		if (field_bsize == 32)
11912b64bebaSOr Gerlitz 			MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p) >> first);
1192d79b6df6SOr Gerlitz 		else if (field_bsize == 16)
11932b64bebaSOr Gerlitz 			MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p) >> first);
1194d79b6df6SOr Gerlitz 		else if (field_bsize == 8)
11952b64bebaSOr Gerlitz 			MLX5_SET(set_action_in, action, data, *(u8 *)vals_p >> first);
1196d79b6df6SOr Gerlitz 
1197d79b6df6SOr Gerlitz 		action += action_size;
1198d79b6df6SOr Gerlitz 		nactions++;
1199d79b6df6SOr Gerlitz 	}
1200d79b6df6SOr Gerlitz 
1201d79b6df6SOr Gerlitz 	parse_attr->num_mod_hdr_actions = nactions;
1202d79b6df6SOr Gerlitz 	return 0;
1203d79b6df6SOr Gerlitz }
1204d79b6df6SOr Gerlitz 
1205d79b6df6SOr Gerlitz static int alloc_mod_hdr_actions(struct mlx5e_priv *priv,
1206d79b6df6SOr Gerlitz 				 const struct tc_action *a, int namespace,
1207d79b6df6SOr Gerlitz 				 struct mlx5e_tc_flow_parse_attr *parse_attr)
1208d79b6df6SOr Gerlitz {
1209d79b6df6SOr Gerlitz 	int nkeys, action_size, max_actions;
1210d79b6df6SOr Gerlitz 
1211d79b6df6SOr Gerlitz 	nkeys = tcf_pedit_nkeys(a);
1212d79b6df6SOr Gerlitz 	action_size = MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto);
1213d79b6df6SOr Gerlitz 
1214d79b6df6SOr Gerlitz 	if (namespace == MLX5_FLOW_NAMESPACE_FDB) /* FDB offloading */
1215d79b6df6SOr Gerlitz 		max_actions = MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, max_modify_header_actions);
1216d79b6df6SOr Gerlitz 	else /* namespace is MLX5_FLOW_NAMESPACE_KERNEL - NIC offloading */
1217d79b6df6SOr Gerlitz 		max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, max_modify_header_actions);
1218d79b6df6SOr Gerlitz 
1219d79b6df6SOr Gerlitz 	/* can get up to crazingly 16 HW actions in 32 bits pedit SW key */
1220d79b6df6SOr Gerlitz 	max_actions = min(max_actions, nkeys * 16);
1221d79b6df6SOr Gerlitz 
1222d79b6df6SOr Gerlitz 	parse_attr->mod_hdr_actions = kcalloc(max_actions, action_size, GFP_KERNEL);
1223d79b6df6SOr Gerlitz 	if (!parse_attr->mod_hdr_actions)
1224d79b6df6SOr Gerlitz 		return -ENOMEM;
1225d79b6df6SOr Gerlitz 
1226d79b6df6SOr Gerlitz 	parse_attr->num_mod_hdr_actions = max_actions;
1227d79b6df6SOr Gerlitz 	return 0;
1228d79b6df6SOr Gerlitz }
1229d79b6df6SOr Gerlitz 
1230d79b6df6SOr Gerlitz static const struct pedit_headers zero_masks = {};
1231d79b6df6SOr Gerlitz 
1232d79b6df6SOr Gerlitz static int parse_tc_pedit_action(struct mlx5e_priv *priv,
1233d79b6df6SOr Gerlitz 				 const struct tc_action *a, int namespace,
1234d79b6df6SOr Gerlitz 				 struct mlx5e_tc_flow_parse_attr *parse_attr)
1235d79b6df6SOr Gerlitz {
1236d79b6df6SOr Gerlitz 	struct pedit_headers masks[__PEDIT_CMD_MAX], vals[__PEDIT_CMD_MAX], *cmd_masks;
1237d79b6df6SOr Gerlitz 	int nkeys, i, err = -EOPNOTSUPP;
1238d79b6df6SOr Gerlitz 	u32 mask, val, offset;
1239d79b6df6SOr Gerlitz 	u8 cmd, htype;
1240d79b6df6SOr Gerlitz 
1241d79b6df6SOr Gerlitz 	nkeys = tcf_pedit_nkeys(a);
1242d79b6df6SOr Gerlitz 
1243d79b6df6SOr Gerlitz 	memset(masks, 0, sizeof(struct pedit_headers) * __PEDIT_CMD_MAX);
1244d79b6df6SOr Gerlitz 	memset(vals,  0, sizeof(struct pedit_headers) * __PEDIT_CMD_MAX);
1245d79b6df6SOr Gerlitz 
1246d79b6df6SOr Gerlitz 	for (i = 0; i < nkeys; i++) {
1247d79b6df6SOr Gerlitz 		htype = tcf_pedit_htype(a, i);
1248d79b6df6SOr Gerlitz 		cmd = tcf_pedit_cmd(a, i);
1249d79b6df6SOr Gerlitz 		err = -EOPNOTSUPP; /* can't be all optimistic */
1250d79b6df6SOr Gerlitz 
1251d79b6df6SOr Gerlitz 		if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) {
1252d79b6df6SOr Gerlitz 			printk(KERN_WARNING "mlx5: legacy pedit isn't offloaded\n");
1253d79b6df6SOr Gerlitz 			goto out_err;
1254d79b6df6SOr Gerlitz 		}
1255d79b6df6SOr Gerlitz 
1256d79b6df6SOr Gerlitz 		if (cmd != TCA_PEDIT_KEY_EX_CMD_SET && cmd != TCA_PEDIT_KEY_EX_CMD_ADD) {
1257d79b6df6SOr Gerlitz 			printk(KERN_WARNING "mlx5: pedit cmd %d isn't offloaded\n", cmd);
1258d79b6df6SOr Gerlitz 			goto out_err;
1259d79b6df6SOr Gerlitz 		}
1260d79b6df6SOr Gerlitz 
1261d79b6df6SOr Gerlitz 		mask = tcf_pedit_mask(a, i);
1262d79b6df6SOr Gerlitz 		val = tcf_pedit_val(a, i);
1263d79b6df6SOr Gerlitz 		offset = tcf_pedit_offset(a, i);
1264d79b6df6SOr Gerlitz 
1265d79b6df6SOr Gerlitz 		err = set_pedit_val(htype, ~mask, val, offset, &masks[cmd], &vals[cmd]);
1266d79b6df6SOr Gerlitz 		if (err)
1267d79b6df6SOr Gerlitz 			goto out_err;
1268d79b6df6SOr Gerlitz 	}
1269d79b6df6SOr Gerlitz 
1270d79b6df6SOr Gerlitz 	err = alloc_mod_hdr_actions(priv, a, namespace, parse_attr);
1271d79b6df6SOr Gerlitz 	if (err)
1272d79b6df6SOr Gerlitz 		goto out_err;
1273d79b6df6SOr Gerlitz 
1274d79b6df6SOr Gerlitz 	err = offload_pedit_fields(masks, vals, parse_attr);
1275d79b6df6SOr Gerlitz 	if (err < 0)
1276d79b6df6SOr Gerlitz 		goto out_dealloc_parsed_actions;
1277d79b6df6SOr Gerlitz 
1278d79b6df6SOr Gerlitz 	for (cmd = 0; cmd < __PEDIT_CMD_MAX; cmd++) {
1279d79b6df6SOr Gerlitz 		cmd_masks = &masks[cmd];
1280d79b6df6SOr Gerlitz 		if (memcmp(cmd_masks, &zero_masks, sizeof(zero_masks))) {
1281d79b6df6SOr Gerlitz 			printk(KERN_WARNING "mlx5: attempt to offload an unsupported field (cmd %d)\n",
1282d79b6df6SOr Gerlitz 			       cmd);
1283d79b6df6SOr Gerlitz 			print_hex_dump(KERN_WARNING, "mask: ", DUMP_PREFIX_ADDRESS,
1284d79b6df6SOr Gerlitz 				       16, 1, cmd_masks, sizeof(zero_masks), true);
1285d79b6df6SOr Gerlitz 			err = -EOPNOTSUPP;
1286d79b6df6SOr Gerlitz 			goto out_dealloc_parsed_actions;
1287d79b6df6SOr Gerlitz 		}
1288d79b6df6SOr Gerlitz 	}
1289d79b6df6SOr Gerlitz 
1290d79b6df6SOr Gerlitz 	return 0;
1291d79b6df6SOr Gerlitz 
1292d79b6df6SOr Gerlitz out_dealloc_parsed_actions:
1293d79b6df6SOr Gerlitz 	kfree(parse_attr->mod_hdr_actions);
1294d79b6df6SOr Gerlitz out_err:
1295d79b6df6SOr Gerlitz 	return err;
1296d79b6df6SOr Gerlitz }
1297d79b6df6SOr Gerlitz 
129826c02749SOr Gerlitz static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 update_flags)
129926c02749SOr Gerlitz {
130026c02749SOr Gerlitz 	u32 prot_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR | TCA_CSUM_UPDATE_FLAG_TCP |
130126c02749SOr Gerlitz 			 TCA_CSUM_UPDATE_FLAG_UDP;
130226c02749SOr Gerlitz 
130326c02749SOr Gerlitz 	/*  The HW recalcs checksums only if re-writing headers */
130426c02749SOr Gerlitz 	if (!(action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) {
130526c02749SOr Gerlitz 		netdev_warn(priv->netdev,
130626c02749SOr Gerlitz 			    "TC csum action is only offloaded with pedit\n");
130726c02749SOr Gerlitz 		return false;
130826c02749SOr Gerlitz 	}
130926c02749SOr Gerlitz 
131026c02749SOr Gerlitz 	if (update_flags & ~prot_flags) {
131126c02749SOr Gerlitz 		netdev_warn(priv->netdev,
131226c02749SOr Gerlitz 			    "can't offload TC csum action for some header/s - flags %#x\n",
131326c02749SOr Gerlitz 			    update_flags);
131426c02749SOr Gerlitz 		return false;
131526c02749SOr Gerlitz 	}
131626c02749SOr Gerlitz 
131726c02749SOr Gerlitz 	return true;
131826c02749SOr Gerlitz }
131926c02749SOr Gerlitz 
13205c40348cSOr Gerlitz static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
1321aa0cbbaeSOr Gerlitz 				struct mlx5e_tc_flow_parse_attr *parse_attr,
1322aa0cbbaeSOr Gerlitz 				struct mlx5e_tc_flow *flow)
1323e3a2b7edSAmir Vadai {
1324aa0cbbaeSOr Gerlitz 	struct mlx5_nic_flow_attr *attr = flow->nic_attr;
1325e3a2b7edSAmir Vadai 	const struct tc_action *a;
132622dc13c8SWANG Cong 	LIST_HEAD(actions);
13272f4fe4caSOr Gerlitz 	int err;
1328e3a2b7edSAmir Vadai 
1329e3a2b7edSAmir Vadai 	if (tc_no_actions(exts))
1330e3a2b7edSAmir Vadai 		return -EINVAL;
1331e3a2b7edSAmir Vadai 
13323bc4b7bfSOr Gerlitz 	attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
13333bc4b7bfSOr Gerlitz 	attr->action = 0;
1334e3a2b7edSAmir Vadai 
133522dc13c8SWANG Cong 	tcf_exts_to_list(exts, &actions);
133622dc13c8SWANG Cong 	list_for_each_entry(a, &actions, list) {
1337e3a2b7edSAmir Vadai 		if (is_tcf_gact_shot(a)) {
13383bc4b7bfSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
1339aad7e08dSAmir Vadai 			if (MLX5_CAP_FLOWTABLE(priv->mdev,
1340aad7e08dSAmir Vadai 					       flow_table_properties_nic_receive.flow_counter))
13413bc4b7bfSOr Gerlitz 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
1342e3a2b7edSAmir Vadai 			continue;
1343e3a2b7edSAmir Vadai 		}
1344e3a2b7edSAmir Vadai 
13452f4fe4caSOr Gerlitz 		if (is_tcf_pedit(a)) {
13462f4fe4caSOr Gerlitz 			err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_KERNEL,
13472f4fe4caSOr Gerlitz 						    parse_attr);
13482f4fe4caSOr Gerlitz 			if (err)
13492f4fe4caSOr Gerlitz 				return err;
13502f4fe4caSOr Gerlitz 
13512f4fe4caSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
13522f4fe4caSOr Gerlitz 					MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
13532f4fe4caSOr Gerlitz 			continue;
13542f4fe4caSOr Gerlitz 		}
13552f4fe4caSOr Gerlitz 
135626c02749SOr Gerlitz 		if (is_tcf_csum(a)) {
135726c02749SOr Gerlitz 			if (csum_offload_supported(priv, attr->action,
135826c02749SOr Gerlitz 						   tcf_csum_update_flags(a)))
135926c02749SOr Gerlitz 				continue;
136026c02749SOr Gerlitz 
136126c02749SOr Gerlitz 			return -EOPNOTSUPP;
136226c02749SOr Gerlitz 		}
136326c02749SOr Gerlitz 
1364e3a2b7edSAmir Vadai 		if (is_tcf_skbedit_mark(a)) {
1365e3a2b7edSAmir Vadai 			u32 mark = tcf_skbedit_mark(a);
1366e3a2b7edSAmir Vadai 
1367e3a2b7edSAmir Vadai 			if (mark & ~MLX5E_TC_FLOW_ID_MASK) {
1368e3a2b7edSAmir Vadai 				netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n",
1369e3a2b7edSAmir Vadai 					    mark);
1370e3a2b7edSAmir Vadai 				return -EINVAL;
1371e3a2b7edSAmir Vadai 			}
1372e3a2b7edSAmir Vadai 
13733bc4b7bfSOr Gerlitz 			attr->flow_tag = mark;
13743bc4b7bfSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1375e3a2b7edSAmir Vadai 			continue;
1376e3a2b7edSAmir Vadai 		}
1377e3a2b7edSAmir Vadai 
1378e3a2b7edSAmir Vadai 		return -EINVAL;
1379e3a2b7edSAmir Vadai 	}
1380e3a2b7edSAmir Vadai 
1381e3a2b7edSAmir Vadai 	return 0;
1382e3a2b7edSAmir Vadai }
1383e3a2b7edSAmir Vadai 
138476f7444dSOr Gerlitz static inline int cmp_encap_info(struct ip_tunnel_key *a,
138576f7444dSOr Gerlitz 				 struct ip_tunnel_key *b)
1386a54e20b4SHadar Hen Zion {
1387a54e20b4SHadar Hen Zion 	return memcmp(a, b, sizeof(*a));
1388a54e20b4SHadar Hen Zion }
1389a54e20b4SHadar Hen Zion 
139076f7444dSOr Gerlitz static inline int hash_encap_info(struct ip_tunnel_key *key)
1391a54e20b4SHadar Hen Zion {
139276f7444dSOr Gerlitz 	return jhash(key, sizeof(*key), 0);
1393a54e20b4SHadar Hen Zion }
1394a54e20b4SHadar Hen Zion 
1395a54e20b4SHadar Hen Zion static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
1396a54e20b4SHadar Hen Zion 				   struct net_device *mirred_dev,
1397a54e20b4SHadar Hen Zion 				   struct net_device **out_dev,
1398a54e20b4SHadar Hen Zion 				   struct flowi4 *fl4,
1399a54e20b4SHadar Hen Zion 				   struct neighbour **out_n,
1400a54e20b4SHadar Hen Zion 				   int *out_ttl)
1401a54e20b4SHadar Hen Zion {
14023e621b19SHadar Hen Zion 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
1403a54e20b4SHadar Hen Zion 	struct rtable *rt;
1404a54e20b4SHadar Hen Zion 	struct neighbour *n = NULL;
1405a54e20b4SHadar Hen Zion 
1406a54e20b4SHadar Hen Zion #if IS_ENABLED(CONFIG_INET)
1407abeffce9SArnd Bergmann 	int ret;
1408abeffce9SArnd Bergmann 
1409a54e20b4SHadar Hen Zion 	rt = ip_route_output_key(dev_net(mirred_dev), fl4);
1410abeffce9SArnd Bergmann 	ret = PTR_ERR_OR_ZERO(rt);
1411abeffce9SArnd Bergmann 	if (ret)
1412abeffce9SArnd Bergmann 		return ret;
1413a54e20b4SHadar Hen Zion #else
1414a54e20b4SHadar Hen Zion 	return -EOPNOTSUPP;
1415a54e20b4SHadar Hen Zion #endif
14163e621b19SHadar Hen Zion 	/* if the egress device isn't on the same HW e-switch, we use the uplink */
14173e621b19SHadar Hen Zion 	if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev))
14183e621b19SHadar Hen Zion 		*out_dev = mlx5_eswitch_get_uplink_netdev(esw);
14193e621b19SHadar Hen Zion 	else
14203e621b19SHadar Hen Zion 		*out_dev = rt->dst.dev;
1421a54e20b4SHadar Hen Zion 
142275c33da8SOr Gerlitz 	*out_ttl = ip4_dst_hoplimit(&rt->dst);
1423a54e20b4SHadar Hen Zion 	n = dst_neigh_lookup(&rt->dst, &fl4->daddr);
1424a54e20b4SHadar Hen Zion 	ip_rt_put(rt);
1425a54e20b4SHadar Hen Zion 	if (!n)
1426a54e20b4SHadar Hen Zion 		return -ENOMEM;
1427a54e20b4SHadar Hen Zion 
1428a54e20b4SHadar Hen Zion 	*out_n = n;
1429a54e20b4SHadar Hen Zion 	return 0;
1430a54e20b4SHadar Hen Zion }
1431a54e20b4SHadar Hen Zion 
1432ce99f6b9SOr Gerlitz static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
1433ce99f6b9SOr Gerlitz 				   struct net_device *mirred_dev,
1434ce99f6b9SOr Gerlitz 				   struct net_device **out_dev,
1435ce99f6b9SOr Gerlitz 				   struct flowi6 *fl6,
1436ce99f6b9SOr Gerlitz 				   struct neighbour **out_n,
1437ce99f6b9SOr Gerlitz 				   int *out_ttl)
1438ce99f6b9SOr Gerlitz {
1439ce99f6b9SOr Gerlitz 	struct neighbour *n = NULL;
1440ce99f6b9SOr Gerlitz 	struct dst_entry *dst;
1441ce99f6b9SOr Gerlitz 
1442ce99f6b9SOr Gerlitz #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
1443ce99f6b9SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
1444ce99f6b9SOr Gerlitz 	int ret;
1445ce99f6b9SOr Gerlitz 
144608820528SPaul Blakey 	ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst,
144708820528SPaul Blakey 					 fl6);
144808820528SPaul Blakey 	if (ret < 0)
1449ce99f6b9SOr Gerlitz 		return ret;
1450ce99f6b9SOr Gerlitz 
1451ce99f6b9SOr Gerlitz 	*out_ttl = ip6_dst_hoplimit(dst);
1452ce99f6b9SOr Gerlitz 
1453ce99f6b9SOr Gerlitz 	/* if the egress device isn't on the same HW e-switch, we use the uplink */
1454ce99f6b9SOr Gerlitz 	if (!switchdev_port_same_parent_id(priv->netdev, dst->dev))
1455ce99f6b9SOr Gerlitz 		*out_dev = mlx5_eswitch_get_uplink_netdev(esw);
1456ce99f6b9SOr Gerlitz 	else
1457ce99f6b9SOr Gerlitz 		*out_dev = dst->dev;
1458ce99f6b9SOr Gerlitz #else
1459ce99f6b9SOr Gerlitz 	return -EOPNOTSUPP;
1460ce99f6b9SOr Gerlitz #endif
1461ce99f6b9SOr Gerlitz 
1462ce99f6b9SOr Gerlitz 	n = dst_neigh_lookup(dst, &fl6->daddr);
1463ce99f6b9SOr Gerlitz 	dst_release(dst);
1464ce99f6b9SOr Gerlitz 	if (!n)
1465ce99f6b9SOr Gerlitz 		return -ENOMEM;
1466ce99f6b9SOr Gerlitz 
1467ce99f6b9SOr Gerlitz 	*out_n = n;
1468ce99f6b9SOr Gerlitz 	return 0;
1469ce99f6b9SOr Gerlitz }
1470ce99f6b9SOr Gerlitz 
147132f3671fSOr Gerlitz static void gen_vxlan_header_ipv4(struct net_device *out_dev,
147232f3671fSOr Gerlitz 				  char buf[], int encap_size,
1473a54e20b4SHadar Hen Zion 				  unsigned char h_dest[ETH_ALEN],
1474a54e20b4SHadar Hen Zion 				  int ttl,
1475a54e20b4SHadar Hen Zion 				  __be32 daddr,
1476a54e20b4SHadar Hen Zion 				  __be32 saddr,
1477a54e20b4SHadar Hen Zion 				  __be16 udp_dst_port,
1478a54e20b4SHadar Hen Zion 				  __be32 vx_vni)
1479a54e20b4SHadar Hen Zion {
1480a54e20b4SHadar Hen Zion 	struct ethhdr *eth = (struct ethhdr *)buf;
1481a54e20b4SHadar Hen Zion 	struct iphdr  *ip = (struct iphdr *)((char *)eth + sizeof(struct ethhdr));
1482a54e20b4SHadar Hen Zion 	struct udphdr *udp = (struct udphdr *)((char *)ip + sizeof(struct iphdr));
1483a54e20b4SHadar Hen Zion 	struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
1484a54e20b4SHadar Hen Zion 
1485a54e20b4SHadar Hen Zion 	memset(buf, 0, encap_size);
1486a54e20b4SHadar Hen Zion 
1487a54e20b4SHadar Hen Zion 	ether_addr_copy(eth->h_dest, h_dest);
1488a54e20b4SHadar Hen Zion 	ether_addr_copy(eth->h_source, out_dev->dev_addr);
1489a54e20b4SHadar Hen Zion 	eth->h_proto = htons(ETH_P_IP);
1490a54e20b4SHadar Hen Zion 
1491a54e20b4SHadar Hen Zion 	ip->daddr = daddr;
1492a54e20b4SHadar Hen Zion 	ip->saddr = saddr;
1493a54e20b4SHadar Hen Zion 
1494a54e20b4SHadar Hen Zion 	ip->ttl = ttl;
1495a54e20b4SHadar Hen Zion 	ip->protocol = IPPROTO_UDP;
1496a54e20b4SHadar Hen Zion 	ip->version = 0x4;
1497a54e20b4SHadar Hen Zion 	ip->ihl = 0x5;
1498a54e20b4SHadar Hen Zion 
1499a54e20b4SHadar Hen Zion 	udp->dest = udp_dst_port;
1500a54e20b4SHadar Hen Zion 	vxh->vx_flags = VXLAN_HF_VNI;
1501a54e20b4SHadar Hen Zion 	vxh->vx_vni = vxlan_vni_field(vx_vni);
1502a54e20b4SHadar Hen Zion }
1503a54e20b4SHadar Hen Zion 
1504225aabafSOr Gerlitz static void gen_vxlan_header_ipv6(struct net_device *out_dev,
1505225aabafSOr Gerlitz 				  char buf[], int encap_size,
1506ce99f6b9SOr Gerlitz 				  unsigned char h_dest[ETH_ALEN],
1507ce99f6b9SOr Gerlitz 				  int ttl,
1508ce99f6b9SOr Gerlitz 				  struct in6_addr *daddr,
1509ce99f6b9SOr Gerlitz 				  struct in6_addr *saddr,
1510ce99f6b9SOr Gerlitz 				  __be16 udp_dst_port,
1511ce99f6b9SOr Gerlitz 				  __be32 vx_vni)
1512ce99f6b9SOr Gerlitz {
1513ce99f6b9SOr Gerlitz 	struct ethhdr *eth = (struct ethhdr *)buf;
1514ce99f6b9SOr Gerlitz 	struct ipv6hdr *ip6h = (struct ipv6hdr *)((char *)eth + sizeof(struct ethhdr));
1515ce99f6b9SOr Gerlitz 	struct udphdr *udp = (struct udphdr *)((char *)ip6h + sizeof(struct ipv6hdr));
1516ce99f6b9SOr Gerlitz 	struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
1517ce99f6b9SOr Gerlitz 
1518ce99f6b9SOr Gerlitz 	memset(buf, 0, encap_size);
1519ce99f6b9SOr Gerlitz 
1520ce99f6b9SOr Gerlitz 	ether_addr_copy(eth->h_dest, h_dest);
1521ce99f6b9SOr Gerlitz 	ether_addr_copy(eth->h_source, out_dev->dev_addr);
1522ce99f6b9SOr Gerlitz 	eth->h_proto = htons(ETH_P_IPV6);
1523ce99f6b9SOr Gerlitz 
1524ce99f6b9SOr Gerlitz 	ip6_flow_hdr(ip6h, 0, 0);
1525ce99f6b9SOr Gerlitz 	/* the HW fills up ipv6 payload len */
1526ce99f6b9SOr Gerlitz 	ip6h->nexthdr     = IPPROTO_UDP;
1527ce99f6b9SOr Gerlitz 	ip6h->hop_limit   = ttl;
1528ce99f6b9SOr Gerlitz 	ip6h->daddr	  = *daddr;
1529ce99f6b9SOr Gerlitz 	ip6h->saddr	  = *saddr;
1530ce99f6b9SOr Gerlitz 
1531ce99f6b9SOr Gerlitz 	udp->dest = udp_dst_port;
1532ce99f6b9SOr Gerlitz 	vxh->vx_flags = VXLAN_HF_VNI;
1533ce99f6b9SOr Gerlitz 	vxh->vx_vni = vxlan_vni_field(vx_vni);
1534ce99f6b9SOr Gerlitz }
1535ce99f6b9SOr Gerlitz 
1536a54e20b4SHadar Hen Zion static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
1537a54e20b4SHadar Hen Zion 					  struct net_device *mirred_dev,
15381a8552bdSHadar Hen Zion 					  struct mlx5e_encap_entry *e)
1539a54e20b4SHadar Hen Zion {
1540a54e20b4SHadar Hen Zion 	int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
154132f3671fSOr Gerlitz 	int ipv4_encap_size = ETH_HLEN + sizeof(struct iphdr) + VXLAN_HLEN;
154276f7444dSOr Gerlitz 	struct ip_tunnel_key *tun_key = &e->tun_info.key;
15431a8552bdSHadar Hen Zion 	struct net_device *out_dev;
1544a42485ebSOr Gerlitz 	struct neighbour *n = NULL;
1545a54e20b4SHadar Hen Zion 	struct flowi4 fl4 = {};
1546a54e20b4SHadar Hen Zion 	char *encap_header;
154732f3671fSOr Gerlitz 	int ttl, err;
1548033354d5SHadar Hen Zion 	u8 nud_state;
1549a54e20b4SHadar Hen Zion 
155032f3671fSOr Gerlitz 	if (max_encap_size < ipv4_encap_size) {
155132f3671fSOr Gerlitz 		mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
155232f3671fSOr Gerlitz 			       ipv4_encap_size, max_encap_size);
155332f3671fSOr Gerlitz 		return -EOPNOTSUPP;
155432f3671fSOr Gerlitz 	}
155532f3671fSOr Gerlitz 
155632f3671fSOr Gerlitz 	encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL);
1557a54e20b4SHadar Hen Zion 	if (!encap_header)
1558a54e20b4SHadar Hen Zion 		return -ENOMEM;
1559a54e20b4SHadar Hen Zion 
1560a54e20b4SHadar Hen Zion 	switch (e->tunnel_type) {
1561a54e20b4SHadar Hen Zion 	case MLX5_HEADER_TYPE_VXLAN:
1562a54e20b4SHadar Hen Zion 		fl4.flowi4_proto = IPPROTO_UDP;
156376f7444dSOr Gerlitz 		fl4.fl4_dport = tun_key->tp_dst;
1564a54e20b4SHadar Hen Zion 		break;
1565a54e20b4SHadar Hen Zion 	default:
1566a54e20b4SHadar Hen Zion 		err = -EOPNOTSUPP;
1567a54e20b4SHadar Hen Zion 		goto out;
1568a54e20b4SHadar Hen Zion 	}
15699a941117SOr Gerlitz 	fl4.flowi4_tos = tun_key->tos;
157076f7444dSOr Gerlitz 	fl4.daddr = tun_key->u.ipv4.dst;
15719a941117SOr Gerlitz 	fl4.saddr = tun_key->u.ipv4.src;
1572a54e20b4SHadar Hen Zion 
15731a8552bdSHadar Hen Zion 	err = mlx5e_route_lookup_ipv4(priv, mirred_dev, &out_dev,
15749a941117SOr Gerlitz 				      &fl4, &n, &ttl);
1575a54e20b4SHadar Hen Zion 	if (err)
1576a54e20b4SHadar Hen Zion 		goto out;
1577a54e20b4SHadar Hen Zion 
1578232c0013SHadar Hen Zion 	/* used by mlx5e_detach_encap to lookup a neigh hash table
1579232c0013SHadar Hen Zion 	 * entry in the neigh hash table when a user deletes a rule
1580232c0013SHadar Hen Zion 	 */
1581232c0013SHadar Hen Zion 	e->m_neigh.dev = n->dev;
1582f6dfb4c3SHadar Hen Zion 	e->m_neigh.family = n->ops->family;
1583232c0013SHadar Hen Zion 	memcpy(&e->m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
1584232c0013SHadar Hen Zion 	e->out_dev = out_dev;
1585232c0013SHadar Hen Zion 
1586232c0013SHadar Hen Zion 	/* It's importent to add the neigh to the hash table before checking
1587232c0013SHadar Hen Zion 	 * the neigh validity state. So if we'll get a notification, in case the
1588232c0013SHadar Hen Zion 	 * neigh changes it's validity state, we would find the relevant neigh
1589232c0013SHadar Hen Zion 	 * in the hash.
1590232c0013SHadar Hen Zion 	 */
1591232c0013SHadar Hen Zion 	err = mlx5e_rep_encap_entry_attach(netdev_priv(out_dev), e);
1592232c0013SHadar Hen Zion 	if (err)
1593232c0013SHadar Hen Zion 		goto out;
1594232c0013SHadar Hen Zion 
1595033354d5SHadar Hen Zion 	read_lock_bh(&n->lock);
1596033354d5SHadar Hen Zion 	nud_state = n->nud_state;
1597033354d5SHadar Hen Zion 	ether_addr_copy(e->h_dest, n->ha);
1598033354d5SHadar Hen Zion 	read_unlock_bh(&n->lock);
1599033354d5SHadar Hen Zion 
1600a54e20b4SHadar Hen Zion 	switch (e->tunnel_type) {
1601a54e20b4SHadar Hen Zion 	case MLX5_HEADER_TYPE_VXLAN:
16021a8552bdSHadar Hen Zion 		gen_vxlan_header_ipv4(out_dev, encap_header,
160332f3671fSOr Gerlitz 				      ipv4_encap_size, e->h_dest, ttl,
16049a941117SOr Gerlitz 				      fl4.daddr,
16059a941117SOr Gerlitz 				      fl4.saddr, tun_key->tp_dst,
160676f7444dSOr Gerlitz 				      tunnel_id_to_key32(tun_key->tun_id));
1607a54e20b4SHadar Hen Zion 		break;
1608a54e20b4SHadar Hen Zion 	default:
1609a54e20b4SHadar Hen Zion 		err = -EOPNOTSUPP;
1610232c0013SHadar Hen Zion 		goto destroy_neigh_entry;
1611232c0013SHadar Hen Zion 	}
1612232c0013SHadar Hen Zion 	e->encap_size = ipv4_encap_size;
1613232c0013SHadar Hen Zion 	e->encap_header = encap_header;
1614232c0013SHadar Hen Zion 
1615232c0013SHadar Hen Zion 	if (!(nud_state & NUD_VALID)) {
1616232c0013SHadar Hen Zion 		neigh_event_send(n, NULL);
161727902f08SWei Yongjun 		err = -EAGAIN;
161827902f08SWei Yongjun 		goto out;
1619a54e20b4SHadar Hen Zion 	}
1620a54e20b4SHadar Hen Zion 
1621a54e20b4SHadar Hen Zion 	err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
162232f3671fSOr Gerlitz 			       ipv4_encap_size, encap_header, &e->encap_id);
1623232c0013SHadar Hen Zion 	if (err)
1624232c0013SHadar Hen Zion 		goto destroy_neigh_entry;
1625232c0013SHadar Hen Zion 
1626232c0013SHadar Hen Zion 	e->flags |= MLX5_ENCAP_ENTRY_VALID;
1627f6dfb4c3SHadar Hen Zion 	mlx5e_rep_queue_neigh_stats_work(netdev_priv(out_dev));
1628a42485ebSOr Gerlitz 	neigh_release(n);
1629232c0013SHadar Hen Zion 	return err;
1630232c0013SHadar Hen Zion 
1631232c0013SHadar Hen Zion destroy_neigh_entry:
1632232c0013SHadar Hen Zion 	mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e);
1633232c0013SHadar Hen Zion out:
1634a54e20b4SHadar Hen Zion 	kfree(encap_header);
1635232c0013SHadar Hen Zion 	if (n)
1636232c0013SHadar Hen Zion 		neigh_release(n);
1637a54e20b4SHadar Hen Zion 	return err;
1638a54e20b4SHadar Hen Zion }
1639a54e20b4SHadar Hen Zion 
1640ce99f6b9SOr Gerlitz static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
1641ce99f6b9SOr Gerlitz 					  struct net_device *mirred_dev,
16421a8552bdSHadar Hen Zion 					  struct mlx5e_encap_entry *e)
1643ce99f6b9SOr Gerlitz {
1644ce99f6b9SOr Gerlitz 	int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
1645225aabafSOr Gerlitz 	int ipv6_encap_size = ETH_HLEN + sizeof(struct ipv6hdr) + VXLAN_HLEN;
1646ce99f6b9SOr Gerlitz 	struct ip_tunnel_key *tun_key = &e->tun_info.key;
16471a8552bdSHadar Hen Zion 	struct net_device *out_dev;
1648ce99f6b9SOr Gerlitz 	struct neighbour *n = NULL;
1649ce99f6b9SOr Gerlitz 	struct flowi6 fl6 = {};
1650ce99f6b9SOr Gerlitz 	char *encap_header;
1651225aabafSOr Gerlitz 	int err, ttl = 0;
1652033354d5SHadar Hen Zion 	u8 nud_state;
1653ce99f6b9SOr Gerlitz 
1654225aabafSOr Gerlitz 	if (max_encap_size < ipv6_encap_size) {
1655225aabafSOr Gerlitz 		mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
1656225aabafSOr Gerlitz 			       ipv6_encap_size, max_encap_size);
1657225aabafSOr Gerlitz 		return -EOPNOTSUPP;
1658225aabafSOr Gerlitz 	}
1659225aabafSOr Gerlitz 
1660225aabafSOr Gerlitz 	encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL);
1661ce99f6b9SOr Gerlitz 	if (!encap_header)
1662ce99f6b9SOr Gerlitz 		return -ENOMEM;
1663ce99f6b9SOr Gerlitz 
1664ce99f6b9SOr Gerlitz 	switch (e->tunnel_type) {
1665ce99f6b9SOr Gerlitz 	case MLX5_HEADER_TYPE_VXLAN:
1666ce99f6b9SOr Gerlitz 		fl6.flowi6_proto = IPPROTO_UDP;
1667ce99f6b9SOr Gerlitz 		fl6.fl6_dport = tun_key->tp_dst;
1668ce99f6b9SOr Gerlitz 		break;
1669ce99f6b9SOr Gerlitz 	default:
1670ce99f6b9SOr Gerlitz 		err = -EOPNOTSUPP;
1671ce99f6b9SOr Gerlitz 		goto out;
1672ce99f6b9SOr Gerlitz 	}
1673ce99f6b9SOr Gerlitz 
1674ce99f6b9SOr Gerlitz 	fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tun_key->tos), tun_key->label);
1675ce99f6b9SOr Gerlitz 	fl6.daddr = tun_key->u.ipv6.dst;
1676ce99f6b9SOr Gerlitz 	fl6.saddr = tun_key->u.ipv6.src;
1677ce99f6b9SOr Gerlitz 
16781a8552bdSHadar Hen Zion 	err = mlx5e_route_lookup_ipv6(priv, mirred_dev, &out_dev,
1679ce99f6b9SOr Gerlitz 				      &fl6, &n, &ttl);
1680ce99f6b9SOr Gerlitz 	if (err)
1681ce99f6b9SOr Gerlitz 		goto out;
1682ce99f6b9SOr Gerlitz 
1683232c0013SHadar Hen Zion 	/* used by mlx5e_detach_encap to lookup a neigh hash table
1684232c0013SHadar Hen Zion 	 * entry in the neigh hash table when a user deletes a rule
1685232c0013SHadar Hen Zion 	 */
1686232c0013SHadar Hen Zion 	e->m_neigh.dev = n->dev;
1687f6dfb4c3SHadar Hen Zion 	e->m_neigh.family = n->ops->family;
1688232c0013SHadar Hen Zion 	memcpy(&e->m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
1689232c0013SHadar Hen Zion 	e->out_dev = out_dev;
1690232c0013SHadar Hen Zion 
1691232c0013SHadar Hen Zion 	/* It's importent to add the neigh to the hash table before checking
1692232c0013SHadar Hen Zion 	 * the neigh validity state. So if we'll get a notification, in case the
1693232c0013SHadar Hen Zion 	 * neigh changes it's validity state, we would find the relevant neigh
1694232c0013SHadar Hen Zion 	 * in the hash.
1695232c0013SHadar Hen Zion 	 */
1696232c0013SHadar Hen Zion 	err = mlx5e_rep_encap_entry_attach(netdev_priv(out_dev), e);
1697232c0013SHadar Hen Zion 	if (err)
1698232c0013SHadar Hen Zion 		goto out;
1699232c0013SHadar Hen Zion 
1700033354d5SHadar Hen Zion 	read_lock_bh(&n->lock);
1701033354d5SHadar Hen Zion 	nud_state = n->nud_state;
1702033354d5SHadar Hen Zion 	ether_addr_copy(e->h_dest, n->ha);
1703033354d5SHadar Hen Zion 	read_unlock_bh(&n->lock);
1704033354d5SHadar Hen Zion 
1705ce99f6b9SOr Gerlitz 	switch (e->tunnel_type) {
1706ce99f6b9SOr Gerlitz 	case MLX5_HEADER_TYPE_VXLAN:
17071a8552bdSHadar Hen Zion 		gen_vxlan_header_ipv6(out_dev, encap_header,
1708225aabafSOr Gerlitz 				      ipv6_encap_size, e->h_dest, ttl,
1709ce99f6b9SOr Gerlitz 				      &fl6.daddr,
1710ce99f6b9SOr Gerlitz 				      &fl6.saddr, tun_key->tp_dst,
1711ce99f6b9SOr Gerlitz 				      tunnel_id_to_key32(tun_key->tun_id));
1712ce99f6b9SOr Gerlitz 		break;
1713ce99f6b9SOr Gerlitz 	default:
1714ce99f6b9SOr Gerlitz 		err = -EOPNOTSUPP;
1715232c0013SHadar Hen Zion 		goto destroy_neigh_entry;
1716232c0013SHadar Hen Zion 	}
1717232c0013SHadar Hen Zion 
1718232c0013SHadar Hen Zion 	e->encap_size = ipv6_encap_size;
1719232c0013SHadar Hen Zion 	e->encap_header = encap_header;
1720232c0013SHadar Hen Zion 
1721232c0013SHadar Hen Zion 	if (!(nud_state & NUD_VALID)) {
1722232c0013SHadar Hen Zion 		neigh_event_send(n, NULL);
172327902f08SWei Yongjun 		err = -EAGAIN;
172427902f08SWei Yongjun 		goto out;
1725ce99f6b9SOr Gerlitz 	}
1726ce99f6b9SOr Gerlitz 
1727ce99f6b9SOr Gerlitz 	err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
1728225aabafSOr Gerlitz 			       ipv6_encap_size, encap_header, &e->encap_id);
1729232c0013SHadar Hen Zion 	if (err)
1730232c0013SHadar Hen Zion 		goto destroy_neigh_entry;
1731232c0013SHadar Hen Zion 
1732232c0013SHadar Hen Zion 	e->flags |= MLX5_ENCAP_ENTRY_VALID;
1733f6dfb4c3SHadar Hen Zion 	mlx5e_rep_queue_neigh_stats_work(netdev_priv(out_dev));
1734ce99f6b9SOr Gerlitz 	neigh_release(n);
1735232c0013SHadar Hen Zion 	return err;
1736232c0013SHadar Hen Zion 
1737232c0013SHadar Hen Zion destroy_neigh_entry:
1738232c0013SHadar Hen Zion 	mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e);
1739232c0013SHadar Hen Zion out:
1740ce99f6b9SOr Gerlitz 	kfree(encap_header);
1741232c0013SHadar Hen Zion 	if (n)
1742232c0013SHadar Hen Zion 		neigh_release(n);
1743ce99f6b9SOr Gerlitz 	return err;
1744ce99f6b9SOr Gerlitz }
1745ce99f6b9SOr Gerlitz 
1746a54e20b4SHadar Hen Zion static int mlx5e_attach_encap(struct mlx5e_priv *priv,
1747a54e20b4SHadar Hen Zion 			      struct ip_tunnel_info *tun_info,
1748a54e20b4SHadar Hen Zion 			      struct net_device *mirred_dev,
174945247bf2SOr Gerlitz 			      struct net_device **encap_dev,
175045247bf2SOr Gerlitz 			      struct mlx5e_tc_flow *flow)
175103a9d11eSOr Gerlitz {
1752a54e20b4SHadar Hen Zion 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
17531ad9a00aSPaul Blakey 	struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw);
1754a54e20b4SHadar Hen Zion 	unsigned short family = ip_tunnel_info_af(tun_info);
175545247bf2SOr Gerlitz 	struct mlx5e_priv *up_priv = netdev_priv(up_dev);
175645247bf2SOr Gerlitz 	struct mlx5_esw_flow_attr *attr = flow->esw_attr;
1757a54e20b4SHadar Hen Zion 	struct ip_tunnel_key *key = &tun_info->key;
1758c1ae1152SOr Gerlitz 	struct mlx5e_encap_entry *e;
175945247bf2SOr Gerlitz 	int tunnel_type, err = 0;
1760a54e20b4SHadar Hen Zion 	uintptr_t hash_key;
1761a54e20b4SHadar Hen Zion 	bool found = false;
1762a54e20b4SHadar Hen Zion 
17632fcd82e9SOr Gerlitz 	/* udp dst port must be set */
1764a54e20b4SHadar Hen Zion 	if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst)))
17652fcd82e9SOr Gerlitz 		goto vxlan_encap_offload_err;
1766a54e20b4SHadar Hen Zion 
1767cd377663SOr Gerlitz 	/* setting udp src port isn't supported */
17682fcd82e9SOr Gerlitz 	if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) {
17692fcd82e9SOr Gerlitz vxlan_encap_offload_err:
17702fcd82e9SOr Gerlitz 		netdev_warn(priv->netdev,
17712fcd82e9SOr Gerlitz 			    "must set udp dst port and not set udp src port\n");
1772cd377663SOr Gerlitz 		return -EOPNOTSUPP;
17732fcd82e9SOr Gerlitz 	}
1774cd377663SOr Gerlitz 
17751ad9a00aSPaul Blakey 	if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->tp_dst)) &&
1776a54e20b4SHadar Hen Zion 	    MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) {
1777a54e20b4SHadar Hen Zion 		tunnel_type = MLX5_HEADER_TYPE_VXLAN;
1778a54e20b4SHadar Hen Zion 	} else {
17792fcd82e9SOr Gerlitz 		netdev_warn(priv->netdev,
17802fcd82e9SOr Gerlitz 			    "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst));
1781a54e20b4SHadar Hen Zion 		return -EOPNOTSUPP;
1782a54e20b4SHadar Hen Zion 	}
1783a54e20b4SHadar Hen Zion 
178476f7444dSOr Gerlitz 	hash_key = hash_encap_info(key);
1785a54e20b4SHadar Hen Zion 
1786a54e20b4SHadar Hen Zion 	hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
1787a54e20b4SHadar Hen Zion 				   encap_hlist, hash_key) {
178876f7444dSOr Gerlitz 		if (!cmp_encap_info(&e->tun_info.key, key)) {
1789a54e20b4SHadar Hen Zion 			found = true;
1790a54e20b4SHadar Hen Zion 			break;
1791a54e20b4SHadar Hen Zion 		}
1792a54e20b4SHadar Hen Zion 	}
1793a54e20b4SHadar Hen Zion 
179445247bf2SOr Gerlitz 	if (found)
179545247bf2SOr Gerlitz 		goto attach_flow;
1796a54e20b4SHadar Hen Zion 
1797a54e20b4SHadar Hen Zion 	e = kzalloc(sizeof(*e), GFP_KERNEL);
1798a54e20b4SHadar Hen Zion 	if (!e)
1799a54e20b4SHadar Hen Zion 		return -ENOMEM;
1800a54e20b4SHadar Hen Zion 
180176f7444dSOr Gerlitz 	e->tun_info = *tun_info;
1802a54e20b4SHadar Hen Zion 	e->tunnel_type = tunnel_type;
1803a54e20b4SHadar Hen Zion 	INIT_LIST_HEAD(&e->flows);
1804a54e20b4SHadar Hen Zion 
1805ce99f6b9SOr Gerlitz 	if (family == AF_INET)
18061a8552bdSHadar Hen Zion 		err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e);
1807ce99f6b9SOr Gerlitz 	else if (family == AF_INET6)
18081a8552bdSHadar Hen Zion 		err = mlx5e_create_encap_header_ipv6(priv, mirred_dev, e);
1809ce99f6b9SOr Gerlitz 
1810232c0013SHadar Hen Zion 	if (err && err != -EAGAIN)
1811a54e20b4SHadar Hen Zion 		goto out_err;
1812a54e20b4SHadar Hen Zion 
1813a54e20b4SHadar Hen Zion 	hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key);
1814a54e20b4SHadar Hen Zion 
181545247bf2SOr Gerlitz attach_flow:
181645247bf2SOr Gerlitz 	list_add(&flow->encap, &e->flows);
181745247bf2SOr Gerlitz 	*encap_dev = e->out_dev;
1818232c0013SHadar Hen Zion 	if (e->flags & MLX5_ENCAP_ENTRY_VALID)
181945247bf2SOr Gerlitz 		attr->encap_id = e->encap_id;
182045247bf2SOr Gerlitz 
1821232c0013SHadar Hen Zion 	return err;
1822a54e20b4SHadar Hen Zion 
1823a54e20b4SHadar Hen Zion out_err:
1824a54e20b4SHadar Hen Zion 	kfree(e);
1825a54e20b4SHadar Hen Zion 	return err;
1826a54e20b4SHadar Hen Zion }
1827a54e20b4SHadar Hen Zion 
1828a54e20b4SHadar Hen Zion static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
1829d7e75a32SOr Gerlitz 				struct mlx5e_tc_flow_parse_attr *parse_attr,
1830a54e20b4SHadar Hen Zion 				struct mlx5e_tc_flow *flow)
1831a54e20b4SHadar Hen Zion {
1832ecf5bb79SOr Gerlitz 	struct mlx5_esw_flow_attr *attr = flow->esw_attr;
18331d447a39SSaeed Mahameed 	struct mlx5e_rep_priv *rpriv = priv->ppriv;
1834a54e20b4SHadar Hen Zion 	struct ip_tunnel_info *info = NULL;
183503a9d11eSOr Gerlitz 	const struct tc_action *a;
183622dc13c8SWANG Cong 	LIST_HEAD(actions);
1837a54e20b4SHadar Hen Zion 	bool encap = false;
1838232c0013SHadar Hen Zion 	int err = 0;
183903a9d11eSOr Gerlitz 
184003a9d11eSOr Gerlitz 	if (tc_no_actions(exts))
184103a9d11eSOr Gerlitz 		return -EINVAL;
184203a9d11eSOr Gerlitz 
1843776b12b6SOr Gerlitz 	memset(attr, 0, sizeof(*attr));
18441d447a39SSaeed Mahameed 	attr->in_rep = rpriv->rep;
184503a9d11eSOr Gerlitz 
184622dc13c8SWANG Cong 	tcf_exts_to_list(exts, &actions);
184722dc13c8SWANG Cong 	list_for_each_entry(a, &actions, list) {
184803a9d11eSOr Gerlitz 		if (is_tcf_gact_shot(a)) {
18498b32580dSOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP |
185003a9d11eSOr Gerlitz 					MLX5_FLOW_CONTEXT_ACTION_COUNT;
185103a9d11eSOr Gerlitz 			continue;
185203a9d11eSOr Gerlitz 		}
185303a9d11eSOr Gerlitz 
1854d7e75a32SOr Gerlitz 		if (is_tcf_pedit(a)) {
1855d7e75a32SOr Gerlitz 			err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_FDB,
1856d7e75a32SOr Gerlitz 						    parse_attr);
1857d7e75a32SOr Gerlitz 			if (err)
1858d7e75a32SOr Gerlitz 				return err;
1859d7e75a32SOr Gerlitz 
1860d7e75a32SOr Gerlitz 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1861d7e75a32SOr Gerlitz 			continue;
1862d7e75a32SOr Gerlitz 		}
1863d7e75a32SOr Gerlitz 
186426c02749SOr Gerlitz 		if (is_tcf_csum(a)) {
186526c02749SOr Gerlitz 			if (csum_offload_supported(priv, attr->action,
186626c02749SOr Gerlitz 						   tcf_csum_update_flags(a)))
186726c02749SOr Gerlitz 				continue;
186826c02749SOr Gerlitz 
186926c02749SOr Gerlitz 			return -EOPNOTSUPP;
187026c02749SOr Gerlitz 		}
187126c02749SOr Gerlitz 
18725724b8b5SShmulik Ladkani 		if (is_tcf_mirred_egress_redirect(a)) {
187303a9d11eSOr Gerlitz 			int ifindex = tcf_mirred_ifindex(a);
187445247bf2SOr Gerlitz 			struct net_device *out_dev, *encap_dev = NULL;
187503a9d11eSOr Gerlitz 			struct mlx5e_priv *out_priv;
187603a9d11eSOr Gerlitz 
187703a9d11eSOr Gerlitz 			out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex);
187803a9d11eSOr Gerlitz 
1879a54e20b4SHadar Hen Zion 			if (switchdev_port_same_parent_id(priv->netdev,
1880a54e20b4SHadar Hen Zion 							  out_dev)) {
1881e37a79e5SMark Bloch 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1882e37a79e5SMark Bloch 					MLX5_FLOW_CONTEXT_ACTION_COUNT;
188303a9d11eSOr Gerlitz 				out_priv = netdev_priv(out_dev);
18841d447a39SSaeed Mahameed 				rpriv = out_priv->ppriv;
18851d447a39SSaeed Mahameed 				attr->out_rep = rpriv->rep;
1886a54e20b4SHadar Hen Zion 			} else if (encap) {
1887a54e20b4SHadar Hen Zion 				err = mlx5e_attach_encap(priv, info,
188845247bf2SOr Gerlitz 							 out_dev, &encap_dev, flow);
1889232c0013SHadar Hen Zion 				if (err && err != -EAGAIN)
1890a54e20b4SHadar Hen Zion 					return err;
1891a54e20b4SHadar Hen Zion 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP |
1892a54e20b4SHadar Hen Zion 					MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1893a54e20b4SHadar Hen Zion 					MLX5_FLOW_CONTEXT_ACTION_COUNT;
189445247bf2SOr Gerlitz 				out_priv = netdev_priv(encap_dev);
18951d447a39SSaeed Mahameed 				rpriv = out_priv->ppriv;
18961d447a39SSaeed Mahameed 				attr->out_rep = rpriv->rep;
1897232c0013SHadar Hen Zion 				attr->parse_attr = parse_attr;
1898a54e20b4SHadar Hen Zion 			} else {
1899a54e20b4SHadar Hen Zion 				pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
1900a54e20b4SHadar Hen Zion 				       priv->netdev->name, out_dev->name);
1901a54e20b4SHadar Hen Zion 				return -EINVAL;
1902a54e20b4SHadar Hen Zion 			}
1903a54e20b4SHadar Hen Zion 			continue;
1904a54e20b4SHadar Hen Zion 		}
1905a54e20b4SHadar Hen Zion 
1906a54e20b4SHadar Hen Zion 		if (is_tcf_tunnel_set(a)) {
1907a54e20b4SHadar Hen Zion 			info = tcf_tunnel_info(a);
1908a54e20b4SHadar Hen Zion 			if (info)
1909a54e20b4SHadar Hen Zion 				encap = true;
1910a54e20b4SHadar Hen Zion 			else
1911a54e20b4SHadar Hen Zion 				return -EOPNOTSUPP;
191203a9d11eSOr Gerlitz 			continue;
191303a9d11eSOr Gerlitz 		}
191403a9d11eSOr Gerlitz 
19158b32580dSOr Gerlitz 		if (is_tcf_vlan(a)) {
191609c91ddfSOr Gerlitz 			if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) {
19178b32580dSOr Gerlitz 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
191809c91ddfSOr Gerlitz 			} else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) {
19198b32580dSOr Gerlitz 				if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q))
19208b32580dSOr Gerlitz 					return -EOPNOTSUPP;
19218b32580dSOr Gerlitz 
19228b32580dSOr Gerlitz 				attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
19238b32580dSOr Gerlitz 				attr->vlan = tcf_vlan_push_vid(a);
192409c91ddfSOr Gerlitz 			} else { /* action is TCA_VLAN_ACT_MODIFY */
192509c91ddfSOr Gerlitz 				return -EOPNOTSUPP;
19268b32580dSOr Gerlitz 			}
19278b32580dSOr Gerlitz 			continue;
19288b32580dSOr Gerlitz 		}
19298b32580dSOr Gerlitz 
1930bbd00f7eSHadar Hen Zion 		if (is_tcf_tunnel_release(a)) {
1931bbd00f7eSHadar Hen Zion 			attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
1932bbd00f7eSHadar Hen Zion 			continue;
1933bbd00f7eSHadar Hen Zion 		}
1934bbd00f7eSHadar Hen Zion 
193503a9d11eSOr Gerlitz 		return -EINVAL;
193603a9d11eSOr Gerlitz 	}
1937232c0013SHadar Hen Zion 	return err;
193803a9d11eSOr Gerlitz }
193903a9d11eSOr Gerlitz 
1940e3a2b7edSAmir Vadai int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
1941e3a2b7edSAmir Vadai 			   struct tc_cls_flower_offload *f)
1942e3a2b7edSAmir Vadai {
1943adb4c123SOr Gerlitz 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
194417091853SOr Gerlitz 	struct mlx5e_tc_flow_parse_attr *parse_attr;
19453bc4b7bfSOr Gerlitz 	struct mlx5e_tc_table *tc = &priv->fs.tc;
19463bc4b7bfSOr Gerlitz 	struct mlx5e_tc_flow *flow;
19473bc4b7bfSOr Gerlitz 	int attr_size, err = 0;
194865ba8fb7SOr Gerlitz 	u8 flow_flags = 0;
1949e3a2b7edSAmir Vadai 
195065ba8fb7SOr Gerlitz 	if (esw && esw->mode == SRIOV_OFFLOADS) {
195165ba8fb7SOr Gerlitz 		flow_flags = MLX5E_TC_FLOW_ESWITCH;
195265ba8fb7SOr Gerlitz 		attr_size  = sizeof(struct mlx5_esw_flow_attr);
19533bc4b7bfSOr Gerlitz 	} else {
19543bc4b7bfSOr Gerlitz 		flow_flags = MLX5E_TC_FLOW_NIC;
19553bc4b7bfSOr Gerlitz 		attr_size  = sizeof(struct mlx5_nic_flow_attr);
195665ba8fb7SOr Gerlitz 	}
1957776b12b6SOr Gerlitz 
195865ba8fb7SOr Gerlitz 	flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL);
19591b9a07eeSLeon Romanovsky 	parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL);
196017091853SOr Gerlitz 	if (!parse_attr || !flow) {
1961e3a2b7edSAmir Vadai 		err = -ENOMEM;
1962e3a2b7edSAmir Vadai 		goto err_free;
1963e3a2b7edSAmir Vadai 	}
1964e3a2b7edSAmir Vadai 
1965e3a2b7edSAmir Vadai 	flow->cookie = f->cookie;
196665ba8fb7SOr Gerlitz 	flow->flags = flow_flags;
1967e3a2b7edSAmir Vadai 
196817091853SOr Gerlitz 	err = parse_cls_flower(priv, flow, &parse_attr->spec, f);
1969e3a2b7edSAmir Vadai 	if (err < 0)
1970e3a2b7edSAmir Vadai 		goto err_free;
1971e3a2b7edSAmir Vadai 
197265ba8fb7SOr Gerlitz 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
1973d7e75a32SOr Gerlitz 		err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow);
1974adb4c123SOr Gerlitz 		if (err < 0)
1975232c0013SHadar Hen Zion 			goto err_handle_encap_flow;
1976aa0cbbaeSOr Gerlitz 		flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow);
1977adb4c123SOr Gerlitz 	} else {
1978aa0cbbaeSOr Gerlitz 		err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow);
1979e3a2b7edSAmir Vadai 		if (err < 0)
1980e3a2b7edSAmir Vadai 			goto err_free;
1981aa0cbbaeSOr Gerlitz 		flow->rule = mlx5e_tc_add_nic_flow(priv, parse_attr, flow);
1982adb4c123SOr Gerlitz 	}
1983adb4c123SOr Gerlitz 
19845c40348cSOr Gerlitz 	if (IS_ERR(flow->rule)) {
19855c40348cSOr Gerlitz 		err = PTR_ERR(flow->rule);
1986aa0cbbaeSOr Gerlitz 		goto err_free;
19875c40348cSOr Gerlitz 	}
19885c40348cSOr Gerlitz 
19890b67a38fSHadar Hen Zion 	flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
1990e3a2b7edSAmir Vadai 	err = rhashtable_insert_fast(&tc->ht, &flow->node,
1991e3a2b7edSAmir Vadai 				     tc->ht_params);
1992e3a2b7edSAmir Vadai 	if (err)
19935c40348cSOr Gerlitz 		goto err_del_rule;
1994e3a2b7edSAmir Vadai 
1995232c0013SHadar Hen Zion 	if (flow->flags & MLX5E_TC_FLOW_ESWITCH &&
1996232c0013SHadar Hen Zion 	    !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP))
1997232c0013SHadar Hen Zion 		kvfree(parse_attr);
1998232c0013SHadar Hen Zion 	return err;
1999e3a2b7edSAmir Vadai 
20005c40348cSOr Gerlitz err_del_rule:
20015e86397aSOr Gerlitz 	mlx5e_tc_del_flow(priv, flow);
2002e3a2b7edSAmir Vadai 
2003232c0013SHadar Hen Zion err_handle_encap_flow:
2004232c0013SHadar Hen Zion 	if (err == -EAGAIN) {
2005232c0013SHadar Hen Zion 		err = rhashtable_insert_fast(&tc->ht, &flow->node,
2006232c0013SHadar Hen Zion 					     tc->ht_params);
2007232c0013SHadar Hen Zion 		if (err)
2008232c0013SHadar Hen Zion 			mlx5e_tc_del_flow(priv, flow);
2009232c0013SHadar Hen Zion 		else
2010232c0013SHadar Hen Zion 			return 0;
2011232c0013SHadar Hen Zion 	}
2012232c0013SHadar Hen Zion 
2013e3a2b7edSAmir Vadai err_free:
201417091853SOr Gerlitz 	kvfree(parse_attr);
2015232c0013SHadar Hen Zion 	kfree(flow);
2016e3a2b7edSAmir Vadai 	return err;
2017e3a2b7edSAmir Vadai }
2018e3a2b7edSAmir Vadai 
2019e3a2b7edSAmir Vadai int mlx5e_delete_flower(struct mlx5e_priv *priv,
2020e3a2b7edSAmir Vadai 			struct tc_cls_flower_offload *f)
2021e3a2b7edSAmir Vadai {
2022e3a2b7edSAmir Vadai 	struct mlx5e_tc_flow *flow;
2023acff797cSMaor Gottlieb 	struct mlx5e_tc_table *tc = &priv->fs.tc;
2024e3a2b7edSAmir Vadai 
2025e3a2b7edSAmir Vadai 	flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
2026e3a2b7edSAmir Vadai 				      tc->ht_params);
2027e3a2b7edSAmir Vadai 	if (!flow)
2028e3a2b7edSAmir Vadai 		return -EINVAL;
2029e3a2b7edSAmir Vadai 
2030e3a2b7edSAmir Vadai 	rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
2031e3a2b7edSAmir Vadai 
2032961e8979SRoi Dayan 	mlx5e_tc_del_flow(priv, flow);
2033e3a2b7edSAmir Vadai 
2034e3a2b7edSAmir Vadai 	kfree(flow);
2035e3a2b7edSAmir Vadai 
2036e3a2b7edSAmir Vadai 	return 0;
2037e3a2b7edSAmir Vadai }
2038e3a2b7edSAmir Vadai 
2039aad7e08dSAmir Vadai int mlx5e_stats_flower(struct mlx5e_priv *priv,
2040aad7e08dSAmir Vadai 		       struct tc_cls_flower_offload *f)
2041aad7e08dSAmir Vadai {
2042aad7e08dSAmir Vadai 	struct mlx5e_tc_table *tc = &priv->fs.tc;
2043aad7e08dSAmir Vadai 	struct mlx5e_tc_flow *flow;
2044aad7e08dSAmir Vadai 	struct mlx5_fc *counter;
2045aad7e08dSAmir Vadai 	u64 bytes;
2046aad7e08dSAmir Vadai 	u64 packets;
2047aad7e08dSAmir Vadai 	u64 lastuse;
2048aad7e08dSAmir Vadai 
2049aad7e08dSAmir Vadai 	flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
2050aad7e08dSAmir Vadai 				      tc->ht_params);
2051aad7e08dSAmir Vadai 	if (!flow)
2052aad7e08dSAmir Vadai 		return -EINVAL;
2053aad7e08dSAmir Vadai 
20540b67a38fSHadar Hen Zion 	if (!(flow->flags & MLX5E_TC_FLOW_OFFLOADED))
20550b67a38fSHadar Hen Zion 		return 0;
20560b67a38fSHadar Hen Zion 
2057aad7e08dSAmir Vadai 	counter = mlx5_flow_rule_counter(flow->rule);
2058aad7e08dSAmir Vadai 	if (!counter)
2059aad7e08dSAmir Vadai 		return 0;
2060aad7e08dSAmir Vadai 
2061aad7e08dSAmir Vadai 	mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
2062aad7e08dSAmir Vadai 
2063d897a638SJakub Kicinski 	tcf_exts_stats_update(f->exts, bytes, packets, lastuse);
2064fed06ee8SOr Gerlitz 
2065aad7e08dSAmir Vadai 	return 0;
2066aad7e08dSAmir Vadai }
2067aad7e08dSAmir Vadai 
2068e8f887acSAmir Vadai static const struct rhashtable_params mlx5e_tc_flow_ht_params = {
2069e8f887acSAmir Vadai 	.head_offset = offsetof(struct mlx5e_tc_flow, node),
2070e8f887acSAmir Vadai 	.key_offset = offsetof(struct mlx5e_tc_flow, cookie),
2071e8f887acSAmir Vadai 	.key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie),
2072e8f887acSAmir Vadai 	.automatic_shrinking = true,
2073e8f887acSAmir Vadai };
2074e8f887acSAmir Vadai 
2075e8f887acSAmir Vadai int mlx5e_tc_init(struct mlx5e_priv *priv)
2076e8f887acSAmir Vadai {
2077acff797cSMaor Gottlieb 	struct mlx5e_tc_table *tc = &priv->fs.tc;
2078e8f887acSAmir Vadai 
207911c9c548SOr Gerlitz 	hash_init(tc->mod_hdr_tbl);
208011c9c548SOr Gerlitz 
2081e8f887acSAmir Vadai 	tc->ht_params = mlx5e_tc_flow_ht_params;
2082e8f887acSAmir Vadai 	return rhashtable_init(&tc->ht, &tc->ht_params);
2083e8f887acSAmir Vadai }
2084e8f887acSAmir Vadai 
2085e8f887acSAmir Vadai static void _mlx5e_tc_del_flow(void *ptr, void *arg)
2086e8f887acSAmir Vadai {
2087e8f887acSAmir Vadai 	struct mlx5e_tc_flow *flow = ptr;
2088e8f887acSAmir Vadai 	struct mlx5e_priv *priv = arg;
2089e8f887acSAmir Vadai 
2090961e8979SRoi Dayan 	mlx5e_tc_del_flow(priv, flow);
2091e8f887acSAmir Vadai 	kfree(flow);
2092e8f887acSAmir Vadai }
2093e8f887acSAmir Vadai 
2094e8f887acSAmir Vadai void mlx5e_tc_cleanup(struct mlx5e_priv *priv)
2095e8f887acSAmir Vadai {
2096acff797cSMaor Gottlieb 	struct mlx5e_tc_table *tc = &priv->fs.tc;
2097e8f887acSAmir Vadai 
2098e8f887acSAmir Vadai 	rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv);
2099e8f887acSAmir Vadai 
2100acff797cSMaor Gottlieb 	if (!IS_ERR_OR_NULL(tc->t)) {
2101acff797cSMaor Gottlieb 		mlx5_destroy_flow_table(tc->t);
2102acff797cSMaor Gottlieb 		tc->t = NULL;
2103e8f887acSAmir Vadai 	}
2104e8f887acSAmir Vadai }
2105