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

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
Loading
Loading
Loading
Loading
+206 −124
Original line number Diff line number Diff line
@@ -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;
	}

	return 0;

meta_rule_err:
	mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
send_vport_meta_err:
	return err;
}

	if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
		/* create peer esw miss group */
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;

out:
	return err;
}

	/* create miss group */
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: