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: Tariq Toukan <tariqt@nvidia.com> Reviewed-by: Maxim Mikityanskiy <maximmi@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
This commit is contained in:
parent
f01cc58c18
commit
248d3b4c9a
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(ð_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) {
|
||||
info->fs = eth_rule->flow_spec;
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue