Blame SOURCES/0229-netdrv-net-mlx5-E-Switch-Mark-miss-packets-with-new-.patch

d8f823
From d1efc329df288e6249c8652723b9e120b71cccec Mon Sep 17 00:00:00 2001
d8f823
From: Alaa Hleihel <ahleihel@redhat.com>
d8f823
Date: Tue, 19 May 2020 07:48:51 -0400
d8f823
Subject: [PATCH 229/312] [netdrv] net/mlx5: E-Switch, Mark miss packets with
d8f823
 new chain id mapping
d8f823
d8f823
Message-id: <20200519074934.6303-21-ahleihel@redhat.com>
d8f823
Patchwork-id: 310523
d8f823
Patchwork-instance: patchwork
d8f823
O-Subject: [RHEL8.3 BZ 1663246 20/63] net/mlx5: E-Switch, Mark miss packets with new chain id mapping
d8f823
Bugzilla: 1790219 1790218 1663246
d8f823
RH-Acked-by: Marcelo Leitner <mleitner@redhat.com>
d8f823
RH-Acked-by: Jarod Wilson <jarod@redhat.com>
d8f823
RH-Acked-by: John Linville <linville@redhat.com>
d8f823
RH-Acked-by: Ivan Vecera <ivecera@redhat.com>
d8f823
RH-Acked-by: Tony Camuso <tcamuso@redhat.com>
d8f823
RH-Acked-by: Kamal Heib <kheib@redhat.com>
d8f823
d8f823
Bugzilla: http://bugzilla.redhat.com/1663246
d8f823
Bugzilla: http://bugzilla.redhat.com/1790219
d8f823
Bugzilla: http://bugzilla.redhat.com/1790218
d8f823
Upstream: v5.7-rc1
d8f823
d8f823
commit 8f1e0b97cc708aa6a4d84b0431afc410feba00b6
d8f823
Author: Paul Blakey <paulb@mellanox.com>
d8f823
Date:   Sun Feb 16 12:01:28 2020 +0200
d8f823
d8f823
    net/mlx5: E-Switch, Mark miss packets with new chain id mapping
d8f823
d8f823
    Currently, if we miss in hardware after jumping to some chain,
d8f823
    we continue in chain 0 in software. This is wrong, and with the new
d8f823
    tc skb extension we can now restore the chain id on the skb, so
d8f823
    tc can continue with in the correct chain.
d8f823
d8f823
    To restore the chain id in software after a miss in hardware, we create
d8f823
    a register mapping from 32bit chain ids to 16bit of reg_c0 (that
d8f823
    survives loopback), to 32bit chain ids. We then mark packets that
d8f823
    miss on some chain with the current chain id mapping on their reg_c0
d8f823
    field. Using this mapping, we will support up to 64K concurrent
d8f823
    chains.
d8f823
d8f823
    This register survives loopback and gets to the CQE on flow_tag
d8f823
    via the eswitch restore rules.
d8f823
d8f823
    In next commit, we will reverse the mapping we got on the CQE
d8f823
    to a chain id and tell tc to continue in the sw chain where we
d8f823
    left off via the tc skb extension.
d8f823
d8f823
    Signed-off-by: Paul Blakey <paulb@mellanox.com>
d8f823
    Reviewed-by: Roi Dayan <roid@mellanox.com>
d8f823
    Reviewed-by: Oz Shlomo <ozsh@mellanox.com>
d8f823
    Reviewed-by: Mark Bloch <markb@mellanox.com>
d8f823
    Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
d8f823
d8f823
Signed-off-by: Alaa Hleihel <ahleihel@redhat.com>
d8f823
Signed-off-by: Frantisek Hrbata <fhrbata@redhat.com>
d8f823
---
d8f823
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c    |   8 ++
d8f823
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.h    |  12 ++
d8f823
 .../mellanox/mlx5/core/eswitch_offloads_chains.c   | 130 ++++++++++++++++++++-
d8f823
 .../mellanox/mlx5/core/eswitch_offloads_chains.h   |   4 +-
d8f823
 4 files changed, 150 insertions(+), 4 deletions(-)
