Commit 4a561817 authored by Roi Dayan's avatar Roi Dayan Committed by Saeed Mahameed

net/mlx5: E-Switch, Split creating fdb tables into smaller chunks

Split esw_create_offloads_fdb_tables() into smaller functions.
This will help maintenance.
Signed-off-by: default avatarRoi Dayan <roid@nvidia.com>
Reviewed-by: default avatarMark Bloch <mbloch@nvidia.com>
Reviewed-by: default avatarMaor Dickman <maord@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent 8ea7bcf6
......@@ -1669,93 +1669,19 @@ esw_chains_destroy(struct mlx5_eswitch *esw, struct mlx5_fs_chains *chains)
#endif
static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
static int
esw_create_send_to_vport_group(struct mlx5_eswitch *esw,
struct mlx5_flow_table *fdb,
u32 *flow_group_in,
int *ix)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_table_attr ft_attr = {};
int num_vfs, table_size, ix, err = 0;
struct mlx5_core_dev *dev = esw->dev;
struct mlx5_flow_namespace *root_ns;
struct mlx5_flow_table *fdb = NULL;
u32 flags = 0, *flow_group_in;
struct mlx5_flow_group *g;
void *match_criteria;
u8 *dmac;
esw_debug(esw->dev, "Create offloads FDB Tables\n");
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
if (!flow_group_in)
return -ENOMEM;
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
if (!root_ns) {
esw_warn(dev, "Failed to get FDB flow namespace\n");
err = -EOPNOTSUPP;
goto ns_err;
}
esw->fdb_table.offloads.ns = root_ns;
err = mlx5_flow_namespace_set_mode(root_ns,
esw->dev->priv.steering->mode);
if (err) {
esw_warn(dev, "Failed to set FDB namespace steering mode\n");
goto ns_err;
}
/* To be strictly correct:
* MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ)
* should be:
* esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ +
* peer_esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ
* but as the peer device might not be in switchdev mode it's not
* possible. We use the fact that by default FW sets max vfs and max sfs
* to the same value on both devices. If it needs to be changed in the future note
* the peer miss group should also be created based on the number of
* total vports of the peer (currently is also uses esw->total_vports).
*/
table_size = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ) +
MLX5_ESW_MISS_FLOWS + esw->total_vports + esw->esw_funcs.num_vfs;
/* create the slow path fdb with encap set, so further table instances
* can be created at run time while VFs are probed if the FW allows that.
*/
if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
ft_attr.flags = flags;
ft_attr.max_fte = table_size;
ft_attr.prio = FDB_SLOW_PATH;
fdb = mlx5_create_flow_table(root_ns, &ft_attr);
if (IS_ERR(fdb)) {
err = PTR_ERR(fdb);
esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
goto slow_fdb_err;
}
esw->fdb_table.offloads.slow_fdb = fdb;
/* Create empty TC-miss managed table. This allows plugging in following
* priorities without directly exposing their level 0 table to
* eswitch_offloads and passing it as miss_fdb to following call to
* esw_chains_create().
*/
memset(&ft_attr, 0, sizeof(ft_attr));
ft_attr.prio = FDB_TC_MISS;
esw->fdb_table.offloads.tc_miss_table = mlx5_create_flow_table(root_ns, &ft_attr);
if (IS_ERR(esw->fdb_table.offloads.tc_miss_table)) {
err = PTR_ERR(esw->fdb_table.offloads.tc_miss_table);
esw_warn(dev, "Failed to create TC miss FDB Table err %d\n", err);
goto tc_miss_table_err;
}
int count, err = 0;
err = esw_chains_create(esw, esw->fdb_table.offloads.tc_miss_table);
if (err) {
esw_warn(dev, "Failed to open fdb chains err(%d)\n", err);
goto fdb_chains_err;
}
memset(flow_group_in, 0, inlen);
/* create send-to-vport group */
MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
MLX5_MATCH_MISC_PARAMETERS);
......@@ -1770,22 +1696,41 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
source_eswitch_owner_vhca_id_valid, 1);
}
/* See comment above table_size calculation */
ix = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ);
/* See comment at table_size calculation */
count = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, *ix + count - 1);
*ix += count;
g = mlx5_create_flow_group(fdb, flow_group_in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
goto send_vport_err;
esw_warn(esw->dev, "Failed to create send-to-vport flow group err(%d)\n", err);
goto out;
}
esw->fdb_table.offloads.send_to_vport_grp = g;
if (esw_src_port_rewrite_supported(esw)) {
/* meta send to vport */
out:
return err;
}
static int
esw_create_meta_send_to_vport_group(struct mlx5_eswitch *esw,
struct mlx5_flow_table *fdb,
u32 *flow_group_in,
int *ix)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
int num_vfs = esw->esw_funcs.num_vfs;
struct mlx5_flow_group *g;
void *match_criteria;
int err = 0;
if (!esw_src_port_rewrite_supported(esw))
return 0;
memset(flow_group_in, 0, inlen);
MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
MLX5_MATCH_MISC_PARAMETERS_2);
......@@ -1797,18 +1742,17 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
MLX5_SET(fte_match_param, match_criteria,
misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK);
num_vfs = esw->esw_funcs.num_vfs;
if (num_vfs) {
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix);
MLX5_SET(create_flow_group_in, flow_group_in,
end_flow_index, ix + num_vfs - 1);
ix += num_vfs;
end_flow_index, *ix + num_vfs - 1);
*ix += num_vfs;
g = mlx5_create_flow_group(fdb, flow_group_in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
esw_warn(dev, "Failed to create send-to-vport meta flow group err(%d)\n",
err);
esw_warn(esw->dev,
"Failed to create send-to-vport meta flow group err(%d)\n", err);
goto send_vport_meta_err;
}
esw->fdb_table.offloads.send_to_vport_meta_grp = g;
......@@ -1817,10 +1761,29 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
if (err)
goto meta_rule_err;
}
}
if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
/* create peer esw miss group */
return 0;
meta_rule_err:
mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
send_vport_meta_err:
return err;
}
static int
esw_create_peer_esw_miss_group(struct mlx5_eswitch *esw,
struct mlx5_flow_table *fdb,
u32 *flow_group_in,
int *ix)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_group *g;
void *match_criteria;
int err = 0;
if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
return 0;
memset(flow_group_in, 0, inlen);
esw_set_flow_group_source_port(esw, flow_group_in);
......@@ -1837,22 +1800,37 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
source_eswitch_owner_vhca_id_valid, 1);
}
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
ix + esw->total_vports - 1);
ix += esw->total_vports;
*ix + esw->total_vports - 1);
*ix += esw->total_vports;
g = mlx5_create_flow_group(fdb, flow_group_in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
goto peer_miss_err;
esw_warn(esw->dev, "Failed to create peer miss flow group err(%d)\n", err);
goto out;
}
esw->fdb_table.offloads.peer_miss_grp = g;
}
/* create miss group */
out:
return err;
}
static int
esw_create_miss_group(struct mlx5_eswitch *esw,
struct mlx5_flow_table *fdb,
u32 *flow_group_in,
int *ix)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_group *g;
void *match_criteria;
int err = 0;
u8 *dmac;
memset(flow_group_in, 0, inlen);
MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
MLX5_MATCH_OUTER_HEADERS);
match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
......@@ -1861,14 +1839,14 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
outer_headers.dmac_47_16);
dmac[0] = 0x01;
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
ix + MLX5_ESW_MISS_FLOWS);
*ix + MLX5_ESW_MISS_FLOWS);
g = mlx5_create_flow_group(fdb, flow_group_in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
esw_warn(esw->dev, "Failed to create miss flow group err(%d)\n", err);
goto miss_err;
}
esw->fdb_table.offloads.miss_grp = g;
......@@ -1877,17 +1855,121 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
if (err)
goto miss_rule_err;
kvfree(flow_group_in);
return 0;
miss_rule_err:
mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
miss_err:
return err;
}
static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_core_dev *dev = esw->dev;
struct mlx5_flow_namespace *root_ns;
struct mlx5_flow_table *fdb = NULL;
int table_size, ix = 0, err = 0;
u32 flags = 0, *flow_group_in;
esw_debug(esw->dev, "Create offloads FDB Tables\n");
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
if (!flow_group_in)
return -ENOMEM;
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
if (!root_ns) {
esw_warn(dev, "Failed to get FDB flow namespace\n");
err = -EOPNOTSUPP;
goto ns_err;
}
esw->fdb_table.offloads.ns = root_ns;
err = mlx5_flow_namespace_set_mode(root_ns,
esw->dev->priv.steering->mode);
if (err) {
esw_warn(dev, "Failed to set FDB namespace steering mode\n");
goto ns_err;
}
/* To be strictly correct:
* MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ)
* should be:
* esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ +
* peer_esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ
* but as the peer device might not be in switchdev mode it's not
* possible. We use the fact that by default FW sets max vfs and max sfs
* to the same value on both devices. If it needs to be changed in the future note
* the peer miss group should also be created based on the number of
* total vports of the peer (currently is also uses esw->total_vports).
*/
table_size = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ) +
MLX5_ESW_MISS_FLOWS + esw->total_vports + esw->esw_funcs.num_vfs;
/* create the slow path fdb with encap set, so further table instances
* can be created at run time while VFs are probed if the FW allows that.
*/
if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
ft_attr.flags = flags;
ft_attr.max_fte = table_size;
ft_attr.prio = FDB_SLOW_PATH;
fdb = mlx5_create_flow_table(root_ns, &ft_attr);
if (IS_ERR(fdb)) {
err = PTR_ERR(fdb);
esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
goto slow_fdb_err;
}
esw->fdb_table.offloads.slow_fdb = fdb;
/* Create empty TC-miss managed table. This allows plugging in following
* priorities without directly exposing their level 0 table to
* eswitch_offloads and passing it as miss_fdb to following call to
* esw_chains_create().
*/
memset(&ft_attr, 0, sizeof(ft_attr));
ft_attr.prio = FDB_TC_MISS;
esw->fdb_table.offloads.tc_miss_table = mlx5_create_flow_table(root_ns, &ft_attr);
if (IS_ERR(esw->fdb_table.offloads.tc_miss_table)) {
err = PTR_ERR(esw->fdb_table.offloads.tc_miss_table);
esw_warn(dev, "Failed to create TC miss FDB Table err %d\n", err);
goto tc_miss_table_err;
}
err = esw_chains_create(esw, esw->fdb_table.offloads.tc_miss_table);
if (err) {
esw_warn(dev, "Failed to open fdb chains err(%d)\n", err);
goto fdb_chains_err;
}
err = esw_create_send_to_vport_group(esw, fdb, flow_group_in, &ix);
if (err)
goto send_vport_err;
err = esw_create_meta_send_to_vport_group(esw, fdb, flow_group_in, &ix);
if (err)
goto send_vport_meta_err;
err = esw_create_peer_esw_miss_group(esw, fdb, flow_group_in, &ix);
if (err)
goto peer_miss_err;
err = esw_create_miss_group(esw, fdb, flow_group_in, &ix);
if (err)
goto miss_err;
kvfree(flow_group_in);
return 0;
miss_err:
if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
peer_miss_err:
mlx5_eswitch_del_send_to_vport_meta_rules(esw);
meta_rule_err:
if (esw->fdb_table.offloads.send_to_vport_meta_grp)
mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
send_vport_meta_err:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment