You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
436 lines
13 KiB
436 lines
13 KiB
From 1dc76baa2155965c13e6d9c5def7a34fe5d91430 Mon Sep 17 00:00:00 2001
|
|
From: Alaa Hleihel <ahleihel@redhat.com>
|
|
Date: Tue, 19 May 2020 07:48:38 -0400
|
|
Subject: [PATCH 217/312] [netdrv] net/mlx5e: Eswitch, Use per vport tables for
|
|
mirroring
|
|
|
|
Message-id: <20200519074934.6303-8-ahleihel@redhat.com>
|
|
Patchwork-id: 310511
|
|
Patchwork-instance: patchwork
|
|
O-Subject: [RHEL8.3 BZ 1663246 07/63] net/mlx5e: Eswitch, Use per vport tables for mirroring
|
|
Bugzilla: 1663246
|
|
RH-Acked-by: Marcelo Leitner <mleitner@redhat.com>
|
|
RH-Acked-by: Jarod Wilson <jarod@redhat.com>
|
|
RH-Acked-by: John Linville <linville@redhat.com>
|
|
RH-Acked-by: Ivan Vecera <ivecera@redhat.com>
|
|
RH-Acked-by: Tony Camuso <tcamuso@redhat.com>
|
|
RH-Acked-by: Kamal Heib <kheib@redhat.com>
|
|
|
|
Bugzilla: http://bugzilla.redhat.com/1663246
|
|
Upstream: v5.7-rc1
|
|
|
|
commit 96e326878fa5e2727d14e9a23644119374619010
|
|
Author: Eli Cohen <eli@mellanox.com>
|
|
Date: Tue Jan 14 17:30:41 2020 +0200
|
|
|
|
net/mlx5e: Eswitch, Use per vport tables for mirroring
|
|
|
|
When using port mirroring, we forward the traffic to another table and
|
|
use that table to forward to the mirrored vport. Since the hardware
|
|
loses the values of reg c, and in particular reg c0, we fail the match
|
|
on the input vport which previously existed in reg c0. To overcome this
|
|
situation, we use a set of per vport tables, positioned at the lowest
|
|
priority, and forward traffic to those tables. Since these tables are
|
|
per vport, we can avoid matching on reg c0.
|
|
|
|
Fixes: c01cfd0f1115 ("net/mlx5: E-Switch, Add match on vport metadata for rule in fast path")
|
|
Signed-off-by: Eli Cohen <eli@mellanox.com>
|
|
Reviewed-by: Mark Bloch <markb@mellanox.com>
|
|
Reviewed-by: Paul Blakey <paulb@mellanox.com>
|
|
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
|
|
|
|
Signed-off-by: Alaa Hleihel <ahleihel@redhat.com>
|
|
Signed-off-by: Frantisek Hrbata <fhrbata@redhat.com>
|
|
---
|
|
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 10 +
|
|
.../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 206 ++++++++++++++++++++-
|
|
.../mellanox/mlx5/core/eswitch_offloads_chains.c | 11 +-
|
|
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 11 ++
|
|
include/linux/mlx5/fs.h | 1 +
|
|
5 files changed, 221 insertions(+), 18 deletions(-)
|
|
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
|
|
index dd7b9a96045c..255838c9ae5d 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
|
|
@@ -49,6 +49,7 @@
|
|
|
|
/* The index of the last real chain (FT) + 1 as chain zero is valid as well */
|
|
#define FDB_NUM_CHAINS (FDB_FT_CHAIN + 1)
|
|
+#define ESW_OFFLOADS_NUM_GROUPS 4
|
|
|
|
#define FDB_TC_MAX_PRIO 16
|
|
#define FDB_TC_LEVELS_PER_PRIO 2
|
|
@@ -206,6 +207,12 @@ struct mlx5_eswitch_fdb {
|
|
|
|
#ifndef __GENKSYMS__
|
|
struct mlx5_esw_chains_priv *esw_chains_priv;
|
|
+ struct {
|
|
+ DECLARE_HASHTABLE(table, 8);
|
|
+ /* Protects vports.table */
|
|
+ struct mutex lock;
|
|
+ } vports;
|
|
+
|
|
#else
|
|
struct {
|
|
struct mlx5_flow_table *fdb;
|
|
@@ -661,6 +668,9 @@ void
|
|
esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw,
|
|
struct mlx5_vport *vport);
|
|
|
|
+int mlx5_esw_vport_tbl_get(struct mlx5_eswitch *esw);
|
|
+void mlx5_esw_vport_tbl_put(struct mlx5_eswitch *esw);
|
|
+
|
|
#else /* CONFIG_MLX5_ESWITCH */
|
|
/* eswitch API stubs */
|
|
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
index 7c33ce7ec074..8b7a2b095ec3 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
@@ -50,6 +50,179 @@
|
|
#define MLX5_ESW_MISS_FLOWS (2)
|
|
#define UPLINK_REP_INDEX 0
|
|
|
|
+/* Per vport tables */
|
|
+
|
|
+#define MLX5_ESW_VPORT_TABLE_SIZE 128
|
|
+
|
|
+/* This struct is used as a key to the hash table and we need it to be packed
|
|
+ * so hash result is consistent
|
|
+ */
|
|
+struct mlx5_vport_key {
|
|
+ u32 chain;
|
|
+ u16 prio;
|
|
+ u16 vport;
|
|
+ u16 vhca_id;
|
|
+} __packed;
|
|
+
|
|
+struct mlx5_vport_table {
|
|
+ struct hlist_node hlist;
|
|
+ struct mlx5_flow_table *fdb;
|
|
+ u32 num_rules;
|
|
+ struct mlx5_vport_key key;
|
|
+};
|
|
+
|
|
+static struct mlx5_flow_table *
|
|
+esw_vport_tbl_create(struct mlx5_eswitch *esw, struct mlx5_flow_namespace *ns)
|
|
+{
|
|
+ struct mlx5_flow_table_attr ft_attr = {};
|
|
+ struct mlx5_flow_table *fdb;
|
|
+
|
|
+ ft_attr.autogroup.max_num_groups = ESW_OFFLOADS_NUM_GROUPS;
|
|
+ ft_attr.max_fte = MLX5_ESW_VPORT_TABLE_SIZE;
|
|
+ ft_attr.prio = FDB_PER_VPORT;
|
|
+ fdb = mlx5_create_auto_grouped_flow_table_attr_(ns, &ft_attr);
|
|
+ if (IS_ERR(fdb)) {
|
|
+ esw_warn(esw->dev, "Failed to create per vport FDB Table err %ld\n",
|
|
+ PTR_ERR(fdb));
|
|
+ }
|
|
+
|
|
+ return fdb;
|
|
+}
|
|
+
|
|
+static u32 flow_attr_to_vport_key(struct mlx5_eswitch *esw,
|
|
+ struct mlx5_esw_flow_attr *attr,
|
|
+ struct mlx5_vport_key *key)
|
|
+{
|
|
+ key->vport = attr->in_rep->vport;
|
|
+ key->chain = attr->chain;
|
|
+ key->prio = attr->prio;
|
|
+ key->vhca_id = MLX5_CAP_GEN(esw->dev, vhca_id);
|
|
+ return jhash(key, sizeof(*key), 0);
|
|
+}
|
|
+
|
|
+/* caller must hold vports.lock */
|
|
+static struct mlx5_vport_table *
|
|
+esw_vport_tbl_lookup(struct mlx5_eswitch *esw, struct mlx5_vport_key *skey, u32 key)
|
|
+{
|
|
+ struct mlx5_vport_table *e;
|
|
+
|
|
+ hash_for_each_possible(esw->fdb_table.offloads.vports.table, e, hlist, key)
|
|
+ if (!memcmp(&e->key, skey, sizeof(*skey)))
|
|
+ return e;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+esw_vport_tbl_put(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr)
|
|
+{
|
|
+ struct mlx5_vport_table *e;
|
|
+ struct mlx5_vport_key key;
|
|
+ u32 hkey;
|
|
+
|
|
+ mutex_lock(&esw->fdb_table.offloads.vports.lock);
|
|
+ hkey = flow_attr_to_vport_key(esw, attr, &key);
|
|
+ e = esw_vport_tbl_lookup(esw, &key, hkey);
|
|
+ if (!e || --e->num_rules)
|
|
+ goto out;
|
|
+
|
|
+ hash_del(&e->hlist);
|
|
+ mlx5_destroy_flow_table(e->fdb);
|
|
+ kfree(e);
|
|
+out:
|
|
+ mutex_unlock(&esw->fdb_table.offloads.vports.lock);
|
|
+}
|
|
+
|
|
+static struct mlx5_flow_table *
|
|
+esw_vport_tbl_get(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr)
|
|
+{
|
|
+ struct mlx5_core_dev *dev = esw->dev;
|
|
+ struct mlx5_flow_namespace *ns;
|
|
+ struct mlx5_flow_table *fdb;
|
|
+ struct mlx5_vport_table *e;
|
|
+ struct mlx5_vport_key skey;
|
|
+ u32 hkey;
|
|
+
|
|
+ mutex_lock(&esw->fdb_table.offloads.vports.lock);
|
|
+ hkey = flow_attr_to_vport_key(esw, attr, &skey);
|
|
+ e = esw_vport_tbl_lookup(esw, &skey, hkey);
|
|
+ if (e) {
|
|
+ e->num_rules++;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
|
|
+ if (!e) {
|
|
+ fdb = ERR_PTR(-ENOMEM);
|
|
+ goto err_alloc;
|
|
+ }
|
|
+
|
|
+ ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
|
|
+ if (!ns) {
|
|
+ esw_warn(dev, "Failed to get FDB namespace\n");
|
|
+ fdb = ERR_PTR(-ENOENT);
|
|
+ goto err_ns;
|
|
+ }
|
|
+
|
|
+ fdb = esw_vport_tbl_create(esw, ns);
|
|
+ if (IS_ERR(fdb))
|
|
+ goto err_ns;
|
|
+
|
|
+ e->fdb = fdb;
|
|
+ e->num_rules = 1;
|
|
+ e->key = skey;
|
|
+ hash_add(esw->fdb_table.offloads.vports.table, &e->hlist, hkey);
|
|
+out:
|
|
+ mutex_unlock(&esw->fdb_table.offloads.vports.lock);
|
|
+ return e->fdb;
|
|
+
|
|
+err_ns:
|
|
+ kfree(e);
|
|
+err_alloc:
|
|
+ mutex_unlock(&esw->fdb_table.offloads.vports.lock);
|
|
+ return fdb;
|
|
+}
|
|
+
|
|
+int mlx5_esw_vport_tbl_get(struct mlx5_eswitch *esw)
|
|
+{
|
|
+ struct mlx5_esw_flow_attr attr = {};
|
|
+ struct mlx5_eswitch_rep rep = {};
|
|
+ struct mlx5_flow_table *fdb;
|
|
+ struct mlx5_vport *vport;
|
|
+ int i;
|
|
+
|
|
+ attr.prio = 1;
|
|
+ attr.in_rep = &rep;
|
|
+ mlx5_esw_for_all_vports(esw, i, vport) {
|
|
+ attr.in_rep->vport = vport->vport;
|
|
+ fdb = esw_vport_tbl_get(esw, &attr);
|
|
+ if (!fdb)
|
|
+ goto out;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+out:
|
|
+ mlx5_esw_vport_tbl_put(esw);
|
|
+ return PTR_ERR(fdb);
|
|
+}
|
|
+
|
|
+void mlx5_esw_vport_tbl_put(struct mlx5_eswitch *esw)
|
|
+{
|
|
+ struct mlx5_esw_flow_attr attr = {};
|
|
+ struct mlx5_eswitch_rep rep = {};
|
|
+ struct mlx5_vport *vport;
|
|
+ int i;
|
|
+
|
|
+ attr.prio = 1;
|
|
+ attr.in_rep = &rep;
|
|
+ mlx5_esw_for_all_vports(esw, i, vport) {
|
|
+ attr.in_rep->vport = vport->vport;
|
|
+ esw_vport_tbl_put(esw, &attr);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* End: Per vport tables */
|
|
+
|
|
static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw,
|
|
u16 vport_num)
|
|
{
|
|
@@ -191,8 +364,6 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
|
|
i++;
|
|
}
|
|
|
|
- mlx5_eswitch_set_rule_source_port(esw, spec, attr);
|
|
-
|
|
if (attr->outer_match_level != MLX5_MATCH_NONE)
|
|
spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
|
|
if (attr->inner_match_level != MLX5_MATCH_NONE)
|
|
@@ -201,8 +372,13 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
|
|
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
|
|
flow_act.modify_hdr = attr->modify_hdr;
|
|
|
|
- fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio,
|
|
- !!split);
|
|
+ if (split) {
|
|
+ fdb = esw_vport_tbl_get(esw, attr);
|
|
+ } else {
|
|
+ fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio,
|
|
+ 0);
|
|
+ mlx5_eswitch_set_rule_source_port(esw, spec, attr);
|
|
+ }
|
|
if (IS_ERR(fdb)) {
|
|
rule = ERR_CAST(fdb);
|
|
goto err_esw_get;
|
|
@@ -221,7 +397,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
|
|
return rule;
|
|
|
|
err_add_rule:
|
|
- mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, !!split);
|
|
+ if (split)
|
|
+ esw_vport_tbl_put(esw, attr);
|
|
+ else
|
|
+ mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0);
|
|
err_esw_get:
|
|
if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH) && attr->dest_chain)
|
|
mlx5_esw_chains_put_table(esw, attr->dest_chain, 1, 0);
|
|
@@ -247,7 +426,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
|
|
goto err_get_fast;
|
|
}
|
|
|
|
- fwd_fdb = mlx5_esw_chains_get_table(esw, attr->chain, attr->prio, 1);
|
|
+ fwd_fdb = esw_vport_tbl_get(esw, attr);
|
|
if (IS_ERR(fwd_fdb)) {
|
|
rule = ERR_CAST(fwd_fdb);
|
|
goto err_get_fwd;
|
|
@@ -285,7 +464,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
|
|
|
|
return rule;
|
|
add_err:
|
|
- mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 1);
|
|
+ esw_vport_tbl_put(esw, attr);
|
|
err_get_fwd:
|
|
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0);
|
|
err_get_fast:
|
|
@@ -312,11 +491,14 @@ __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
|
|
atomic64_dec(&esw->offloads.num_flows);
|
|
|
|
if (fwd_rule) {
|
|
- mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 1);
|
|
+ esw_vport_tbl_put(esw, attr);
|
|
mlx5_esw_chains_put_table(esw, attr->chain, attr->prio, 0);
|
|
} else {
|
|
- mlx5_esw_chains_put_table(esw, attr->chain, attr->prio,
|
|
- !!split);
|
|
+ if (split)
|
|
+ esw_vport_tbl_put(esw, attr);
|
|
+ else
|
|
+ mlx5_esw_chains_put_table(esw, attr->chain, attr->prio,
|
|
+ 0);
|
|
if (attr->dest_chain)
|
|
mlx5_esw_chains_put_table(esw, attr->dest_chain, 1, 0);
|
|
}
|
|
@@ -1938,6 +2120,9 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
|
|
if (err)
|
|
goto create_fg_err;
|
|
|
|
+ mutex_init(&esw->fdb_table.offloads.vports.lock);
|
|
+ hash_init(esw->fdb_table.offloads.vports.table);
|
|
+
|
|
return 0;
|
|
|
|
create_fg_err:
|
|
@@ -1954,6 +2139,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
|
|
|
|
static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
|
|
{
|
|
+ mutex_destroy(&esw->fdb_table.offloads.vports.lock);
|
|
esw_destroy_vport_rx_group(esw);
|
|
esw_destroy_offloads_table(esw);
|
|
esw_destroy_offloads_fdb_tables(esw);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
|
|
index cdf435cd08fb..483186883ac4 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_chains.c
|
|
@@ -21,8 +21,6 @@
|
|
#define fdb_ignore_flow_level_supported(esw) \
|
|
(MLX5_CAP_ESW_FLOWTABLE_FDB((esw)->dev, ignore_flow_level))
|
|
|
|
-#define ESW_OFFLOADS_NUM_GROUPS 4
|
|
-
|
|
/* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS),
|
|
* and a virtual memory region of 16M (ESW_SIZE), this region is duplicated
|
|
* for each flow table pool. We can allocate up to 16M of each pool,
|
|
@@ -704,12 +702,9 @@ mlx5_esw_chains_open(struct mlx5_eswitch *esw)
|
|
|
|
/* Open level 1 for split rules now if prios isn't supported */
|
|
if (!mlx5_esw_chains_prios_supported(esw)) {
|
|
- ft = mlx5_esw_chains_get_table(esw, 0, 1, 1);
|
|
-
|
|
- if (IS_ERR(ft)) {
|
|
- err = PTR_ERR(ft);
|
|
+ err = mlx5_esw_vport_tbl_get(esw);
|
|
+ if (err)
|
|
goto level_1_err;
|
|
- }
|
|
}
|
|
|
|
return 0;
|
|
@@ -725,7 +720,7 @@ static void
|
|
mlx5_esw_chains_close(struct mlx5_eswitch *esw)
|
|
{
|
|
if (!mlx5_esw_chains_prios_supported(esw))
|
|
- mlx5_esw_chains_put_table(esw, 0, 1, 1);
|
|
+ mlx5_esw_vport_tbl_put(esw);
|
|
mlx5_esw_chains_put_table(esw, 0, 1, 0);
|
|
mlx5_esw_chains_put_table(esw, mlx5_esw_chains_get_ft_chain(esw), 1, 0);
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
index 7cc21f08cbcc..344e5470a81c 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
@@ -2720,6 +2720,17 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
|
|
goto out_err;
|
|
}
|
|
|
|
+ /* We put this priority last, knowing that nothing will get here
|
|
+ * unless explicitly forwarded to. This is possible because the
|
|
+ * slow path tables have catch all rules and nothing gets passed
|
|
+ * those tables.
|
|
+ */
|
|
+ maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_PER_VPORT, 1);
|
|
+ if (IS_ERR(maj_prio)) {
|
|
+ err = PTR_ERR(maj_prio);
|
|
+ goto out_err;
|
|
+ }
|
|
+
|
|
set_prio_attrs(steering->fdb_root_ns);
|
|
return 0;
|
|
|
|
diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h
|
|
index b918d9724fc2..b63d3a8b502e 100644
|
|
--- a/include/linux/mlx5/fs.h
|
|
+++ b/include/linux/mlx5/fs.h
|
|
@@ -86,6 +86,7 @@ enum {
|
|
FDB_TC_OFFLOAD,
|
|
FDB_FT_OFFLOAD,
|
|
FDB_SLOW_PATH,
|
|
+ FDB_PER_VPORT,
|
|
};
|
|
|
|
struct mlx5_pkt_reformat;
|
|
--
|
|
2.13.6
|
|
|