d8f823
d8f823
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
d8f823
index 9d6ac9a1461b..a9142bde2dc6 100644
d8f823
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
d8f823
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
d8f823
@@ -153,6 +153,14 @@ struct mlx5e_tc_flow_parse_attr {
d8f823
 #define MLX5E_TC_TABLE_NUM_GROUPS 4
d8f823
 #define MLX5E_TC_TABLE_MAX_GROUP_SIZE BIT(16)
d8f823
 
d8f823
+struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
d8f823
+	[CHAIN_TO_REG] = {
d8f823
+		.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_0,
d8f823
+		.moffset = 0,
d8f823
+		.mlen = 2,
d8f823
+	},
d8f823
+};
d8f823
+
d8f823
 struct mlx5e_hairpin {
d8f823
 	struct mlx5_hairpin *pair;
d8f823
 
d8f823
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
d8f823
index 262cdb7b69b1..e2dbbae6d4d7 100644
d8f823
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
d8f823
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
d8f823
@@ -91,6 +91,18 @@ int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags);
d8f823
 
d8f823
 void mlx5e_tc_reoffload_flows_work(struct work_struct *work);
d8f823
 
d8f823
+enum mlx5e_tc_attr_to_reg {
d8f823
+	CHAIN_TO_REG,
d8f823
+};
d8f823
+
d8f823
+struct mlx5e_tc_attr_to_reg_mapping {
d8f823
+	int mfield; /* rewrite field */
d8f823
+	int moffset; /* offset of mfield */
d8f823
+	int mlen; /* bytes to rewrite/match */
d8f823
+};
d8f823
+
d8f823
+extern struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[];
d8f823
+
d8f823
 bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
d8f823
 				    struct net_device *out_dev);
d8f823
 
d8f823
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
d8f823
index 6ffc4f041b6c..12ca184cd795 100644
d8f823
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
d8f823
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
d8f823
@@ -6,14 +6,17 @@
d8f823
 #include <linux/mlx5/fs.h>
d8f823
 
d8f823
 #include "eswitch_offloads_chains.h"
d8f823
+#include "en/mapping.h"
d8f823
 #include "mlx5_core.h"
d8f823
 #include "fs_core.h"
d8f823
 #include "eswitch.h"
d8f823
 #include "en.h"
d8f823
+#include "en_tc.h"
d8f823
 
d8f823
 #define esw_chains_priv(esw) ((esw)->fdb_table.offloads.esw_chains_priv)
d8f823
 #define esw_chains_lock(esw) (esw_chains_priv(esw)->lock)
d8f823
 #define esw_chains_ht(esw) (esw_chains_priv(esw)->chains_ht)
d8f823
+#define esw_chains_mapping(esw) (esw_chains_priv(esw)->chains_mapping)
d8f823
 #define esw_prios_ht(esw) (esw_chains_priv(esw)->prios_ht)
d8f823
 #define fdb_pool_left(esw) (esw_chains_priv(esw)->fdb_left)
d8f823
 #define tc_slow_fdb(esw) ((esw)->fdb_table.offloads.slow_fdb)
d8f823
@@ -42,6 +45,7 @@ struct mlx5_esw_chains_priv {
d8f823
 	struct mutex lock;
d8f823
 
d8f823
 	struct mlx5_flow_table *tc_end_fdb;
d8f823
+	struct mapping_ctx *chains_mapping;
d8f823
 
d8f823
 	int fdb_left[ARRAY_SIZE(ESW_POOLS)];
d8f823
 };
d8f823
@@ -52,9 +56,12 @@ struct fdb_chain {
d8f823
 	u32 chain;
d8f823
 
d8f823
 	int ref;
d8f823
+	int id;
d8f823
 
d8f823
 	struct mlx5_eswitch *esw;
d8f823
 	struct list_head prios_list;
d8f823
+	struct mlx5_flow_handle *restore_rule;
d8f823
+	struct mlx5_modify_hdr *miss_modify_hdr;
d8f823
 };
d8f823
 
d8f823
 struct fdb_prio_key {
d8f823
@@ -258,6 +265,70 @@ mlx5_esw_chains_destroy_fdb_table(struct mlx5_eswitch *esw,
d8f823
 	mlx5_destroy_flow_table(fdb);
d8f823
 }
d8f823
 
d8f823
+static int
d8f823
+create_fdb_chain_restore(struct fdb_chain *fdb_chain)
d8f823
+{
d8f823
+	char modact[MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)];
d8f823
+	struct mlx5_eswitch *esw = fdb_chain->esw;
d8f823
+	struct mlx5_modify_hdr *mod_hdr;
d8f823
+	u32 index;
d8f823
+	int err;
d8f823
+
d8f823
+	if (fdb_chain->chain == mlx5_esw_chains_get_ft_chain(esw))
d8f823
+		return 0;
d8f823
+
d8f823
+	err = mapping_add(esw_chains_mapping(esw), &fdb_chain->chain, &index);
d8f823
+	if (err)
d8f823
+		return err;
d8f823
+	if (index == MLX5_FS_DEFAULT_FLOW_TAG) {
d8f823
+		/* we got the special default flow tag id, so we won't know
d8f823
+		 * if we actually marked the packet with the restore rule
d8f823
+		 * we create.
d8f823
+		 *
d8f823
+		 * This case isn't possible with MLX5_FS_DEFAULT_FLOW_TAG = 0.
d8f823
+		 */
d8f823
+		err = mapping_add(esw_chains_mapping(esw),
d8f823
+				  &fdb_chain->chain, &index);
d8f823
+		mapping_remove(esw_chains_mapping(esw),
d8f823
+			       MLX5_FS_DEFAULT_FLOW_TAG);
d8f823
+		if (err)
d8f823
+			return err;
d8f823
+	}
d8f823
+
d8f823
+	fdb_chain->id = index;
d8f823
+
d8f823
+	MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
d8f823
+	MLX5_SET(set_action_in, modact, field,
d8f823
+		 mlx5e_tc_attr_to_reg_mappings[CHAIN_TO_REG].mfield);
d8f823
+	MLX5_SET(set_action_in, modact, offset,
d8f823
+		 mlx5e_tc_attr_to_reg_mappings[CHAIN_TO_REG].moffset * 8);
d8f823
+	MLX5_SET(set_action_in, modact, length,
d8f823
+		 mlx5e_tc_attr_to_reg_mappings[CHAIN_TO_REG].mlen * 8);
d8f823
+	MLX5_SET(set_action_in, modact, data, fdb_chain->id);
d8f823
+	mod_hdr = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_FDB,
d8f823
+					   1, modact);
d8f823
+	if (IS_ERR(mod_hdr)) {
d8f823
+		err = PTR_ERR(mod_hdr);
d8f823
+		goto err_mod_hdr;
d8f823
+	}
d8f823
+	fdb_chain->miss_modify_hdr = mod_hdr;
d8f823
+
d8f823
+	fdb_chain->restore_rule = esw_add_restore_rule(esw, fdb_chain->id);
d8f823
+	if (IS_ERR(fdb_chain->restore_rule)) {
d8f823
+		err = PTR_ERR(fdb_chain->restore_rule);
d8f823
+		goto err_rule;
d8f823
+	}
d8f823
+
d8f823
+	return 0;
d8f823
+
d8f823
+err_rule:
d8f823
+	mlx5_modify_header_dealloc(esw->dev, fdb_chain->miss_modify_hdr);
d8f823
+err_mod_hdr:
d8f823
+	/* Datapath can't find this mapping, so we can safely remove it */
d8f823
+	mapping_remove(esw_chains_mapping(esw), fdb_chain->id);
d8f823
+	return err;
d8f823
+}
d8f823
+
d8f823
 static struct fdb_chain *
d8f823
 mlx5_esw_chains_create_fdb_chain(struct mlx5_eswitch *esw, u32 chain)
