net/mlx5: add metadata register copy table
While reg_c[meta] can be copied to reg_b simply by modify-header action (it is supported by hardware), it is not possible to copy reg_c[mark] to the STE flow_tag as flow_tag is not a metadata register and this is not supported by hardware. Instead, it should be manually set by a flow per each unique MARK ID. For this purpose, there should be a dedicated flow table - RX_CP_TBL and all the Rx flow should pass by the table to properly copy values from the register to flow tag field. And for each MARK action, a copy flow should be added to RX_CP_TBL according to the MARK ID like: (if reg_c[mark] == mark_id), flow_tag := mark_id / reg_b := reg_c[meta] / jump to RX_ACT_TBL For SET_META action, there can be only one default flow like: reg_b := reg_c[meta] / jump to RX_ACT_TBL Signed-off-by: Yongseok Koh <yskoh@mellanox.com> Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com> Acked-by: Matan Azrad <matan@mellanox.com>
This commit is contained in:
parent
71e254bc02
commit
dd3c774f6f
@ -1039,6 +1039,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)
|
||||
priv->txqs = NULL;
|
||||
}
|
||||
mlx5_proc_priv_uninit(dev);
|
||||
if (priv->mreg_cp_tbl)
|
||||
mlx5_hlist_destroy(priv->mreg_cp_tbl, NULL, NULL);
|
||||
mlx5_mprq_free_mp(dev);
|
||||
mlx5_free_shared_dr(priv);
|
||||
if (priv->rss_conf.rss_key != NULL)
|
||||
@ -2458,9 +2460,22 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (priv->config.dv_flow_en &&
|
||||
priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
|
||||
mlx5_flow_ext_mreg_supported(eth_dev) &&
|
||||
priv->sh->dv_regc0_mask) {
|
||||
priv->mreg_cp_tbl = mlx5_hlist_create(MLX5_FLOW_MREG_HNAME,
|
||||
MLX5_FLOW_MREG_HTABLE_SZ);
|
||||
if (!priv->mreg_cp_tbl) {
|
||||
err = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return eth_dev;
|
||||
error:
|
||||
if (priv) {
|
||||
if (priv->mreg_cp_tbl)
|
||||
mlx5_hlist_destroy(priv->mreg_cp_tbl, NULL, NULL);
|
||||
if (priv->sh)
|
||||
mlx5_free_shared_dr(priv);
|
||||
if (priv->nl_socket_route >= 0)
|
||||
|
@ -569,8 +569,9 @@ struct mlx5_flow_tbl_resource {
|
||||
#define MLX5_HAIRPIN_TX_TABLE (UINT16_MAX - 1)
|
||||
/* Reserve the last two tables for metadata register copy. */
|
||||
#define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)
|
||||
#define MLX5_FLOW_MREG_CP_TABLE_GROUP \
|
||||
(MLX5_FLOW_MREG_ACT_TABLE_GROUP - 1)
|
||||
#define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)
|
||||
/* Tables for metering splits should be added here. */
|
||||
#define MLX5_MAX_TABLES_EXTERNAL (MLX5_MAX_TABLES - 3)
|
||||
#define MLX5_MAX_TABLES_FDB UINT16_MAX
|
||||
|
||||
#define MLX5_DBR_PAGE_SIZE 4096 /* Must be >= 512. */
|
||||
@ -736,6 +737,8 @@ struct mlx5_priv {
|
||||
LIST_HEAD(dbrpage, mlx5_devx_dbr_page) dbrpgs; /* Door-bell pages. */
|
||||
struct mlx5_vlan_vmwa_context *vmwa_context; /* VLAN WA context. */
|
||||
struct mlx5_flow_id_pool *qrss_id_pool;
|
||||
struct mlx5_hlist *mreg_cp_tbl;
|
||||
/* Hash table of Rx metadata register copy table. */
|
||||
#ifndef RTE_ARCH_64
|
||||
rte_spinlock_t uar_lock_cq; /* CQs share a common distinct UAR */
|
||||
rte_spinlock_t uar_lock[MLX5_UAR_PAGE_NUM_MAX];
|
||||
|
@ -145,6 +145,10 @@
|
||||
#define MLX5_XMETA_MODE_META16 1
|
||||
#define MLX5_XMETA_MODE_META32 2
|
||||
|
||||
/* Size of the simple hash table for metadata register table. */
|
||||
#define MLX5_FLOW_MREG_HTABLE_SZ 4096
|
||||
#define MLX5_FLOW_MREG_HNAME "MARK_COPY_TABLE"
|
||||
|
||||
/* Definition of static_assert found in /usr/include/assert.h */
|
||||
#ifndef HAVE_STATIC_ASSERT
|
||||
#define static_assert _Static_assert
|
||||
|
@ -675,7 +675,17 @@ flow_drv_rxq_flags_set(struct rte_eth_dev *dev, struct mlx5_flow *dev_flow)
|
||||
container_of((*priv->rxqs)[idx],
|
||||
struct mlx5_rxq_ctrl, rxq);
|
||||
|
||||
if (mark) {
|
||||
/*
|
||||
* To support metadata register copy on Tx loopback,
|
||||
* this must be always enabled (metadata may arive
|
||||
* from other port - not from local flows only.
|
||||
*/
|
||||
if (priv->config.dv_flow_en &&
|
||||
priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
|
||||
mlx5_flow_ext_mreg_supported(dev)) {
|
||||
rxq_ctrl->rxq.mark = 1;
|
||||
rxq_ctrl->flow_mark_n = 1;
|
||||
} else if (mark) {
|
||||
rxq_ctrl->rxq.mark = 1;
|
||||
rxq_ctrl->flow_mark_n++;
|
||||
}
|
||||
@ -739,7 +749,12 @@ flow_drv_rxq_flags_trim(struct rte_eth_dev *dev, struct mlx5_flow *dev_flow)
|
||||
container_of((*priv->rxqs)[idx],
|
||||
struct mlx5_rxq_ctrl, rxq);
|
||||
|
||||
if (mark) {
|
||||
if (priv->config.dv_flow_en &&
|
||||
priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
|
||||
mlx5_flow_ext_mreg_supported(dev)) {
|
||||
rxq_ctrl->rxq.mark = 1;
|
||||
rxq_ctrl->flow_mark_n = 1;
|
||||
} else if (mark) {
|
||||
rxq_ctrl->flow_mark_n--;
|
||||
rxq_ctrl->rxq.mark = !!rxq_ctrl->flow_mark_n;
|
||||
}
|
||||
@ -2749,6 +2764,398 @@ flow_check_hairpin_split(struct rte_eth_dev *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Declare flow create/destroy prototype in advance. */
|
||||
static struct rte_flow *
|
||||
flow_list_create(struct rte_eth_dev *dev, struct mlx5_flows *list,
|
||||
const struct rte_flow_attr *attr,
|
||||
const struct rte_flow_item items[],
|
||||
const struct rte_flow_action actions[],
|
||||
bool external, struct rte_flow_error *error);
|
||||
|
||||
static void
|
||||
flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,
|
||||
struct rte_flow *flow);
|
||||
|
||||
/**
|
||||
* Add a flow of copying flow metadata registers in RX_CP_TBL.
|
||||
*
|
||||
* As mark_id is unique, if there's already a registered flow for the mark_id,
|
||||
* return by increasing the reference counter of the resource. Otherwise, create
|
||||
* the resource (mcp_res) and flow.
|
||||
*
|
||||
* Flow looks like,
|
||||
* - If ingress port is ANY and reg_c[1] is mark_id,
|
||||
* flow_tag := mark_id, reg_b := reg_c[0] and jump to RX_ACT_TBL.
|
||||
*
|
||||
* For default flow (zero mark_id), flow is like,
|
||||
* - If ingress port is ANY,
|
||||
* reg_b := reg_c[0] and jump to RX_ACT_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
* @param mark_id
|
||||
* ID of MARK action, zero means default flow for META.
|
||||
* @param[out] error
|
||||
* Perform verbose error reporting if not NULL.
|
||||
*
|
||||
* @return
|
||||
* Associated resource on success, NULL otherwise and rte_errno is set.
|
||||
*/
|
||||
static struct mlx5_flow_mreg_copy_resource *
|
||||
flow_mreg_add_copy_action(struct rte_eth_dev *dev, uint32_t mark_id,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
struct mlx5_priv *priv = dev->data->dev_private;
|
||||
struct rte_flow_attr attr = {
|
||||
.group = MLX5_FLOW_MREG_CP_TABLE_GROUP,
|
||||
.ingress = 1,
|
||||
};
|
||||
struct mlx5_rte_flow_item_tag tag_spec = {
|
||||
.data = mark_id,
|
||||
};
|
||||
struct rte_flow_item items[] = {
|
||||
[1] = { .type = RTE_FLOW_ITEM_TYPE_END, },
|
||||
};
|
||||
struct rte_flow_action_mark ftag = {
|
||||
.id = mark_id,
|
||||
};
|
||||
struct mlx5_flow_action_copy_mreg cp_mreg = {
|
||||
.dst = REG_B,
|
||||
.src = 0,
|
||||
};
|
||||
struct rte_flow_action_jump jump = {
|
||||
.group = MLX5_FLOW_MREG_ACT_TABLE_GROUP,
|
||||
};
|
||||
struct rte_flow_action actions[] = {
|
||||
[3] = { .type = RTE_FLOW_ACTION_TYPE_END, },
|
||||
};
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res;
|
||||
int ret;
|
||||
|
||||
/* Fill the register fileds in the flow. */
|
||||
ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
tag_spec.id = ret;
|
||||
ret = mlx5_flow_get_reg_id(dev, MLX5_METADATA_RX, 0, error);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
cp_mreg.src = ret;
|
||||
/* Check if already registered. */
|
||||
assert(priv->mreg_cp_tbl);
|
||||
mcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl, mark_id);
|
||||
if (mcp_res) {
|
||||
/* For non-default rule. */
|
||||
if (mark_id)
|
||||
mcp_res->refcnt++;
|
||||
assert(mark_id || mcp_res->refcnt == 1);
|
||||
return mcp_res;
|
||||
}
|
||||
/* Provide the full width of FLAG specific value. */
|
||||
if (mark_id == (priv->sh->dv_regc0_mask & MLX5_FLOW_MARK_DEFAULT))
|
||||
tag_spec.data = MLX5_FLOW_MARK_DEFAULT;
|
||||
/* Build a new flow. */
|
||||
if (mark_id) {
|
||||
items[0] = (struct rte_flow_item){
|
||||
.type = MLX5_RTE_FLOW_ITEM_TYPE_TAG,
|
||||
.spec = &tag_spec,
|
||||
};
|
||||
items[1] = (struct rte_flow_item){
|
||||
.type = RTE_FLOW_ITEM_TYPE_END,
|
||||
};
|
||||
actions[0] = (struct rte_flow_action){
|
||||
.type = MLX5_RTE_FLOW_ACTION_TYPE_MARK,
|
||||
.conf = &ftag,
|
||||
};
|
||||
actions[1] = (struct rte_flow_action){
|
||||
.type = MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,
|
||||
.conf = &cp_mreg,
|
||||
};
|
||||
actions[2] = (struct rte_flow_action){
|
||||
.type = RTE_FLOW_ACTION_TYPE_JUMP,
|
||||
.conf = &jump,
|
||||
};
|
||||
actions[3] = (struct rte_flow_action){
|
||||
.type = RTE_FLOW_ACTION_TYPE_END,
|
||||
};
|
||||
} else {
|
||||
/* Default rule, wildcard match. */
|
||||
attr.priority = MLX5_FLOW_PRIO_RSVD;
|
||||
items[0] = (struct rte_flow_item){
|
||||
.type = RTE_FLOW_ITEM_TYPE_END,
|
||||
};
|
||||
actions[0] = (struct rte_flow_action){
|
||||
.type = MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,
|
||||
.conf = &cp_mreg,
|
||||
};
|
||||
actions[1] = (struct rte_flow_action){
|
||||
.type = RTE_FLOW_ACTION_TYPE_JUMP,
|
||||
.conf = &jump,
|
||||
};
|
||||
actions[2] = (struct rte_flow_action){
|
||||
.type = RTE_FLOW_ACTION_TYPE_END,
|
||||
};
|
||||
}
|
||||
/* Build a new entry. */
|
||||
mcp_res = rte_zmalloc(__func__, sizeof(*mcp_res), 0);
|
||||
if (!mcp_res) {
|
||||
rte_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* The copy Flows are not included in any list. There
|
||||
* ones are referenced from other Flows and can not
|
||||
* be applied, removed, deleted in ardbitrary order
|
||||
* by list traversing.
|
||||
*/
|
||||
mcp_res->flow = flow_list_create(dev, NULL, &attr, items,
|
||||
actions, false, error);
|
||||
if (!mcp_res->flow)
|
||||
goto error;
|
||||
mcp_res->refcnt++;
|
||||
mcp_res->hlist_ent.key = mark_id;
|
||||
ret = mlx5_hlist_insert(priv->mreg_cp_tbl,
|
||||
&mcp_res->hlist_ent);
|
||||
assert(!ret);
|
||||
if (ret)
|
||||
goto error;
|
||||
return mcp_res;
|
||||
error:
|
||||
if (mcp_res->flow)
|
||||
flow_list_destroy(dev, NULL, mcp_res->flow);
|
||||
rte_free(mcp_res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release flow in RX_CP_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
* @flow
|
||||
* Parent flow for wich copying is provided.
|
||||
*/
|
||||
static void
|
||||
flow_mreg_del_copy_action(struct rte_eth_dev *dev,
|
||||
struct rte_flow *flow)
|
||||
{
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res = flow->mreg_copy;
|
||||
struct mlx5_priv *priv = dev->data->dev_private;
|
||||
|
||||
if (!mcp_res || !priv->mreg_cp_tbl)
|
||||
return;
|
||||
if (flow->copy_applied) {
|
||||
assert(mcp_res->appcnt);
|
||||
flow->copy_applied = 0;
|
||||
--mcp_res->appcnt;
|
||||
if (!mcp_res->appcnt)
|
||||
flow_drv_remove(dev, mcp_res->flow);
|
||||
}
|
||||
/*
|
||||
* We do not check availability of metadata registers here,
|
||||
* because copy resources are allocated in this case.
|
||||
*/
|
||||
if (--mcp_res->refcnt)
|
||||
return;
|
||||
assert(mcp_res->flow);
|
||||
flow_list_destroy(dev, NULL, mcp_res->flow);
|
||||
mlx5_hlist_remove(priv->mreg_cp_tbl, &mcp_res->hlist_ent);
|
||||
rte_free(mcp_res);
|
||||
flow->mreg_copy = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start flow in RX_CP_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
* @flow
|
||||
* Parent flow for wich copying is provided.
|
||||
*
|
||||
* @return
|
||||
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
||||
*/
|
||||
static int
|
||||
flow_mreg_start_copy_action(struct rte_eth_dev *dev,
|
||||
struct rte_flow *flow)
|
||||
{
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res = flow->mreg_copy;
|
||||
int ret;
|
||||
|
||||
if (!mcp_res || flow->copy_applied)
|
||||
return 0;
|
||||
if (!mcp_res->appcnt) {
|
||||
ret = flow_drv_apply(dev, mcp_res->flow, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
++mcp_res->appcnt;
|
||||
flow->copy_applied = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop flow in RX_CP_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
* @flow
|
||||
* Parent flow for wich copying is provided.
|
||||
*/
|
||||
static void
|
||||
flow_mreg_stop_copy_action(struct rte_eth_dev *dev,
|
||||
struct rte_flow *flow)
|
||||
{
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res = flow->mreg_copy;
|
||||
|
||||
if (!mcp_res || !flow->copy_applied)
|
||||
return;
|
||||
assert(mcp_res->appcnt);
|
||||
--mcp_res->appcnt;
|
||||
flow->copy_applied = 0;
|
||||
if (!mcp_res->appcnt)
|
||||
flow_drv_remove(dev, mcp_res->flow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default copy action from RX_CP_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
*/
|
||||
static void
|
||||
flow_mreg_del_default_copy_action(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res;
|
||||
struct mlx5_priv *priv = dev->data->dev_private;
|
||||
|
||||
/* Check if default flow is registered. */
|
||||
if (!priv->mreg_cp_tbl)
|
||||
return;
|
||||
mcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl, 0ULL);
|
||||
if (!mcp_res)
|
||||
return;
|
||||
assert(mcp_res->flow);
|
||||
flow_list_destroy(dev, NULL, mcp_res->flow);
|
||||
mlx5_hlist_remove(priv->mreg_cp_tbl, &mcp_res->hlist_ent);
|
||||
rte_free(mcp_res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the default copy action in in RX_CP_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
* @param[out] error
|
||||
* Perform verbose error reporting if not NULL.
|
||||
*
|
||||
* @return
|
||||
* 0 for success, negative value otherwise and rte_errno is set.
|
||||
*/
|
||||
static int
|
||||
flow_mreg_add_default_copy_action(struct rte_eth_dev *dev,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
struct mlx5_priv *priv = dev->data->dev_private;
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res;
|
||||
|
||||
/* Check whether extensive metadata feature is engaged. */
|
||||
if (!priv->config.dv_flow_en ||
|
||||
priv->config.dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
|
||||
!mlx5_flow_ext_mreg_supported(dev) ||
|
||||
!priv->sh->dv_regc0_mask)
|
||||
return 0;
|
||||
mcp_res = flow_mreg_add_copy_action(dev, 0, error);
|
||||
if (!mcp_res)
|
||||
return -rte_errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a flow of copying flow metadata registers in RX_CP_TBL.
|
||||
*
|
||||
* All the flow having Q/RSS action should be split by
|
||||
* flow_mreg_split_qrss_prep() to pass by RX_CP_TBL. A flow in the RX_CP_TBL
|
||||
* performs the following,
|
||||
* - CQE->flow_tag := reg_c[1] (MARK)
|
||||
* - CQE->flow_table_metadata (reg_b) := reg_c[0] (META)
|
||||
* As CQE's flow_tag is not a register, it can't be simply copied from reg_c[1]
|
||||
* but there should be a flow per each MARK ID set by MARK action.
|
||||
*
|
||||
* For the aforementioned reason, if there's a MARK action in flow's action
|
||||
* list, a corresponding flow should be added to the RX_CP_TBL in order to copy
|
||||
* the MARK ID to CQE's flow_tag like,
|
||||
* - If reg_c[1] is mark_id,
|
||||
* flow_tag := mark_id, reg_b := reg_c[0] and jump to RX_ACT_TBL.
|
||||
*
|
||||
* For SET_META action which stores value in reg_c[0], as the destination is
|
||||
* also a flow metadata register (reg_b), adding a default flow is enough. Zero
|
||||
* MARK ID means the default flow. The default flow looks like,
|
||||
* - For all flow, reg_b := reg_c[0] and jump to RX_ACT_TBL.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device.
|
||||
* @param flow
|
||||
* Pointer to flow structure.
|
||||
* @param[in] actions
|
||||
* Pointer to the list of actions.
|
||||
* @param[out] error
|
||||
* Perform verbose error reporting if not NULL.
|
||||
*
|
||||
* @return
|
||||
* 0 on success, negative value otherwise and rte_errno is set.
|
||||
*/
|
||||
static int
|
||||
flow_mreg_update_copy_table(struct rte_eth_dev *dev,
|
||||
struct rte_flow *flow,
|
||||
const struct rte_flow_action *actions,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
struct mlx5_priv *priv = dev->data->dev_private;
|
||||
struct mlx5_dev_config *config = &priv->config;
|
||||
struct mlx5_flow_mreg_copy_resource *mcp_res;
|
||||
const struct rte_flow_action_mark *mark;
|
||||
|
||||
/* Check whether extensive metadata feature is engaged. */
|
||||
if (!config->dv_flow_en ||
|
||||
config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
|
||||
!mlx5_flow_ext_mreg_supported(dev) ||
|
||||
!priv->sh->dv_regc0_mask)
|
||||
return 0;
|
||||
/* Find MARK action. */
|
||||
for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
|
||||
switch (actions->type) {
|
||||
case RTE_FLOW_ACTION_TYPE_FLAG:
|
||||
mcp_res = flow_mreg_add_copy_action
|
||||
(dev, MLX5_FLOW_MARK_DEFAULT, error);
|
||||
if (!mcp_res)
|
||||
return -rte_errno;
|
||||
flow->mreg_copy = mcp_res;
|
||||
if (dev->data->dev_started) {
|
||||
mcp_res->appcnt++;
|
||||
flow->copy_applied = 1;
|
||||
}
|
||||
return 0;
|
||||
case RTE_FLOW_ACTION_TYPE_MARK:
|
||||
mark = (const struct rte_flow_action_mark *)
|
||||
actions->conf;
|
||||
mcp_res =
|
||||
flow_mreg_add_copy_action(dev, mark->id, error);
|
||||
if (!mcp_res)
|
||||
return -rte_errno;
|
||||
flow->mreg_copy = mcp_res;
|
||||
if (dev->data->dev_started) {
|
||||
mcp_res->appcnt++;
|
||||
flow->copy_applied = 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MLX5_MAX_SPLIT_ACTIONS 24
|
||||
#define MLX5_MAX_SPLIT_ITEMS 24
|
||||
|
||||
@ -3472,6 +3879,22 @@ flow_list_create(struct rte_eth_dev *dev, struct mlx5_flows *list,
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* Update the metadata register copy table. If extensive
|
||||
* metadata feature is enabled and registers are supported
|
||||
* we might create the extra rte_flow for each unique
|
||||
* MARK/FLAG action ID.
|
||||
*
|
||||
* The table is updated for ingress Flows only, because
|
||||
* the egress Flows belong to the different device and
|
||||
* copy table should be updated in peer NIC Rx domain.
|
||||
*/
|
||||
if (attr->ingress &&
|
||||
(external || attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP)) {
|
||||
ret = flow_mreg_update_copy_table(dev, flow, actions, error);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
if (dev->data->dev_started) {
|
||||
ret = flow_drv_apply(dev, flow, error);
|
||||
if (ret < 0)
|
||||
@ -3487,6 +3910,8 @@ flow_list_create(struct rte_eth_dev *dev, struct mlx5_flows *list,
|
||||
hairpin_id);
|
||||
return NULL;
|
||||
error:
|
||||
assert(flow);
|
||||
flow_mreg_del_copy_action(dev, flow);
|
||||
ret = rte_errno; /* Save rte_errno before cleanup. */
|
||||
if (flow->hairpin_flow_id)
|
||||
mlx5_flow_id_release(priv->sh->flow_id_pool,
|
||||
@ -3595,6 +4020,7 @@ flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,
|
||||
flow_drv_destroy(dev, flow);
|
||||
if (list)
|
||||
TAILQ_REMOVE(list, flow, next);
|
||||
flow_mreg_del_copy_action(dev, flow);
|
||||
rte_free(flow->fdir);
|
||||
rte_free(flow);
|
||||
}
|
||||
@ -3631,8 +4057,11 @@ mlx5_flow_stop(struct rte_eth_dev *dev, struct mlx5_flows *list)
|
||||
{
|
||||
struct rte_flow *flow;
|
||||
|
||||
TAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next)
|
||||
TAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next) {
|
||||
flow_drv_remove(dev, flow);
|
||||
flow_mreg_stop_copy_action(dev, flow);
|
||||
}
|
||||
flow_mreg_del_default_copy_action(dev);
|
||||
flow_rxq_flags_clear(dev);
|
||||
}
|
||||
|
||||
@ -3654,7 +4083,15 @@ mlx5_flow_start(struct rte_eth_dev *dev, struct mlx5_flows *list)
|
||||
struct rte_flow_error error;
|
||||
int ret = 0;
|
||||
|
||||
/* Make sure default copy action (reg_c[0] -> reg_b) is created. */
|
||||
ret = flow_mreg_add_default_copy_action(dev, &error);
|
||||
if (ret < 0)
|
||||
return -rte_errno;
|
||||
/* Apply Flows created by application. */
|
||||
TAILQ_FOREACH(flow, list, next) {
|
||||
ret = flow_mreg_start_copy_action(dev, flow);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
ret = flow_drv_apply(dev, flow, &error);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
@ -38,6 +38,7 @@ enum mlx5_rte_flow_item_type {
|
||||
enum mlx5_rte_flow_action_type {
|
||||
MLX5_RTE_FLOW_ACTION_TYPE_END = INT_MIN,
|
||||
MLX5_RTE_FLOW_ACTION_TYPE_TAG,
|
||||
MLX5_RTE_FLOW_ACTION_TYPE_MARK,
|
||||
MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,
|
||||
};
|
||||
|
||||
@ -417,6 +418,21 @@ struct mlx5_flow_dv_push_vlan_action_resource {
|
||||
rte_be32_t vlan_tag; /**< VLAN tag value. */
|
||||
};
|
||||
|
||||
/* Metadata register copy table entry. */
|
||||
struct mlx5_flow_mreg_copy_resource {
|
||||
/*
|
||||
* Hash list entry for copy table.
|
||||
* - Key is 32/64-bit MARK action ID.
|
||||
* - MUST be the first entry.
|
||||
*/
|
||||
struct mlx5_hlist_entry hlist_ent;
|
||||
LIST_ENTRY(mlx5_flow_mreg_copy_resource) next;
|
||||
/* List entry for device flows. */
|
||||
uint32_t refcnt; /* Reference counter. */
|
||||
uint32_t appcnt; /* Apply/Remove counter. */
|
||||
struct rte_flow *flow; /* Built flow for copy. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Max number of actions per DV flow.
|
||||
* See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
|
||||
@ -510,10 +526,13 @@ struct rte_flow {
|
||||
enum mlx5_flow_drv_type drv_type; /**< Driver type. */
|
||||
struct mlx5_flow_rss rss; /**< RSS context. */
|
||||
struct mlx5_flow_counter *counter; /**< Holds flow counter. */
|
||||
struct mlx5_flow_mreg_copy_resource *mreg_copy;
|
||||
/**< pointer to metadata register copy table resource. */
|
||||
LIST_HEAD(dev_flows, mlx5_flow) dev_flows;
|
||||
/**< Device flows that are part of the flow. */
|
||||
struct mlx5_fdir *fdir; /**< Pointer to associated FDIR if any. */
|
||||
uint32_t hairpin_flow_id; /**< The flow id used for hairpin. */
|
||||
uint32_t copy_applied:1; /**< The MARK copy Flow os applied. */
|
||||
};
|
||||
|
||||
typedef int (*mlx5_flow_validate_t)(struct rte_eth_dev *dev,
|
||||
|
@ -4086,8 +4086,11 @@ flow_dv_validate_attributes(struct rte_eth_dev *dev,
|
||||
NULL,
|
||||
"groups are not supported");
|
||||
#else
|
||||
uint32_t max_group = attributes->transfer ? MLX5_MAX_TABLES_FDB :
|
||||
MLX5_MAX_TABLES;
|
||||
uint32_t max_group = attributes->transfer ?
|
||||
MLX5_MAX_TABLES_FDB :
|
||||
external ?
|
||||
MLX5_MAX_TABLES_EXTERNAL :
|
||||
MLX5_MAX_TABLES;
|
||||
uint32_t table;
|
||||
int ret;
|
||||
|
||||
@ -4721,6 +4724,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
|
||||
MLX5_FLOW_ACTION_DEC_TCP_ACK;
|
||||
break;
|
||||
case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
|
||||
case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
|
||||
case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
|
||||
break;
|
||||
default:
|
||||
@ -6557,6 +6561,8 @@ __flow_dv_translate(struct rte_eth_dev *dev,
|
||||
action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
|
||||
break;
|
||||
}
|
||||
/* Fall-through */
|
||||
case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
|
||||
/* Legacy (non-extensive) MARK action. */
|
||||
tag_resource.tag = mlx5_flow_mark_set
|
||||
(((const struct rte_flow_action_mark *)
|
||||
|
Loading…
Reference in New Issue
Block a user