net/mlx5: support device control for E-Switch default rule

This patch adds support for fdb_def_rule_en device argument to HW
Steering, which controls:

- the creation of the default FDB jump flow rule.
- the ability of the user to create transfer flow rules in the root
table.

Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Signed-off-by: Xueming Li <xuemingl@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
This commit is contained in:
Dariusz Sosnowski 2022-10-20 18:41:50 +03:00 committed by Raslan Darawsheh
parent a3778a4784
commit 26e1eaf2da
12 changed files with 291 additions and 191 deletions

View File

@ -78,6 +78,7 @@ meter_color = Y
mpls = Y
nvgre = Y
port_id = Y
port_representor = Y
tag = Y
tcp = Y
udp = Y

View File

@ -1567,6 +1567,20 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
rte_rwlock_init(&priv->ind_tbls_lock);
if (priv->sh->config.dv_flow_en == 2) {
#ifdef HAVE_MLX5_HWS_SUPPORT
if (priv->sh->config.dv_esw_en) {
if (priv->sh->dv_regc0_mask == UINT32_MAX) {
DRV_LOG(ERR, "E-Switch port metadata is required when using HWS "
"but it is disabled (configure it through devlink)");
err = ENOTSUP;
goto error;
}
if (priv->sh->dv_regc0_mask == 0) {
DRV_LOG(ERR, "E-Switch with HWS is not supported "
"(no available bits in reg_c[0])");
err = ENOTSUP;
goto error;
}
}
if (priv->vport_meta_mask)
flow_hw_set_port_info(eth_dev);
if (priv->sh->config.dv_esw_en &&

View File

@ -2028,7 +2028,7 @@ int mlx5_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops);
int mlx5_flow_start_default(struct rte_eth_dev *dev);
void mlx5_flow_stop_default(struct rte_eth_dev *dev);
int mlx5_flow_verify(struct rte_eth_dev *dev);
int mlx5_ctrl_flow_source_queue(struct rte_eth_dev *dev, uint32_t queue);
int mlx5_ctrl_flow_source_queue(struct rte_eth_dev *dev, uint32_t sq_num);
int mlx5_ctrl_flow_vlan(struct rte_eth_dev *dev,
struct rte_flow_item_eth *eth_spec,
struct rte_flow_item_eth *eth_mask,
@ -2040,7 +2040,7 @@ int mlx5_ctrl_flow(struct rte_eth_dev *dev,
int mlx5_flow_lacp_miss(struct rte_eth_dev *dev);
struct rte_flow *mlx5_flow_create_esw_table_zero_flow(struct rte_eth_dev *dev);
uint32_t mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev,
uint32_t txq);
uint32_t sq_num);
void mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh,
uint64_t async_id, int status);
void mlx5_set_query_alarm(struct mlx5_dev_ctx_shared *sh);

View File

@ -7155,14 +7155,14 @@ mlx5_flow_create_esw_table_zero_flow(struct rte_eth_dev *dev)
*
* @param dev
* Pointer to Ethernet device.
* @param txq
* Txq index.
* @param sq_num
* SQ number.
*
* @return
* Flow ID on success, 0 otherwise and rte_errno is set.
*/
uint32_t
mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq)
mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t sq_num)
{
struct rte_flow_attr attr = {
.group = 0,
@ -7174,8 +7174,8 @@ mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq)
struct rte_flow_item_port_id port_spec = {
.id = MLX5_PORT_ESW_MGR,
};
struct mlx5_rte_flow_item_sq txq_spec = {
.queue = txq,
struct mlx5_rte_flow_item_sq sq_spec = {
.queue = sq_num,
};
struct rte_flow_item pattern[] = {
{
@ -7185,7 +7185,7 @@ mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq)
{
.type = (enum rte_flow_item_type)
MLX5_RTE_FLOW_ITEM_TYPE_SQ,
.spec = &txq_spec,
.spec = &sq_spec,
},
{
.type = RTE_FLOW_ITEM_TYPE_END,
@ -7556,22 +7556,22 @@ mlx5_flow_verify(struct rte_eth_dev *dev __rte_unused)
*
* @param dev
* Pointer to Ethernet device.
* @param queue
* The queue index.
* @param sq_num
* The SQ hw number.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
int
mlx5_ctrl_flow_source_queue(struct rte_eth_dev *dev,
uint32_t queue)
uint32_t sq_num)
{
const struct rte_flow_attr attr = {
.egress = 1,
.priority = 0,
};
struct mlx5_rte_flow_item_sq queue_spec = {
.queue = queue,
.queue = sq_num,
};
struct mlx5_rte_flow_item_sq queue_mask = {
.queue = UINT32_MAX,

View File

@ -116,7 +116,7 @@ struct mlx5_flow_action_copy_mreg {
/* Matches on source queue. */
struct mlx5_rte_flow_item_sq {
uint32_t queue;
uint32_t queue; /* DevX SQ number */
};
/* Feature name to allocate metadata register. */
@ -2493,9 +2493,8 @@ int mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev,
int mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *dev);
int mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev);
int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev,
uint32_t txq);
uint32_t sqn);
int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev);
int mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev);
int mlx5_flow_actions_validate(struct rte_eth_dev *dev,

View File

@ -10125,6 +10125,29 @@ flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *key,
return 0;
}
/**
* Translate port representor item to eswitch match on port id.
*
* @param[in] dev
* The devich to configure through.
* @param[in, out] key
* Flow matcher value.
* @param[in] key_type
* Set flow matcher mask or value.
*
* @return
* 0 on success, a negative errno value otherwise.
*/
static int
flow_dv_translate_item_port_representor(struct rte_eth_dev *dev, void *key,
uint32_t key_type)
{
flow_dv_translate_item_source_vport(key,
key_type & MLX5_SET_MATCHER_V ?
mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff);
return 0;
}
/**
* Translate represented port item to eswitch match on port id.
*
@ -11404,10 +11427,10 @@ flow_dv_translate_create_counter(struct rte_eth_dev *dev,
}
/**
* Add Tx queue matcher
* Add SQ matcher
*
* @param[in] dev
* Pointer to the dev struct.
* @param[in, out] matcher
* Flow matcher.
* @param[in, out] key
* Flow matcher value.
* @param[in] item
@ -11416,40 +11439,29 @@ flow_dv_translate_create_counter(struct rte_eth_dev *dev,
* Set flow matcher mask or value.
*/
static void
flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
void *key,
const struct rte_flow_item *item,
uint32_t key_type)
flow_dv_translate_item_sq(void *key,
const struct rte_flow_item *item,
uint32_t key_type)
{
const struct mlx5_rte_flow_item_sq *queue_m;
const struct mlx5_rte_flow_item_sq *queue_v;
const struct mlx5_rte_flow_item_sq queue_mask = {
.queue = UINT32_MAX,
};
void *misc_v =
MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
struct mlx5_txq_ctrl *txq = NULL;
void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
uint32_t queue;
MLX5_ITEM_UPDATE(item, key_type, queue_v, queue_m, &queue_mask);
if (!queue_m || !queue_v)
return;
if (key_type & MLX5_SET_MATCHER_V) {
txq = mlx5_txq_get(dev, queue_v->queue);
if (!txq)
return;
if (txq->is_hairpin)
queue = txq->obj->sq->id;
else
queue = txq->obj->sq_obj.sq->id;
queue = queue_v->queue;
if (key_type == MLX5_SET_MATCHER_SW_V)
queue &= queue_m->queue;
} else {
queue = queue_m->queue;
}
MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue);
if (txq)
mlx5_txq_release(dev, queue_v->queue);
}
/**
@ -13195,6 +13207,11 @@ flow_dv_translate_items(struct rte_eth_dev *dev,
(dev, key, items, wks->attr, key_type);
last_item = MLX5_FLOW_ITEM_PORT_ID;
break;
case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR:
flow_dv_translate_item_port_representor
(dev, key, key_type);
last_item = MLX5_FLOW_ITEM_PORT_REPRESENTOR;
break;
case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT:
flow_dv_translate_item_represented_port
(dev, key, items, wks->attr, key_type);
@ -13401,7 +13418,7 @@ flow_dv_translate_items(struct rte_eth_dev *dev,
last_item = MLX5_FLOW_ITEM_TAG;
break;
case MLX5_RTE_FLOW_ITEM_TYPE_SQ:
flow_dv_translate_item_tx_queue(dev, key, items, key_type);
flow_dv_translate_item_sq(key, items, key_type);
last_item = MLX5_FLOW_ITEM_SQ;
break;
case RTE_FLOW_ITEM_TYPE_GTP:
@ -13617,7 +13634,6 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev,
wks.last_item = tunnel ? MLX5_FLOW_ITEM_INNER_FLEX :
MLX5_FLOW_ITEM_OUTER_FLEX;
break;
default:
ret = flow_dv_translate_items(dev, items, &wks_m,
match_mask, MLX5_SET_MATCHER_SW_M, error);
@ -13640,7 +13656,9 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev,
* in use.
*/
if (!(wks.item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
!(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) && priv->sh->esw_mode &&
!(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) &&
!(wks.item_flags & MLX5_FLOW_ITEM_PORT_REPRESENTOR) &&
priv->sh->esw_mode &&
!(attr->egress && !attr->transfer) &&
attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP) {
if (flow_dv_translate_item_port_id_all(dev, match_mask,

View File

@ -3176,7 +3176,10 @@ flow_hw_translate_group(struct rte_eth_dev *dev,
struct mlx5_priv *priv = dev->data->dev_private;
const struct rte_flow_attr *flow_attr = &cfg->attr.flow_attr;
if (priv->sh->config.dv_esw_en && cfg->external && flow_attr->transfer) {
if (priv->sh->config.dv_esw_en &&
priv->fdb_def_rule &&
cfg->external &&
flow_attr->transfer) {
if (group > MLX5_HW_MAX_TRANSFER_GROUP)
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
@ -5140,14 +5143,23 @@ flow_hw_free_vport_actions(struct mlx5_priv *priv)
}
static uint32_t
flow_hw_usable_lsb_vport_mask(struct mlx5_priv *priv)
flow_hw_esw_mgr_regc_marker_mask(struct rte_eth_dev *dev)
{
uint32_t usable_mask = ~priv->vport_meta_mask;
uint32_t mask = MLX5_SH(dev)->dv_regc0_mask;
if (usable_mask)
return (1 << rte_bsf32(usable_mask));
else
return 0;
/* Mask is verified during device initialization. */
MLX5_ASSERT(mask != 0);
return mask;
}
static uint32_t
flow_hw_esw_mgr_regc_marker(struct rte_eth_dev *dev)
{
uint32_t mask = MLX5_SH(dev)->dv_regc0_mask;
/* Mask is verified during device initialization. */
MLX5_ASSERT(mask != 0);
return RTE_BIT32(rte_bsf32(mask));
}
/**
@ -5173,12 +5185,19 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev)
struct rte_flow_item_ethdev port_mask = {
.port_id = UINT16_MAX,
};
struct mlx5_rte_flow_item_sq sq_mask = {
.queue = UINT32_MAX,
};
struct rte_flow_item items[] = {
{
.type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT,
.spec = &port_spec,
.mask = &port_mask,
},
{
.type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ,
.mask = &sq_mask,
},
{
.type = RTE_FLOW_ITEM_TYPE_END,
},
@ -5188,9 +5207,10 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev)
}
/**
* Creates a flow pattern template used to match REG_C_0 and a TX queue.
* Matching on REG_C_0 is set up to match on least significant bit usable
* by user-space, which is set when packet was originated from E-Switch Manager.
* Creates a flow pattern template used to match REG_C_0 and a SQ.
* Matching on REG_C_0 is set up to match on all bits usable by user-space.
* If traffic was sent from E-Switch Manager, then all usable bits will be set to 0,
* except the least significant bit, which will be set to 1.
*
* This template is used to set up a table for SQ miss default flow.
*
@ -5203,8 +5223,6 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev)
static struct rte_flow_pattern_template *
flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev)
{
struct mlx5_priv *priv = dev->data->dev_private;
uint32_t marker_bit = flow_hw_usable_lsb_vport_mask(priv);
struct rte_flow_pattern_template_attr attr = {
.relaxed_matching = 0,
.transfer = 1,
@ -5214,6 +5232,7 @@ flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev)
};
struct rte_flow_item_tag reg_c0_mask = {
.index = 0xff,
.data = flow_hw_esw_mgr_regc_marker_mask(dev),
};
struct mlx5_rte_flow_item_sq queue_mask = {
.queue = UINT32_MAX,
@ -5235,12 +5254,6 @@ flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev)
},
};
if (!marker_bit) {
DRV_LOG(ERR, "Unable to set up pattern template for SQ miss table");
return NULL;
}
reg_c0_spec.data = marker_bit;
reg_c0_mask.data = marker_bit;
return flow_hw_pattern_template_create(dev, &attr, items, NULL);
}
@ -5332,9 +5345,8 @@ flow_hw_create_tx_default_mreg_copy_pattern_template(struct rte_eth_dev *dev)
static struct rte_flow_actions_template *
flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev)
{
struct mlx5_priv *priv = dev->data->dev_private;
uint32_t marker_bit = flow_hw_usable_lsb_vport_mask(priv);
uint32_t marker_bit_mask = UINT32_MAX;
uint32_t marker_mask = flow_hw_esw_mgr_regc_marker_mask(dev);
uint32_t marker_bits = flow_hw_esw_mgr_regc_marker(dev);
struct rte_flow_actions_template_attr attr = {
.transfer = 1,
};
@ -5347,7 +5359,7 @@ flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev)
.src = {
.field = RTE_FLOW_FIELD_VALUE,
},
.width = 1,
.width = __builtin_popcount(marker_mask),
};
struct rte_flow_action_modify_field set_reg_m = {
.operation = RTE_FLOW_MODIFY_SET,
@ -5394,13 +5406,9 @@ flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev)
}
};
if (!marker_bit) {
DRV_LOG(ERR, "Unable to set up actions template for SQ miss table");
return NULL;
}
set_reg_v.dst.offset = rte_bsf32(marker_bit);
rte_memcpy(set_reg_v.src.value, &marker_bit, sizeof(marker_bit));
rte_memcpy(set_reg_m.src.value, &marker_bit_mask, sizeof(marker_bit_mask));
set_reg_v.dst.offset = rte_bsf32(marker_mask);
rte_memcpy(set_reg_v.src.value, &marker_bits, sizeof(marker_bits));
rte_memcpy(set_reg_m.src.value, &marker_mask, sizeof(marker_mask));
return flow_hw_actions_template_create(dev, &attr, actions_v, actions_m, NULL);
}
@ -5587,7 +5595,7 @@ flow_hw_create_ctrl_sq_miss_root_table(struct rte_eth_dev *dev,
struct rte_flow_template_table_attr attr = {
.flow_attr = {
.group = 0,
.priority = 0,
.priority = MLX5_HW_LOWEST_PRIO_ROOT,
.ingress = 0,
.egress = 0,
.transfer = 1,
@ -5702,7 +5710,7 @@ flow_hw_create_ctrl_jump_table(struct rte_eth_dev *dev,
struct rte_flow_template_table_attr attr = {
.flow_attr = {
.group = 0,
.priority = MLX5_HW_LOWEST_PRIO_ROOT,
.priority = 0,
.ingress = 0,
.egress = 0,
.transfer = 1,
@ -7800,141 +7808,123 @@ flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev)
}
int
mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct rte_flow_item_ethdev port_spec = {
.port_id = MLX5_REPRESENTED_PORT_ESW_MGR,
};
struct rte_flow_item_ethdev port_mask = {
.port_id = MLX5_REPRESENTED_PORT_ESW_MGR,
};
struct rte_flow_item items[] = {
{
.type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT,
.spec = &port_spec,
.mask = &port_mask,
},
{
.type = RTE_FLOW_ITEM_TYPE_END,
},
};
struct rte_flow_action_modify_field modify_field = {
.operation = RTE_FLOW_MODIFY_SET,
.dst = {
.field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG,
},
.src = {
.field = RTE_FLOW_FIELD_VALUE,
},
.width = 1,
};
struct rte_flow_action_jump jump = {
.group = 1,
};
struct rte_flow_action actions[] = {
{
.type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
.conf = &modify_field,
},
{
.type = RTE_FLOW_ACTION_TYPE_JUMP,
.conf = &jump,
},
{
.type = RTE_FLOW_ACTION_TYPE_END,
},
};
MLX5_ASSERT(priv->master);
if (!priv->dr_ctx ||
!priv->hw_esw_sq_miss_root_tbl)
return 0;
return flow_hw_create_ctrl_flow(dev, dev,
priv->hw_esw_sq_miss_root_tbl,
items, 0, actions, 0);
}
int
mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq)
mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t sqn)
{
uint16_t port_id = dev->data->port_id;
struct rte_flow_item_ethdev esw_mgr_spec = {
.port_id = MLX5_REPRESENTED_PORT_ESW_MGR,
};
struct rte_flow_item_ethdev esw_mgr_mask = {
.port_id = MLX5_REPRESENTED_PORT_ESW_MGR,
};
struct rte_flow_item_tag reg_c0_spec = {
.index = (uint8_t)REG_C_0,
.data = flow_hw_esw_mgr_regc_marker(dev),
};
struct rte_flow_item_tag reg_c0_mask = {
.index = 0xff,
.data = flow_hw_esw_mgr_regc_marker_mask(dev),
};
struct mlx5_rte_flow_item_sq queue_spec = {
.queue = txq,
};
struct mlx5_rte_flow_item_sq queue_mask = {
.queue = UINT32_MAX,
};
struct rte_flow_item items[] = {
{
.type = (enum rte_flow_item_type)
MLX5_RTE_FLOW_ITEM_TYPE_TAG,
.spec = &reg_c0_spec,
.mask = &reg_c0_mask,
},
{
.type = (enum rte_flow_item_type)
MLX5_RTE_FLOW_ITEM_TYPE_SQ,
.spec = &queue_spec,
.mask = &queue_mask,
},
{
.type = RTE_FLOW_ITEM_TYPE_END,
},
struct mlx5_rte_flow_item_sq sq_spec = {
.queue = sqn,
};
struct rte_flow_action_ethdev port = {
.port_id = port_id,
};
struct rte_flow_action actions[] = {
{
.type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT,
.conf = &port,
},
{
.type = RTE_FLOW_ACTION_TYPE_END,
},
};
struct rte_flow_item items[3] = { { 0 } };
struct rte_flow_action actions[3] = { { 0 } };
struct rte_eth_dev *proxy_dev;
struct mlx5_priv *proxy_priv;
uint16_t proxy_port_id = dev->data->port_id;
uint32_t marker_bit;
int ret;
RTE_SET_USED(txq);
ret = rte_flow_pick_transfer_proxy(port_id, &proxy_port_id, NULL);
if (ret) {
DRV_LOG(ERR, "Unable to pick proxy port for port %u", port_id);
DRV_LOG(ERR, "Unable to pick transfer proxy port for port %u. Transfer proxy "
"port must be present to create default SQ miss flows.",
port_id);
return ret;
}
proxy_dev = &rte_eth_devices[proxy_port_id];
proxy_priv = proxy_dev->data->dev_private;
if (!proxy_priv->dr_ctx)
if (!proxy_priv->dr_ctx) {
DRV_LOG(DEBUG, "Transfer proxy port (port %u) of port %u must be configured "
"for HWS to create default SQ miss flows. Default flows will "
"not be created.",
proxy_port_id, port_id);
return 0;
}
if (!proxy_priv->hw_esw_sq_miss_root_tbl ||
!proxy_priv->hw_esw_sq_miss_tbl) {
DRV_LOG(ERR, "port %u proxy port %u was configured but default"
" flow tables are not created",
port_id, proxy_port_id);
DRV_LOG(ERR, "Transfer proxy port (port %u) of port %u was configured, but "
"default flow tables were not created.",
proxy_port_id, port_id);
rte_errno = ENOMEM;
return -rte_errno;
}
marker_bit = flow_hw_usable_lsb_vport_mask(proxy_priv);
if (!marker_bit) {
DRV_LOG(ERR, "Unable to set up control flow in SQ miss table");
rte_errno = EINVAL;
return -rte_errno;
/*
* Create a root SQ miss flow rule - match E-Switch Manager and SQ,
* and jump to group 1.
*/
items[0] = (struct rte_flow_item){
.type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT,
.spec = &esw_mgr_spec,
.mask = &esw_mgr_mask,
};
items[1] = (struct rte_flow_item){
.type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ,
.spec = &sq_spec,
};
items[2] = (struct rte_flow_item){
.type = RTE_FLOW_ITEM_TYPE_END,
};
actions[0] = (struct rte_flow_action){
.type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
};
actions[1] = (struct rte_flow_action){
.type = RTE_FLOW_ACTION_TYPE_JUMP,
};
actions[2] = (struct rte_flow_action) {
.type = RTE_FLOW_ACTION_TYPE_END,
};
ret = flow_hw_create_ctrl_flow(dev, proxy_dev, proxy_priv->hw_esw_sq_miss_root_tbl,
items, 0, actions, 0);
if (ret) {
DRV_LOG(ERR, "Port %u failed to create root SQ miss flow rule for SQ %u, ret %d",
port_id, sqn, ret);
return ret;
}
reg_c0_spec.data = marker_bit;
reg_c0_mask.data = marker_bit;
return flow_hw_create_ctrl_flow(dev, proxy_dev,
proxy_priv->hw_esw_sq_miss_tbl,
items, 0, actions, 0);
/*
* Create a non-root SQ miss flow rule - match REG_C_0 marker and SQ,
* and forward to port.
*/
items[0] = (struct rte_flow_item){
.type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_TAG,
.spec = &reg_c0_spec,
.mask = &reg_c0_mask,
};
items[1] = (struct rte_flow_item){
.type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ,
.spec = &sq_spec,
};
items[2] = (struct rte_flow_item){
.type = RTE_FLOW_ITEM_TYPE_END,
};
actions[0] = (struct rte_flow_action){
.type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT,
.conf = &port,
};
actions[1] = (struct rte_flow_action){
.type = RTE_FLOW_ACTION_TYPE_END,
};
ret = flow_hw_create_ctrl_flow(dev, proxy_dev, proxy_priv->hw_esw_sq_miss_tbl,
items, 0, actions, 0);
if (ret) {
DRV_LOG(ERR, "Port %u failed to create HWS SQ miss flow rule for SQ %u, ret %d",
port_id, sqn, ret);
return ret;
}
return 0;
}
int
@ -7972,17 +7962,24 @@ mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev)
ret = rte_flow_pick_transfer_proxy(port_id, &proxy_port_id, NULL);
if (ret) {
DRV_LOG(ERR, "Unable to pick proxy port for port %u", port_id);
DRV_LOG(ERR, "Unable to pick transfer proxy port for port %u. Transfer proxy "
"port must be present to create default FDB jump rule.",
port_id);
return ret;
}
proxy_dev = &rte_eth_devices[proxy_port_id];
proxy_priv = proxy_dev->data->dev_private;
if (!proxy_priv->dr_ctx)
if (!proxy_priv->dr_ctx) {
DRV_LOG(DEBUG, "Transfer proxy port (port %u) of port %u must be configured "
"for HWS to create default FDB jump rule. Default rule will "
"not be created.",
proxy_port_id, port_id);
return 0;
}
if (!proxy_priv->hw_esw_zero_tbl) {
DRV_LOG(ERR, "port %u proxy port %u was configured but default"
" flow tables are not created",
port_id, proxy_port_id);
DRV_LOG(ERR, "Transfer proxy port (port %u) of port %u was configured, but "
"default flow tables were not created.",
proxy_port_id, port_id);
rte_errno = EINVAL;
return -rte_errno;
}

View File

@ -426,7 +426,7 @@ mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue,
mlx5_txq_release(dev, peer_queue);
return -rte_errno;
}
peer_info->qp_id = txq_ctrl->obj->sq->id;
peer_info->qp_id = mlx5_txq_get_sqn(txq_ctrl);
peer_info->vhca_id = priv->sh->cdev->config.hca_attr.vhca_id;
/* 1-to-1 mapping, only the first one is used. */
peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue;
@ -818,7 +818,7 @@ mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
}
/* Pass TxQ's information to peer RxQ and try binding. */
cur.peer_q = rx_queue;
cur.qp_id = txq_ctrl->obj->sq->id;
cur.qp_id = mlx5_txq_get_sqn(txq_ctrl);
cur.vhca_id = priv->sh->cdev->config.hca_attr.vhca_id;
cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind;
@ -1300,8 +1300,6 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev)
int ret;
if (priv->sh->config.dv_esw_en && priv->master) {
if (mlx5_flow_hw_esw_create_mgr_sq_miss_flow(dev))
goto error;
if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS)
if (mlx5_flow_hw_create_tx_default_mreg_copy_flow(dev))
goto error;
@ -1312,10 +1310,7 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev)
if (!txq)
continue;
if (txq->is_hairpin)
queue = txq->obj->sq->id;
else
queue = txq->obj->sq_obj.sq->id;
queue = mlx5_txq_get_sqn(txq);
if ((priv->representor || priv->master) &&
priv->sh->config.dv_esw_en) {
if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, queue)) {
@ -1325,9 +1320,15 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev)
}
mlx5_txq_release(dev, i);
}
if ((priv->master || priv->representor) && priv->sh->config.dv_esw_en) {
if (mlx5_flow_hw_esw_create_default_jump_flow(dev))
goto error;
if (priv->sh->config.fdb_def_rule) {
if ((priv->master || priv->representor) && priv->sh->config.dv_esw_en) {
if (!mlx5_flow_hw_esw_create_default_jump_flow(dev))
priv->fdb_def_rule = 1;
else
goto error;
}
} else {
DRV_LOG(INFO, "port %u FDB default rule is disabled", dev->data->port_id);
}
return 0;
error:
@ -1393,14 +1394,18 @@ mlx5_traffic_enable(struct rte_eth_dev *dev)
txq_ctrl->hairpin_conf.tx_explicit == 0 &&
txq_ctrl->hairpin_conf.peers[0].port ==
priv->dev_data->port_id) {
ret = mlx5_ctrl_flow_source_queue(dev, i);
ret = mlx5_ctrl_flow_source_queue(dev,
mlx5_txq_get_sqn(txq_ctrl));
if (ret) {
mlx5_txq_release(dev, i);
goto error;
}
}
if (priv->sh->config.dv_esw_en) {
if (mlx5_flow_create_devx_sq_miss_flow(dev, i) == 0) {
uint32_t q = mlx5_txq_get_sqn(txq_ctrl);
if (mlx5_flow_create_devx_sq_miss_flow(dev, q) == 0) {
mlx5_txq_release(dev, i);
DRV_LOG(ERR,
"Port %u Tx queue %u SQ create representor devx default miss rule failed.",
dev->data->port_id, i);

View File

@ -213,6 +213,7 @@ struct mlx5_txq_ctrl *mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx);
int mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx);
int mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx);
int mlx5_txq_verify(struct rte_eth_dev *dev);
int mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq);
void txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl);
void txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl);
uint64_t mlx5_get_tx_port_offloads(struct rte_eth_dev *dev);