d8f823
 {
d8f823
@@ -272,6 +343,10 @@ mlx5_esw_chains_create_fdb_chain(struct mlx5_eswitch *esw, u32 chain)
d8f823
 	fdb_chain->chain = chain;
d8f823
 	INIT_LIST_HEAD(&fdb_chain->prios_list);
d8f823
 
d8f823
+	err = create_fdb_chain_restore(fdb_chain);
d8f823
+	if (err)
d8f823
+		goto err_restore;
d8f823
+
d8f823
 	err = rhashtable_insert_fast(&esw_chains_ht(esw), &fdb_chain->node,
d8f823
 				     chain_params);
d8f823
 	if (err)
d8f823
@@ -280,6 +355,12 @@ mlx5_esw_chains_create_fdb_chain(struct mlx5_eswitch *esw, u32 chain)
d8f823
 	return fdb_chain;
d8f823
 
d8f823
 err_insert:
d8f823
+	if (fdb_chain->chain != mlx5_esw_chains_get_ft_chain(esw)) {
d8f823
+		mlx5_del_flow_rules(fdb_chain->restore_rule);
d8f823
+		mlx5_modify_header_dealloc(esw->dev,
d8f823
+					   fdb_chain->miss_modify_hdr);
d8f823
+	}
d8f823
+err_restore:
d8f823
 	kvfree(fdb_chain);
d8f823
 	return ERR_PTR(err);
d8f823
 }
d8f823
@@ -291,6 +372,15 @@ mlx5_esw_chains_destroy_fdb_chain(struct fdb_chain *fdb_chain)
d8f823
 
d8f823
 	rhashtable_remove_fast(&esw_chains_ht(esw), &fdb_chain->node,
d8f823
 			       chain_params);
d8f823
+
d8f823
+	if (fdb_chain->chain != mlx5_esw_chains_get_ft_chain(esw)) {
d8f823
+		mlx5_del_flow_rules(fdb_chain->restore_rule);
d8f823
+		mlx5_modify_header_dealloc(esw->dev,
d8f823
+					   fdb_chain->miss_modify_hdr);
d8f823
+
d8f823
+		mapping_remove(esw_chains_mapping(esw), fdb_chain->id);
d8f823
+	}
d8f823
+
d8f823
 	kvfree(fdb_chain);
d8f823
 }
d8f823
 
d8f823
@@ -313,10 +403,12 @@ mlx5_esw_chains_get_fdb_chain(struct mlx5_eswitch *esw, u32 chain)
d8f823
 }
d8f823
 
d8f823
 static struct mlx5_flow_handle *
