Commit 248d3b4c authored by Tariq Toukan's avatar Tariq Toukan Committed by Saeed Mahameed
Browse files

net/mlx5e: Support flow classification into RSS contexts



Extend the existing flow classification support, to steer
flows not only directly to a receive ring, but also into
the new RSS contexts.

Create needed TIR objects on demand, and hold reference
on the RSS context.

Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Reviewed-by: default avatarMaxim Mikityanskiy <maximmi@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent f01cc58c
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -367,6 +367,30 @@ u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
	return mlx5e_tir_get_tirn(tir);
}

/* Fill the "tirn" output parameter.
 * Create the requested TIR if it's its first usage.
 */
int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
			  enum mlx5_traffic_types tt,
			  const struct mlx5e_lro_param *init_lro_param,
			  bool inner, u32 *tirn)
{
	struct mlx5e_tir *tir;

	tir = rss_get_tir(rss, tt, inner);
	if (!tir) { /* TIR doesn't exist, create one */
		int err;

		err = mlx5e_rss_create_tir(rss, tt, init_lro_param, inner);
		if (err)
			return err;
		tir = rss_get_tir(rss, tt, inner);
	}

	*tirn = mlx5e_tir_get_tirn(tir);
	return 0;
}

static void mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns)
{
	int err;
+5 −0
Original line number Diff line number Diff line
@@ -28,6 +28,11 @@ unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss);

u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
		       bool inner);
int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
			  enum mlx5_traffic_types tt,
			  const struct mlx5e_lro_param *init_lro_param,
			  bool inner, u32 *tirn);

void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns);
void mlx5e_rss_disable(struct mlx5e_rss *rss);

+22 −0
Original line number Diff line number Diff line
@@ -245,6 +245,28 @@ int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res)
	return cnt;
}

int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss)
{
	int i;

	if (!rss)
		return -EINVAL;

	for (i = 0; i < MLX5E_MAX_NUM_RSS; i++)
		if (rss == res->rss[i])
			return i;

	return -ENOENT;
}

struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx)
{
	if (rss_idx >= MLX5E_MAX_NUM_RSS)
		return NULL;

	return res->rss[rss_idx];
}

/* End of API rx_res_rss_* */

struct mlx5e_rx_res *mlx5e_rx_res_alloc(void)
+2 −0
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param
int mlx5e_rx_res_rss_init(struct mlx5e_rx_res *res, u32 *rss_idx, unsigned int init_nch);
int mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx);
int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res);
int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss);
struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx);

/* Workaround for hairpin */
struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *res);
+78 −21
Original line number Diff line number Diff line
@@ -35,11 +35,19 @@
#include "en/params.h"
#include "en/xsk/pool.h"

static int flow_type_to_traffic_type(u32 flow_type);

static u32 flow_type_mask(u32 flow_type)
{
	return flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
}

struct mlx5e_ethtool_rule {
	struct list_head             list;
	struct ethtool_rx_flow_spec  flow_spec;
	struct mlx5_flow_handle	     *rule;
	struct mlx5e_ethtool_table   *eth_ft;
	struct mlx5e_rss             *rss;
};

static void put_flow_table(struct mlx5e_ethtool_table *eth_ft)
@@ -66,7 +74,7 @@ static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv,
	int table_size;
	int prio;

	switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
	switch (flow_type_mask(fs->flow_type)) {
	case TCP_V4_FLOW:
	case UDP_V4_FLOW:
	case TCP_V6_FLOW:
@@ -329,7 +337,7 @@ static int set_flow_attrs(u32 *match_c, u32 *match_v,
					     outer_headers);
	void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v,
					     outer_headers);
	u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT);
	u32 flow_type = flow_type_mask(fs->flow_type);

	switch (flow_type) {
	case TCP_V4_FLOW:
@@ -397,10 +405,53 @@ static bool outer_header_zero(u32 *match_criteria)
						  size - 1);
}

static int flow_get_tirn(struct mlx5e_priv *priv,
			 struct mlx5e_ethtool_rule *eth_rule,
			 struct ethtool_rx_flow_spec *fs,
			 u32 rss_context, u32 *tirn)
{
	if (fs->flow_type & FLOW_RSS) {
		struct mlx5e_lro_param lro_param;
		struct mlx5e_rss *rss;
		u32 flow_type;
		int err;
		int tt;

		rss = mlx5e_rx_res_rss_get(priv->rx_res, rss_context);
		if (!rss)
			return -ENOENT;

		flow_type = flow_type_mask(fs->flow_type);
		tt = flow_type_to_traffic_type(flow_type);
		if (tt < 0)
			return -EINVAL;

		lro_param = mlx5e_get_lro_param(&priv->channels.params);
		err = mlx5e_rss_obtain_tirn(rss, tt, &lro_param, false, tirn);
		if (err)
			return err;
		eth_rule->rss = rss;
		mlx5e_rss_refcnt_inc(eth_rule->rss);
	} else {
		struct mlx5e_params *params = &priv->channels.params;
		enum mlx5e_rq_group group;
		u16 ix;

		mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group);

		*tirn = group == MLX5E_RQ_GROUP_XSK ?
			mlx5e_rx_res_get_tirn_xsk(priv->rx_res, ix) :
			mlx5e_rx_res_get_tirn_direct(priv->rx_res, ix);
	}

	return 0;
}

static struct mlx5_flow_handle *
add_ethtool_flow_rule(struct mlx5e_priv *priv,
		      struct mlx5e_ethtool_rule *eth_rule,
		      struct mlx5_flow_table *ft,
		      struct ethtool_rx_flow_spec *fs)
		      struct ethtool_rx_flow_spec *fs, u32 rss_context)
{
	struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND };
	struct mlx5_flow_destination *dst = NULL;
@@ -419,23 +470,17 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv,
	if (fs->ring_cookie == RX_CLS_FLOW_DISC) {
		flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
	} else {
		struct mlx5e_params *params = &priv->channels.params;
		enum mlx5e_rq_group group;
		u16 ix;

		mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group);

		dst = kzalloc(sizeof(*dst), GFP_KERNEL);
		if (!dst) {
			err = -ENOMEM;
			goto free;
		}

		err = flow_get_tirn(priv, eth_rule, fs, rss_context, &dst->tir_num);
		if (err)
			goto free;

		dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
		if (group == MLX5E_RQ_GROUP_XSK)
			dst->tir_num = mlx5e_rx_res_get_tirn_xsk(priv->rx_res, ix);
		else
			dst->tir_num = mlx5e_rx_res_get_tirn_direct(priv->rx_res, ix);
		flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
	}

@@ -459,6 +504,8 @@ static void del_ethtool_rule(struct mlx5e_priv *priv,
{
	if (eth_rule->rule)
		mlx5_del_flow_rules(eth_rule->rule);
	if (eth_rule->rss)
		mlx5e_rss_refcnt_dec(eth_rule->rss);
	list_del(&eth_rule->list);
	priv->fs.ethtool.tot_num_rules--;
	put_flow_table(eth_rule->eth_ft);
@@ -619,7 +666,7 @@ static int validate_flow(struct mlx5e_priv *priv,
					fs->ring_cookie))
			return -EINVAL;

	switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
	switch (flow_type_mask(fs->flow_type)) {
	case ETHER_FLOW:
		num_tuples += validate_ethter(fs);
		break;
@@ -668,7 +715,7 @@ static int validate_flow(struct mlx5e_priv *priv,

static int
mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
			   struct ethtool_rx_flow_spec *fs)
			   struct ethtool_rx_flow_spec *fs, u32 rss_context)
{
	struct mlx5e_ethtool_table *eth_ft;
	struct mlx5e_ethtool_rule *eth_rule;
@@ -699,7 +746,7 @@ mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
		err = -EINVAL;
		goto del_ethtool_rule;
	}
	rule = add_ethtool_flow_rule(priv, eth_ft->ft, fs);
	rule = add_ethtool_flow_rule(priv, eth_rule, eth_ft->ft, fs, rss_context);
	if (IS_ERR(rule)) {
		err = PTR_ERR(rule);
		goto del_ethtool_rule;
@@ -745,10 +792,20 @@ mlx5e_ethtool_get_flow(struct mlx5e_priv *priv,
		return -EINVAL;

	list_for_each_entry(eth_rule, &priv->fs.ethtool.rules, list) {
		if (eth_rule->flow_spec.location == location) {
		int index;

		if (eth_rule->flow_spec.location != location)
			continue;
		if (!info)
			return 0;
		info->fs = eth_rule->flow_spec;
		if (!eth_rule->rss)
			return 0;
		index = mlx5e_rx_res_rss_index(priv->rx_res, eth_rule->rss);
		if (index < 0)
			return index;
		info->rss_context = index;
		return 0;
		}
	}

	return -ENOENT;
@@ -764,7 +821,7 @@ mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv,

	info->data = MAX_NUM_OF_ETHTOOL_RULES;
	while ((!err || err == -ENOENT) && idx < info->rule_cnt) {
		err = mlx5e_ethtool_get_flow(priv, info, location);
		err = mlx5e_ethtool_get_flow(priv, NULL, location);
		if (!err)
			rule_locs[idx++] = location;
		location++;
@@ -887,7 +944,7 @@ int mlx5e_ethtool_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)

	switch (cmd->cmd) {
	case ETHTOOL_SRXCLSRLINS:
		err = mlx5e_ethtool_flow_replace(priv, &cmd->fs);
		err = mlx5e_ethtool_flow_replace(priv, &cmd->fs, cmd->rss_context);
		break;
	case ETHTOOL_SRXCLSRLDEL:
		err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location);