View File

@ -27,6 +27,8 @@
#include "mlx5_tx.h"
#include "mlx5_rxtx.h"
#include "mlx5_autoconf.h"
#include "rte_pmd_mlx5.h"
#include "mlx5_flow.h"
/**
* Allocate TX queue elements.
@ -1274,6 +1276,51 @@ mlx5_txq_verify(struct rte_eth_dev *dev)
return ret;
}
int
mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq)
{
return txq->is_hairpin ? txq->obj->sq->id : txq->obj->sq_obj.sq->id;
}
int
rte_pmd_mlx5_external_sq_enable(uint16_t port_id, uint32_t sq_num)
{
struct rte_eth_dev *dev;
struct mlx5_priv *priv;
uint32_t flow;
if (rte_eth_dev_is_valid_port(port_id) < 0) {
DRV_LOG(ERR, "There is no Ethernet device for port %u.",
port_id);
rte_errno = ENODEV;
return -rte_errno;
}
dev = &rte_eth_devices[port_id];
priv = dev->data->dev_private;
if ((!priv->representor && !priv->master) ||
!priv->sh->config.dv_esw_en) {
DRV_LOG(ERR, "Port %u must be represetnor or master port in E-Switch mode.",
port_id);
rte_errno = EINVAL;
return -rte_errno;
}
if (sq_num == 0) {
DRV_LOG(ERR, "Invalid SQ number.");
rte_errno = EINVAL;
return -rte_errno;
}
#ifdef HAVE_MLX5_HWS_SUPPORT
if (priv->sh->config.dv_flow_en == 2)
return mlx5_flow_hw_esw_create_sq_miss_flow(dev, sq_num);
#endif
flow = mlx5_flow_create_devx_sq_miss_flow(dev, sq_num);
if (flow > 0)
return 0;
DRV_LOG(ERR, "Port %u failed to create default miss flow for SQ %u.",
port_id, sq_num);
return -rte_errno;
}
/**
* Set the Tx queue dynamic timestamp (mask and offset)
*

View File

@ -139,6 +139,23 @@ int rte_pmd_mlx5_external_rx_queue_id_unmap(uint16_t port_id,
__rte_experimental
int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate, uint32_t flags);
/**
* Enable traffic for external SQ.
*
* @param[in] port_id
* The port identifier of the Ethernet device.
* @param[in] sq_num
* SQ HW number.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
* Possible values for rte_errno:
* - EINVAL - invalid sq_number or port type.
* - ENODEV - there is no Ethernet device for this port id.
*/
__rte_experimental
int rte_pmd_mlx5_external_sq_enable(uint16_t port_id, uint32_t sq_num);
#ifdef __cplusplus
}
#endif

View File

@ -14,4 +14,5 @@ EXPERIMENTAL {
rte_pmd_mlx5_external_rx_queue_id_unmap;
# added in 22.07
rte_pmd_mlx5_host_shaper_config;
rte_pmd_mlx5_external_sq_enable;
};