d8f823
-mlx5_esw_chains_add_miss_rule(struct mlx5_flow_table *fdb,
d8f823
+mlx5_esw_chains_add_miss_rule(struct fdb_chain *fdb_chain,
d8f823
+			      struct mlx5_flow_table *fdb,
d8f823
 			      struct mlx5_flow_table *next_fdb)
d8f823
 {
d8f823
 	static const struct mlx5_flow_spec spec = {};
d8f823
+	struct mlx5_eswitch *esw = fdb_chain->esw;
d8f823
 	struct mlx5_flow_destination dest = {};
d8f823
 	struct mlx5_flow_act act = {};
d8f823
 
d8f823
@@ -325,6 +417,11 @@ mlx5_esw_chains_add_miss_rule(struct mlx5_flow_table *fdb,
d8f823
 	dest.type  = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
d8f823
 	dest.ft = next_fdb;
d8f823
 
d8f823
+	if (fdb_chain->chain != mlx5_esw_chains_get_ft_chain(esw)) {
d8f823
+		act.modify_hdr = fdb_chain->miss_modify_hdr;
d8f823
+		act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
d8f823
+	}
d8f823
+
d8f823
 	return mlx5_add_flow_rules(fdb, &spec, &act, &dest, 1);
d8f823
 }
d8f823
 
d8f823
@@ -348,7 +445,8 @@ mlx5_esw_chains_update_prio_prevs(struct fdb_prio *fdb_prio,
d8f823
 	list_for_each_entry_continue_reverse(pos,
d8f823
 					     &fdb_chain->prios_list,
d8f823
 					     list) {
d8f823
-		miss_rules[n] = mlx5_esw_chains_add_miss_rule(pos->fdb,
d8f823
+		miss_rules[n] = mlx5_esw_chains_add_miss_rule(fdb_chain,
d8f823
+							      pos->fdb,
d8f823
 							      next_fdb);
d8f823
 		if (IS_ERR(miss_rules[n])) {
d8f823
 			err = PTR_ERR(miss_rules[n]);
d8f823
@@ -462,7 +560,7 @@ mlx5_esw_chains_create_fdb_prio(struct mlx5_eswitch *esw,
d8f823
 	}
d8f823
 
d8f823
 	/* Add miss rule to next_fdb */
d8f823
-	miss_rule = mlx5_esw_chains_add_miss_rule(fdb, next_fdb);
d8f823
+	miss_rule = mlx5_esw_chains_add_miss_rule(fdb_chain, fdb, next_fdb);
d8f823
 	if (IS_ERR(miss_rule)) {
d8f823
 		err = PTR_ERR(miss_rule);
d8f823
 		goto err_miss_rule;
d8f823
@@ -627,6 +725,7 @@ mlx5_esw_chains_init(struct mlx5_eswitch *esw)
d8f823
 	struct mlx5_esw_chains_priv *chains_priv;
d8f823
 	struct mlx5_core_dev *dev = esw->dev;
d8f823
 	u32 max_flow_counter, fdb_max;
d8f823
+	struct mapping_ctx *mapping;
d8f823
 	int err;
d8f823
 
d8f823
 	chains_priv = kzalloc(sizeof(*chains_priv), GFP_KERNEL);
d8f823
@@ -663,10 +762,20 @@ mlx5_esw_chains_init(struct mlx5_eswitch *esw)
d8f823
 	if (err)
d8f823
 		goto init_prios_ht_err;
d8f823
 
d8f823
+	mapping = mapping_create(sizeof(u32), esw_get_max_restore_tag(esw),
d8f823
+				 true);
d8f823
+	if (IS_ERR(mapping)) {
d8f823
+		err = PTR_ERR(mapping);
d8f823
+		goto mapping_err;
d8f823
+	}
d8f823
+	esw_chains_mapping(esw) = mapping;
d8f823
+
d8f823
 	mutex_init(&esw_chains_lock(esw));
d8f823
 
d8f823
 	return 0;
d8f823
 
d8f823
+mapping_err:
d8f823
+	rhashtable_destroy(&esw_prios_ht(esw));
d8f823
 init_prios_ht_err:
d8f823
 	rhashtable_destroy(&esw_chains_ht(esw));
d8f823
 init_chains_ht_err:
d8f823
@@ -678,6 +787,7 @@ static void
d8f823
 mlx5_esw_chains_cleanup(struct mlx5_eswitch *esw)
d8f823
 {
d8f823
 	mutex_destroy(&esw_chains_lock(esw));
d8f823
+	mapping_destroy(esw_chains_mapping(esw));
d8f823
 	rhashtable_destroy(&esw_prios_ht(esw));
d8f823
 	rhashtable_destroy(&esw_chains_ht(esw));
d8f823
 
d8f823
@@ -756,3 +866,17 @@ mlx5_esw_chains_destroy(struct mlx5_eswitch *esw)
d8f823
 	mlx5_esw_chains_close(esw);
d8f823
 	mlx5_esw_chains_cleanup(esw);
d8f823
 }
d8f823
+
d8f823
+int mlx5_eswitch_get_chain_for_tag(struct mlx5_eswitch *esw, u32 tag,
d8f823
+				   u32 *chain)
d8f823
+{
d8f823
+	int err;
d8f823
+
d8f823
+	err = mapping_find(esw_chains_mapping(esw), tag, chain);
d8f823
+	if (err) {
d8f823
+		esw_warn(esw->dev, "Can't find chain for tag: %d\n", tag);
d8f823
+		return -ENOENT;
d8f823
+	}
d8f823
+
d8f823
+	return 0;
d8f823
+}
d8f823
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.h
d8f823
index 4ae2baf2a7a1..e806d8de868e 100644
d8f823
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.h
d8f823
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.h
d8f823
@@ -28,5 +28,7 @@ mlx5_esw_chains_get_tc_end_ft(struct mlx5_eswitch *esw);
d8f823
 int mlx5_esw_chains_create(struct mlx5_eswitch *esw);
d8f823
 void mlx5_esw_chains_destroy(struct mlx5_eswitch *esw);
d8f823
 
d8f823
-#endif /* __ML5_ESW_CHAINS_H__ */
d8f823
+int
d8f823
+mlx5_eswitch_get_chain_for_tag(struct mlx5_eswitch *esw, u32 tag, u32 *chain);
d8f823
 
d8f823
+#endif /* __ML5_ESW_CHAINS_H__ */
d8f823
-- 
d8f823
2.13.6
d8f823