* [dpdk-dev] [PATCH v1 1/4] net/mlx5: support meter action in meter policy
2021-07-06 13:14 [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Shun Hao
@ 2021-07-06 13:14 ` Shun Hao
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 2/4] net/mlx5: support meter hierarchy drop count Shun Hao
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Shun Hao @ 2021-07-06 13:14 UTC (permalink / raw)
To: orika, viacheslavo, matan, Shahaf Shuler; +Cc: dev, thomas, rasland
This makes the meter policy support meter action. So multiple meters
can be chained as a meter hierarchy.
Only termination meter is allowed as the last meter in a hierarchy,
and there're two cases:
1. The last meter has non-RSS policy, can directly create sub-policy
and color rules during each meter's policy creation.
2. The last meter has RSS policy, don't create sub-policy/rules when
creating meter policy. Only when a RTE flow is using the meter hierarchy,
will iterate all meters of the hierarchy and create neede sub-
policies and color rules for them.
Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
drivers/net/mlx5/mlx5.h | 12 ++
drivers/net/mlx5/mlx5_flow.c | 71 +++++---
drivers/net/mlx5/mlx5_flow.h | 5 +
drivers/net/mlx5/mlx5_flow_dv.c | 270 ++++++++++++++++++++++++-----
drivers/net/mlx5/mlx5_flow_meter.c | 43 ++++-
5 files changed, 332 insertions(+), 69 deletions(-)
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 0f4b239142..0c555f0b1f 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -677,6 +677,12 @@ struct mlx5_meter_policy_action_container {
/* Jump/drop action per color. */
uint16_t queue;
/* Queue action configuration. */
+ struct {
+ uint32_t next_mtr_id;
+ /* The next meter id. */
+ void *next_sub_policy;
+ /* Next meter's sub-policy. */
+ };
};
};
@@ -694,6 +700,8 @@ struct mlx5_flow_meter_policy {
/* Rule applies to transfer domain. */
uint32_t is_queue:1;
/* Is queue action in policy table. */
+ uint32_t is_hierarchy:1;
+ /* Is meter action in policy table. */
rte_spinlock_t sl;
uint32_t ref_cnt;
/* Use count. */
@@ -712,6 +720,7 @@ struct mlx5_flow_meter_policy {
#define MLX5_MTR_SUB_POLICY_NUM_SHIFT 3
#define MLX5_MTR_SUB_POLICY_NUM_MASK 0x7
#define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
+#define MLX5_MTR_CHAIN_MAX_NUM 8
/* Flow meter default policy parameter structure.
* Policy index 0 is reserved by default policy table.
@@ -1669,6 +1678,9 @@ struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
(struct rte_eth_dev *dev,
uint32_t policy_id,
uint32_t *policy_idx);
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *policy);
int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
struct rte_mtr_error *error);
void mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index c27f6197a0..6c4bfde098 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3492,10 +3492,18 @@ flow_get_rss_action(struct rte_eth_dev *dev,
const struct rte_flow_action_meter *mtr = actions->conf;
fm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);
- if (fm) {
+ if (fm && !fm->def_policy) {
policy = mlx5_flow_meter_policy_find(dev,
fm->policy_id, NULL);
- if (policy && policy->is_rss)
+ MLX5_ASSERT(policy);
+ if (policy->is_hierarchy) {
+ policy =
+ mlx5_flow_meter_hierarchy_get_final_policy(dev,
+ policy);
+ if (!policy)
+ return NULL;
+ }
+ if (policy->is_rss)
rss =
policy->act_cnt[RTE_COLOR_GREEN].rss->conf;
}
@@ -4564,8 +4572,8 @@ flow_create_split_inner(struct rte_eth_dev *dev,
* Pointer to Ethernet device.
* @param[in] flow
* Parent flow structure pointer.
- * @param[in] policy_id;
- * Meter Policy id.
+ * @param wks
+ * Pointer to thread flow work space.
* @param[in] attr
* Flow rule attributes.
* @param[in] items
@@ -4579,31 +4587,22 @@ flow_create_split_inner(struct rte_eth_dev *dev,
static struct mlx5_flow_meter_sub_policy *
get_meter_sub_policy(struct rte_eth_dev *dev,
struct rte_flow *flow,
- uint32_t policy_id,
+ struct mlx5_flow_workspace *wks,
const struct rte_flow_attr *attr,
const struct rte_flow_item items[],
struct rte_flow_error *error)
{
struct mlx5_flow_meter_policy *policy;
+ struct mlx5_flow_meter_policy *final_policy;
struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
- policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
- if (!policy) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
- "Failed to find Meter Policy.");
- goto exit;
- }
- if (policy->is_rss ||
- (policy->is_queue &&
- !policy->sub_policys[MLX5_MTR_DOMAIN_INGRESS][0]->rix_hrxq[0])) {
- struct mlx5_flow_workspace *wks =
- mlx5_flow_get_thread_workspace();
+ policy = wks->policy;
+ final_policy = policy->is_hierarchy ? wks->final_policy : policy;
+ if (final_policy->is_rss || final_policy->is_queue) {
struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
uint32_t i;
- MLX5_ASSERT(wks);
/**
* This is a tmp dev_flow,
* no need to register any matcher for it in translate.
@@ -4613,9 +4612,9 @@ get_meter_sub_policy(struct rte_eth_dev *dev,
struct mlx5_flow dev_flow = {0};
struct mlx5_flow_handle dev_handle = { {0} };
- if (policy->is_rss) {
+ if (final_policy->is_rss) {
const void *rss_act =
- policy->act_cnt[i].rss->conf;
+ final_policy->act_cnt[i].rss->conf;
struct rte_flow_action rss_actions[2] = {
[0] = {
.type = RTE_FLOW_ACTION_TYPE_RSS,
@@ -4656,7 +4655,7 @@ get_meter_sub_policy(struct rte_eth_dev *dev,
rss_desc_v[i].key_len = 0;
rss_desc_v[i].hash_fields = 0;
rss_desc_v[i].queue =
- &policy->act_cnt[i].queue;
+ &final_policy->act_cnt[i].queue;
rss_desc_v[i].queue_num = 1;
}
rss_desc[i] = &rss_desc_v[i];
@@ -4696,8 +4695,8 @@ get_meter_sub_policy(struct rte_eth_dev *dev,
* Pointer to Ethernet device.
* @param[in] flow
* Parent flow structure pointer.
- * @param[in] fm
- * Pointer to flow meter structure.
+ * @param wks
+ * Pointer to thread flow work space.
* @param[in] attr
* Flow rule attributes.
* @param[in] items
@@ -4721,7 +4720,7 @@ get_meter_sub_policy(struct rte_eth_dev *dev,
static int
flow_meter_split_prep(struct rte_eth_dev *dev,
struct rte_flow *flow,
- struct mlx5_flow_meter_info *fm,
+ struct mlx5_flow_workspace *wks,
const struct rte_flow_attr *attr,
const struct rte_flow_item items[],
struct rte_flow_item sfx_items[],
@@ -4732,6 +4731,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_info *fm = wks->fm;
struct rte_flow_action *tag_action = NULL;
struct rte_flow_item *tag_item;
struct mlx5_rte_flow_action_set_tag *set_tag;
@@ -4856,9 +4856,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
struct mlx5_flow_tbl_data_entry *tbl_data;
if (!fm->def_policy) {
- sub_policy = get_meter_sub_policy(dev, flow,
- fm->policy_id, attr,
- items, error);
+ sub_policy = get_meter_sub_policy(dev, flow, wks,
+ attr, items, error);
if (!sub_policy)
return -rte_errno;
} else {
@@ -5746,6 +5745,22 @@ flow_create_split_meter(struct rte_eth_dev *dev,
}
MLX5_ASSERT(wks);
wks->fm = fm;
+ if (!fm->def_policy) {
+ wks->policy = mlx5_flow_meter_policy_find(dev,
+ fm->policy_id,
+ NULL);
+ MLX5_ASSERT(wks->policy);
+ if (wks->policy->is_hierarchy) {
+ wks->final_policy =
+ mlx5_flow_meter_hierarchy_get_final_policy(dev,
+ wks->policy);
+ if (!wks->final_policy)
+ return rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to find terminal policy of hierarchy.");
+ }
+ }
/*
* If it isn't default-policy Meter, and
* 1. There's no action in flow to change
@@ -5776,7 +5791,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
pre_actions = sfx_actions + 1;
else
pre_actions = sfx_actions + actions_n;
- ret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+ ret = flow_meter_split_prep(dev, flow, wks, &sfx_attr,
items, sfx_items, actions,
sfx_actions, pre_actions,
(set_mtr_reg ? &mtr_flow_id : NULL),
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 2f2aa962f9..09d6d609db 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -454,6 +454,7 @@ enum mlx5_flow_fate_type {
MLX5_FLOW_FATE_DROP,
MLX5_FLOW_FATE_DEFAULT_MISS,
MLX5_FLOW_FATE_SHARED_RSS,
+ MLX5_FLOW_FATE_MTR,
MLX5_FLOW_FATE_MAX,
};
@@ -1102,6 +1103,10 @@ struct mlx5_flow_workspace {
uint32_t rssq_num; /* Allocated queue num in rss_desc. */
uint32_t flow_idx; /* Intermediate device flow index. */
struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
+ struct mlx5_flow_meter_policy *policy;
+ /* The meter policy used by meter in flow. */
+ struct mlx5_flow_meter_policy *final_policy;
+ /* The final policy when meter policy is hierarchy. */
uint32_t skip_matcher_reg:1;
/* Indicates if need to skip matcher register in translate. */
};
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 75ef6216ac..d34f5214a8 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7864,6 +7864,8 @@ flow_dv_prepare(struct rte_eth_dev *dev,
MLX5_ASSERT(wks);
wks->skip_matcher_reg = 0;
+ wks->policy = NULL;
+ wks->final_policy = NULL;
/* In case of corrupting the memory. */
if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
rte_flow_error_set(error, ENOSPC,
@@ -15028,6 +15030,37 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
action_flags |= MLX5_FLOW_ACTION_JUMP;
break;
}
+ case RTE_FLOW_ACTION_TYPE_METER:
+ {
+ const struct rte_flow_action_meter *mtr;
+ struct mlx5_flow_meter_info *next_fm;
+ struct mlx5_flow_meter_policy *next_policy;
+ uint32_t next_mtr_idx = 0;
+
+ mtr = act->conf;
+ next_fm = mlx5_flow_meter_find(priv,
+ mtr->mtr_id,
+ &next_mtr_idx);
+ if (!next_fm)
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+ "Fail to find next meter.");
+ if (next_fm->def_policy)
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+ "Hierarchy only supports termination meter.");
+ next_policy = mlx5_flow_meter_policy_find(dev,
+ next_fm->policy_id, NULL);
+ MLX5_ASSERT(next_policy);
+ act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
+ act_cnt->next_mtr_id = next_fm->meter_id;
+ act_cnt->next_sub_policy = NULL;
+ mtr_policy->is_hierarchy = 1;
+ mtr_policy->dev = next_policy->dev;
+ action_flags |=
+ MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
+ break;
+ }
default:
return -rte_mtr_error_set(error, ENOTSUP,
RTE_MTR_ERROR_TYPE_METER_POLICY,
@@ -15563,7 +15596,14 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
struct mlx5_flow_dv_tag_resource *tag;
struct mlx5_flow_dv_port_id_action_resource *port_action;
struct mlx5_hrxq *hrxq;
- uint8_t egress, transfer;
+ struct mlx5_flow_meter_info *next_fm = NULL;
+ struct mlx5_flow_meter_policy *next_policy;
+ struct mlx5_flow_meter_sub_policy *next_sub_policy;
+ struct mlx5_flow_tbl_data_entry *tbl_data;
+ struct rte_flow_error error;
+ uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+ uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+ bool mtr_first = egress || (transfer && priv->representor_id != 0xffff);
bool match_src_port = false;
int i;
@@ -15578,13 +15618,39 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
acts[i].actions_n = 1;
continue;
}
+ if (mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
+ struct rte_flow_attr attr = {
+ .transfer = transfer
+ };
+
+ next_fm = mlx5_flow_meter_find(priv,
+ mtr_policy->act_cnt[i].next_mtr_id,
+ NULL);
+ if (!next_fm) {
+ DRV_LOG(ERR,
+ "Failed to get next hierarchy meter.");
+ goto err_exit;
+ }
+ if (mlx5_flow_meter_attach(priv, next_fm,
+ &attr, &error)) {
+ DRV_LOG(ERR, "%s", error.message);
+ next_fm = NULL;
+ goto err_exit;
+ }
+ /* Meter action must be the first for TX. */
+ if (mtr_first) {
+ acts[i].dv_actions[acts[i].actions_n] =
+ next_fm->meter_action;
+ acts[i].actions_n++;
+ }
+ }
if (mtr_policy->act_cnt[i].rix_mark) {
tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
mtr_policy->act_cnt[i].rix_mark);
if (!tag) {
DRV_LOG(ERR, "Failed to find "
"mark action for policy.");
- return -1;
+ goto err_exit;
}
acts[i].dv_actions[acts[i].actions_n] =
tag->action;
@@ -15604,7 +15670,7 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
if (!port_action) {
DRV_LOG(ERR, "Failed to find "
"port action for policy.");
- return -1;
+ goto err_exit;
}
acts[i].dv_actions[acts[i].actions_n] =
port_action->action;
@@ -15626,12 +15692,42 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
if (!hrxq) {
DRV_LOG(ERR, "Failed to find "
"queue action for policy.");
- return -1;
+ goto err_exit;
}
acts[i].dv_actions[acts[i].actions_n] =
hrxq->action;
acts[i].actions_n++;
break;
+ case MLX5_FLOW_FATE_MTR:
+ if (!next_fm) {
+ DRV_LOG(ERR,
+ "No next hierarchy meter.");
+ goto err_exit;
+ }
+ if (!mtr_first) {
+ acts[i].dv_actions[acts[i].actions_n] =
+ next_fm->meter_action;
+ acts[i].actions_n++;
+ }
+ if (mtr_policy->act_cnt[i].next_sub_policy) {
+ next_sub_policy =
+ mtr_policy->act_cnt[i].next_sub_policy;
+ } else {
+ next_policy =
+ mlx5_flow_meter_policy_find(dev,
+ next_fm->policy_id, NULL);
+ MLX5_ASSERT(next_policy);
+ next_sub_policy =
+ next_policy->sub_policys[domain][0];
+ }
+ tbl_data =
+ container_of(next_sub_policy->tbl_rsc,
+ struct mlx5_flow_tbl_data_entry, tbl);
+ acts[i].dv_actions[acts[i].actions_n++] =
+ tbl_data->jump.action;
+ if (mtr_policy->act_cnt[i].modify_hdr)
+ match_src_port = !!transfer;
+ break;
default:
/*Queue action do nothing*/
break;
@@ -15644,9 +15740,13 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
egress, transfer, match_src_port, acts)) {
DRV_LOG(ERR,
"Failed to create policy rules per domain.");
- return -1;
+ goto err_exit;
}
return 0;
+err_exit:
+ if (next_fm)
+ mlx5_flow_meter_detach(priv, next_fm);
+ return -1;
}
/**
@@ -15956,22 +16056,12 @@ flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
return -1;
}
-/**
- * Find the policy table for prefix table with RSS.
- *
- * @param[in] dev
- * Pointer to Ethernet device.
- * @param[in] mtr_policy
- * Pointer to meter policy table.
- * @param[in] rss_desc
- * Pointer to rss_desc
- * @return
- * Pointer to table set on success, NULL otherwise and rte_errno is set.
- */
static struct mlx5_flow_meter_sub_policy *
-flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+__flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev,
struct mlx5_flow_meter_policy *mtr_policy,
- struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+ struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS],
+ struct mlx5_flow_meter_sub_policy *next_sub_policy,
+ bool *is_reuse)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
@@ -16013,6 +16103,7 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
rte_spinlock_unlock(&mtr_policy->sl);
for (j = 0; j < MLX5_MTR_RTE_COLORS; j++)
mlx5_hrxq_release(dev, hrxq_idx[j]);
+ *is_reuse = true;
return mtr_policy->sub_policys[domain][i];
}
}
@@ -16038,24 +16129,30 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
if (!rss_desc[i])
continue;
sub_policy->rix_hrxq[i] = hrxq_idx[i];
- /*
- * Overwrite the last action from
- * RSS action to Queue action.
- */
- hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
- hrxq_idx[i]);
- if (!hrxq) {
- DRV_LOG(ERR, "Failed to create policy hrxq");
- goto rss_sub_policy_error;
- }
- act_cnt = &mtr_policy->act_cnt[i];
- if (act_cnt->rix_mark || act_cnt->modify_hdr) {
- memset(&dh, 0, sizeof(struct mlx5_flow_handle));
- if (act_cnt->rix_mark)
- dh.mark = 1;
- dh.fate_action = MLX5_FLOW_FATE_QUEUE;
- dh.rix_hrxq = hrxq_idx[i];
- flow_drv_rxq_flags_set(dev, &dh);
+ if (mtr_policy->is_hierarchy) {
+ act_cnt = &mtr_policy->act_cnt[i];
+ act_cnt->next_sub_policy = next_sub_policy;
+ mlx5_hrxq_release(dev, hrxq_idx[i]);
+ } else {
+ /*
+ * Overwrite the last action from
+ * RSS action to Queue action.
+ */
+ hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+ hrxq_idx[i]);
+ if (!hrxq) {
+ DRV_LOG(ERR, "Failed to create policy hrxq");
+ goto rss_sub_policy_error;
+ }
+ act_cnt = &mtr_policy->act_cnt[i];
+ if (act_cnt->rix_mark || act_cnt->modify_hdr) {
+ memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+ if (act_cnt->rix_mark)
+ dh.mark = 1;
+ dh.fate_action = MLX5_FLOW_FATE_QUEUE;
+ dh.rix_hrxq = hrxq_idx[i];
+ flow_drv_rxq_flags_set(dev, &dh);
+ }
}
}
if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
@@ -16079,6 +16176,7 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
}
rte_spinlock_unlock(&mtr_policy->sl);
+ *is_reuse = false;
return sub_policy;
rss_sub_policy_error:
if (sub_policy) {
@@ -16093,13 +16191,105 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
sub_policy->idx);
}
}
- if (sub_policy_idx)
- mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
- sub_policy_idx);
rte_spinlock_unlock(&mtr_policy->sl);
return NULL;
}
+/**
+ * Find the policy table for prefix table with RSS.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] mtr_policy
+ * Pointer to meter policy table.
+ * @param[in] rss_desc
+ * Pointer to rss_desc
+ * @return
+ * Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy,
+ struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+ struct mlx5_flow_meter_info *next_fm;
+ struct mlx5_flow_meter_policy *next_policy;
+ struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL;
+ struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM];
+ struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM];
+ uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
+ bool reuse_sub_policy;
+ uint32_t i = 0;
+ uint32_t j = 0;
+
+ while (true) {
+ /* Iterate hierarchy to get all policies in this hierarchy. */
+ policies[i++] = mtr_policy;
+ if (!mtr_policy->is_hierarchy)
+ break;
+ if (i >= MLX5_MTR_CHAIN_MAX_NUM) {
+ DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
+ return NULL;
+ }
+ next_fm = mlx5_flow_meter_find(priv,
+ mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
+ if (!next_fm) {
+ DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
+ return NULL;
+ }
+ next_policy =
+ mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
+ NULL);
+ MLX5_ASSERT(next_policy);
+ mtr_policy = next_policy;
+ }
+ while (i) {
+ /**
+ * From last policy to the first one in hierarchy,
+ * create/get the sub policy for each of them.
+ */
+ sub_policy = __flow_dv_meter_get_rss_sub_policy(dev,
+ policies[--i],
+ rss_desc,
+ next_sub_policy,
+ &reuse_sub_policy);
+ if (!sub_policy) {
+ DRV_LOG(ERR, "Failed to get the sub policy.");
+ goto err_exit;
+ }
+ if (!reuse_sub_policy)
+ sub_policies[j++] = sub_policy;
+ next_sub_policy = sub_policy;
+ }
+ return sub_policy;
+err_exit:
+ while (j) {
+ uint16_t sub_policy_num;
+
+ sub_policy = sub_policies[--j];
+ mtr_policy = sub_policy->main_policy;
+ __flow_dv_destroy_sub_policy_rules(dev, sub_policy);
+ if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+ sub_policy_num = (mtr_policy->sub_policy_num >>
+ (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+ MLX5_MTR_SUB_POLICY_NUM_MASK;
+ mtr_policy->sub_policys[domain][sub_policy_num - 1] =
+ NULL;
+ sub_policy_num--;
+ mtr_policy->sub_policy_num &=
+ ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+ (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
+ mtr_policy->sub_policy_num |=
+ (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+ (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
+ mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+ sub_policy->idx);
+ }
+ }
+ return NULL;
+}
/**
* Destroy the sub policy table with RX queue.
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 6f962a8d52..03f7e120e1 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -529,6 +529,37 @@ mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
return NULL;
}
+/**
+ * Get the last meter's policy from one meter's policy in hierarchy.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] policy
+ * Pointer to flow meter policy.
+ *
+ * @return
+ * Pointer to the final meter's policy, or NULL when fail.
+ */
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *policy)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_info *next_fm;
+ struct mlx5_flow_meter_policy *next_policy = policy;
+
+ while (next_policy->is_hierarchy) {
+ next_fm = mlx5_flow_meter_find(priv,
+ next_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
+ if (!next_fm || next_fm->def_policy)
+ return NULL;
+ next_policy = mlx5_flow_meter_policy_find(dev,
+ next_fm->policy_id, NULL);
+ MLX5_ASSERT(next_policy);
+ }
+ return next_policy;
+}
+
/**
* Callback to check MTR policy action validate
*
@@ -650,6 +681,7 @@ mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
uint16_t sub_policy_num;
uint8_t domain_bitmap = 0;
union mlx5_l3t_data data;
+ bool skip_rule = false;
if (!priv->mtr_en)
return -rte_mtr_error_set(error, ENOTSUP,
@@ -759,7 +791,16 @@ mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
policy->actions, error);
if (ret)
goto policy_add_err;
- if (!is_rss && !mtr_policy->is_queue) {
+ if (mtr_policy->is_hierarchy) {
+ struct mlx5_flow_meter_policy *final_policy;
+
+ final_policy =
+ mlx5_flow_meter_hierarchy_get_final_policy(dev, mtr_policy);
+ if (!final_policy)
+ goto policy_add_err;
+ skip_rule = (final_policy->is_rss || final_policy->is_queue);
+ }
+ if (!is_rss && !mtr_policy->is_queue && !skip_rule) {
/* Create policy rules in HW. */
ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
if (ret)
--
2.21.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [dpdk-dev] [PATCH v1 2/4] net/mlx5: support meter hierarchy drop count
2021-07-06 13:14 [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Shun Hao
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 1/4] net/mlx5: support meter action in meter policy Shun Hao
@ 2021-07-06 13:14 ` Shun Hao
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 3/4] net/mlx5: meter hierarchy destroy and cleanup Shun Hao
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Shun Hao @ 2021-07-06 13:14 UTC (permalink / raw)
To: orika, viacheslavo, matan, Shahaf Shuler; +Cc: dev, thomas, rasland
When using meter hierarchy with multiple meters, every meter may have
drop counter, so a packet being set red color by one meter should be
counted to that specific meter only.
To support this, add tag action in the color rule so packet going to
next new meter can have its meter id, so as to be counted to the
correct drop counter in drop table.
Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
drivers/net/mlx5/mlx5.h | 20 +-
drivers/net/mlx5/mlx5_flow.c | 52 +++++-
drivers/net/mlx5/mlx5_flow.h | 7 +
drivers/net/mlx5/mlx5_flow_dv.c | 318 ++++++++++++++++++++++++++------
4 files changed, 339 insertions(+), 58 deletions(-)
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 0c555f0b1f..e5c9ec0777 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -631,6 +631,20 @@ enum mlx5_meter_domain {
MLX5_MTR_DOMAIN_EGRESS_BIT | \
MLX5_MTR_DOMAIN_TRANSFER_BIT)
+/* The color tag rule structure. */
+struct mlx5_sub_policy_color_rule {
+ void *rule;
+ /* The color rule. */
+ struct mlx5_flow_dv_matcher *matcher;
+ /* The color matcher. */
+ TAILQ_ENTRY(mlx5_sub_policy_color_rule) next_port;
+ /**< Pointer to the next color rule structure. */
+ int32_t src_port;
+ /* On which src port this rule applied. */
+};
+
+TAILQ_HEAD(mlx5_sub_policy_color_rules, mlx5_sub_policy_color_rule);
+
/*
* Meter sub-policy structure.
* Each RSS TIR in meter policy need its own sub-policy resource.
@@ -648,10 +662,8 @@ struct mlx5_flow_meter_sub_policy {
/* Index to TIR resource. */
struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
/* Meter jump/drop table. */
- struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
- /* Matcher for Color. */
- void *color_rule[RTE_COLORS];
- /* Meter green/yellow/drop rule. */
+ struct mlx5_sub_policy_color_rules color_rules[RTE_COLORS];
+ /* List for the color rules. */
};
struct mlx5_meter_policy_acts {
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 6c4bfde098..3cd91a7e8c 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3449,6 +3449,41 @@ flow_drv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
return fops->meter_sub_policy_rss_prepare(dev, policy, rss_desc);
}
+/**
+ * Flow driver color tag rule API. This abstracts calling driver
+ * specific functions. Parent flow (rte_flow) should have driver
+ * type (drv_type). It will create the color tag rules in hierarchy meter.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in, out] flow
+ * Pointer to flow structure.
+ * @param[in] fm
+ * Pointer to flow meter structure.
+ * @param[in] src_port
+ * The src port this extra rule should use.
+ * @param[in] item
+ * The src port id match item.
+ * @param[out] error
+ * Pointer to error structure.
+ */
+static int
+flow_drv_mtr_hierarchy_rule_create(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ struct mlx5_flow_meter_info *fm,
+ int32_t src_port,
+ const struct rte_flow_item *item,
+ struct rte_flow_error *error)
+{
+ const struct mlx5_flow_driver_ops *fops;
+ enum mlx5_flow_drv_type type = flow->drv_type;
+
+ MLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
+ fops = flow_get_drv_ops(type);
+ return fops->meter_hierarchy_rule_create(dev, fm,
+ src_port, item, error);
+}
+
/**
* Get RSS action from the action list.
*
@@ -4773,6 +4808,15 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
pid_v,
"Failed to get port info.");
flow_src_port = port_priv->representor_id;
+ if (!fm->def_policy && wks->policy->is_hierarchy &&
+ flow_src_port != priv->representor_id) {
+ if (flow_drv_mtr_hierarchy_rule_create(dev,
+ flow, fm,
+ flow_src_port,
+ items,
+ error))
+ return -rte_errno;
+ }
memcpy(sfx_items, items, sizeof(*sfx_items));
sfx_items++;
break;
@@ -5713,6 +5757,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
bool has_mtr = false;
bool has_modify = false;
bool set_mtr_reg = true;
+ bool is_mtr_hierarchy = false;
uint32_t meter_id = 0;
uint32_t mtr_idx = 0;
uint32_t mtr_flow_id = 0;
@@ -5759,6 +5804,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION, NULL,
"Failed to find terminal policy of hierarchy.");
+ is_mtr_hierarchy = true;
}
}
/*
@@ -5766,9 +5812,11 @@ flow_create_split_meter(struct rte_eth_dev *dev,
* 1. There's no action in flow to change
* packet (modify/encap/decap etc.), OR
* 2. No drop count needed for this meter.
- * no need to use regC to save meter id anymore.
+ * 3. It's not meter hierarchy.
+ * Then no need to use regC to save meter id anymore.
*/
- if (!fm->def_policy && (!has_modify || !fm->drop_cnt))
+ if (!fm->def_policy && !is_mtr_hierarchy &&
+ (!has_modify || !fm->drop_cnt))
set_mtr_reg = false;
/* Prefix actions: meter, decap, encap, tag, jump, end. */
act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 09d6d609db..7d97c5880f 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1161,6 +1161,12 @@ typedef struct mlx5_flow_meter_sub_policy *
(struct rte_eth_dev *dev,
struct mlx5_flow_meter_policy *mtr_policy,
struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
+typedef int (*mlx5_flow_meter_hierarchy_rule_create_t)
+ (struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_info *fm,
+ int32_t src_port,
+ const struct rte_flow_item *item,
+ struct rte_flow_error *error);
typedef void (*mlx5_flow_destroy_sub_policy_with_rxq_t)
(struct rte_eth_dev *dev,
struct mlx5_flow_meter_policy *mtr_policy);
@@ -1257,6 +1263,7 @@ struct mlx5_flow_driver_ops {
mlx5_flow_create_def_policy_t create_def_policy;
mlx5_flow_destroy_def_policy_t destroy_def_policy;
mlx5_flow_meter_sub_policy_rss_prepare_t meter_sub_policy_rss_prepare;
+ mlx5_flow_meter_hierarchy_rule_create_t meter_hierarchy_rule_create;
mlx5_flow_destroy_sub_policy_with_rxq_t destroy_sub_policy_with_rxq;
mlx5_flow_counter_alloc_t counter_alloc;
mlx5_flow_counter_free_t counter_free;
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index d34f5214a8..119de09809 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -23,6 +23,7 @@
#include <rte_mpls.h>
#include <rte_mtr.h>
#include <rte_mtr_driver.h>
+#include <rte_tailq.h>
#include <mlx5_glue.h>
#include <mlx5_devx_cmds.h>
@@ -13090,6 +13091,15 @@ flow_dv_translate(struct rte_eth_dev *dev,
matcher.mask.size);
matcher.priority = mlx5_get_matcher_priority(dev, attr,
matcher.priority);
+ /**
+ * When creating meter drop flow in drop table, using original
+ * 5-tuple match, the matcher priority should be lower than
+ * mtr_id matcher.
+ */
+ if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
+ dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP &&
+ matcher.priority <= MLX5_REG_BITS)
+ matcher.priority += MLX5_REG_BITS;
/* reserved field no needs to be set to 0 here. */
tbl_key.is_fdb = attr->transfer;
tbl_key.is_egress = attr->egress;
@@ -14579,20 +14589,21 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_sub_policy *sub_policy)
{
struct mlx5_flow_tbl_data_entry *tbl;
+ struct mlx5_sub_policy_color_rule *color_rule;
+ void *tmp;
int i;
for (i = 0; i < RTE_COLORS; i++) {
- if (sub_policy->color_rule[i]) {
- claim_zero(mlx5_flow_os_destroy_flow
- (sub_policy->color_rule[i]));
- sub_policy->color_rule[i] = NULL;
- }
- if (sub_policy->color_matcher[i]) {
- tbl = container_of(sub_policy->color_matcher[i]->tbl,
- typeof(*tbl), tbl);
+ TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
+ next_port, tmp) {
+ claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
+ tbl = container_of(color_rule->matcher->tbl,
+ typeof(*tbl), tbl);
mlx5_cache_unregister(&tbl->matchers,
- &sub_policy->color_matcher[i]->entry);
- sub_policy->color_matcher[i] = NULL;
+ &color_rule->matcher->entry);
+ TAILQ_REMOVE(&sub_policy->color_rules[i],
+ color_rule, next_port);
+ mlx5_free(color_rule);
}
}
for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
@@ -14741,6 +14752,7 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
sizeof(struct mlx5_modification_cmd) *
(MLX5_MAX_MODIFY_NUM + 1)];
} mhdr_dummy;
+ struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
@@ -14748,6 +14760,11 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
memset(&dev_flow, 0, sizeof(struct mlx5_flow));
memset(&port_id_action, 0,
sizeof(struct mlx5_flow_dv_port_id_action_resource));
+ memset(mhdr_res, 0, sizeof(*mhdr_res));
+ mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
+ egress ?
+ MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+ MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
dev_flow.handle = &dh;
dev_flow.dv.port_id_action = &port_id_action;
dev_flow.external = true;
@@ -14786,10 +14803,6 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
break;
}
case RTE_FLOW_ACTION_TYPE_SET_TAG:
- {
- struct mlx5_flow_dv_modify_hdr_resource
- *mhdr_res = &mhdr_dummy.res;
-
if (i >= MLX5_MTR_RTE_COLORS)
return -rte_mtr_error_set(error,
ENOTSUP,
@@ -14797,12 +14810,6 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
NULL,
"cannot create policy "
"set tag action for this color");
- memset(mhdr_res, 0, sizeof(*mhdr_res));
- mhdr_res->ft_type = transfer ?
- MLX5DV_FLOW_TABLE_TYPE_FDB :
- egress ?
- MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
- MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
if (flow_dv_convert_action_set_tag
(dev, mhdr_res,
(const struct rte_flow_action_set_tag *)
@@ -14818,20 +14825,8 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
RTE_MTR_ERROR_TYPE_METER_POLICY,
NULL, "cannot find policy "
"set tag action");
- /* create modify action if needed. */
- dev_flow.dv.group = 1;
- if (flow_dv_modify_hdr_resource_register
- (dev, mhdr_res, &dev_flow, &flow_err))
- return -rte_mtr_error_set(error,
- ENOTSUP,
- RTE_MTR_ERROR_TYPE_METER_POLICY,
- NULL, "cannot register policy "
- "set tag action");
- act_cnt->modify_hdr =
- dev_flow.handle->dvh.modify_hdr;
action_flags |= MLX5_FLOW_ACTION_SET_TAG;
break;
- }
case RTE_FLOW_ACTION_TYPE_DROP:
{
struct mlx5_flow_mtr_mng *mtrmng =
@@ -15035,6 +15030,8 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
const struct rte_flow_action_meter *mtr;
struct mlx5_flow_meter_info *next_fm;
struct mlx5_flow_meter_policy *next_policy;
+ struct rte_flow_action tag_action;
+ struct mlx5_rte_flow_action_set_tag set_tag;
uint32_t next_mtr_idx = 0;
mtr = act->conf;
@@ -15052,6 +15049,30 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
next_policy = mlx5_flow_meter_policy_find(dev,
next_fm->policy_id, NULL);
MLX5_ASSERT(next_policy);
+ if (next_fm->drop_cnt) {
+ set_tag.id =
+ (enum modify_reg)
+ mlx5_flow_get_reg_id(dev,
+ MLX5_MTR_ID,
+ 0,
+ (struct rte_flow_error *)error);
+ set_tag.offset = (priv->mtr_reg_share ?
+ MLX5_MTR_COLOR_BITS : 0);
+ set_tag.length = (priv->mtr_reg_share ?
+ MLX5_MTR_IDLE_BITS_IN_COLOR_REG :
+ MLX5_REG_BITS);
+ set_tag.data = next_mtr_idx;
+ tag_action.type =
+ (enum rte_flow_action_type)
+ MLX5_RTE_FLOW_ACTION_TYPE_TAG;
+ tag_action.conf = &set_tag;
+ if (flow_dv_convert_action_set_reg
+ (mhdr_res, &tag_action,
+ (struct rte_flow_error *)error))
+ return -rte_errno;
+ action_flags |=
+ MLX5_FLOW_ACTION_SET_TAG;
+ }
act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
act_cnt->next_mtr_id = next_fm->meter_id;
act_cnt->next_sub_policy = NULL;
@@ -15066,6 +15087,19 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
RTE_MTR_ERROR_TYPE_METER_POLICY,
NULL, "action type not supported");
}
+ if (action_flags & MLX5_FLOW_ACTION_SET_TAG) {
+ /* create modify action if needed. */
+ dev_flow.dv.group = 1;
+ if (flow_dv_modify_hdr_resource_register
+ (dev, mhdr_res, &dev_flow, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot register policy "
+ "set tag action");
+ act_cnt->modify_hdr =
+ dev_flow.handle->dvh.modify_hdr;
+ }
}
}
return 0;
@@ -15418,8 +15452,8 @@ __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
uint32_t color_reg_c_idx,
enum rte_color color, void *matcher_object,
int actions_n, void *actions,
- bool match_src_port, void **rule,
- const struct rte_flow_attr *attr)
+ bool match_src_port, const struct rte_flow_item *item,
+ void **rule, const struct rte_flow_attr *attr)
{
int ret;
struct mlx5_flow_dv_match_params value = {
@@ -15434,7 +15468,7 @@ __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
if (match_src_port && (priv->representor || priv->master)) {
if (flow_dv_translate_item_port_id(dev, matcher.buf,
- value.buf, NULL, attr)) {
+ value.buf, item, attr)) {
DRV_LOG(ERR,
"Failed to create meter policy flow with port.");
return -1;
@@ -15460,6 +15494,8 @@ __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
struct mlx5_flow_meter_sub_policy *sub_policy,
const struct rte_flow_attr *attr,
bool match_src_port,
+ const struct rte_flow_item *item,
+ struct mlx5_flow_dv_matcher **policy_matcher,
struct rte_flow_error *error)
{
struct mlx5_cache_entry *entry;
@@ -15485,7 +15521,7 @@ __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
if (match_src_port && (priv->representor || priv->master)) {
if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
- value.buf, NULL, attr)) {
+ value.buf, item, attr)) {
DRV_LOG(ERR,
"Failed to register meter drop matcher with port.");
return -1;
@@ -15503,7 +15539,7 @@ __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
DRV_LOG(ERR, "Failed to register meter drop matcher.");
return -1;
}
- sub_policy->color_matcher[priority] =
+ *policy_matcher =
container_of(entry, struct mlx5_flow_dv_matcher, entry);
return 0;
}
@@ -15531,6 +15567,7 @@ __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
uint8_t egress, uint8_t transfer, bool match_src_port,
struct mlx5_meter_policy_acts acts[RTE_COLORS])
{
+ struct mlx5_priv *priv = dev->data->dev_private;
struct rte_flow_error flow_err;
uint32_t color_reg_c_idx;
struct rte_flow_attr attr = {
@@ -15543,6 +15580,7 @@ __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
};
int i;
int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
+ struct mlx5_sub_policy_color_rule *color_rule;
if (ret < 0)
return -1;
@@ -15560,29 +15598,56 @@ __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
/* Prepare matchers. */
color_reg_c_idx = ret;
for (i = 0; i < RTE_COLORS; i++) {
+ TAILQ_INIT(&sub_policy->color_rules[i]);
if (i == RTE_COLOR_YELLOW || !acts[i].actions_n)
continue;
+ color_rule = mlx5_malloc(MLX5_MEM_ZERO,
+ sizeof(struct mlx5_sub_policy_color_rule),
+ 0, SOCKET_ID_ANY);
+ if (!color_rule) {
+ DRV_LOG(ERR, "No memory to create color rule.");
+ goto err_exit;
+ }
+ color_rule->src_port = priv->representor_id;
attr.priority = i;
- if (!sub_policy->color_matcher[i]) {
- /* Create matchers for Color. */
- if (__flow_dv_create_policy_matcher(dev,
- color_reg_c_idx, i, sub_policy,
- &attr, match_src_port, &flow_err))
- return -1;
+ /* Create matchers for Color. */
+ if (__flow_dv_create_policy_matcher(dev,
+ color_reg_c_idx, i, sub_policy, &attr,
+ (i != RTE_COLOR_RED ? match_src_port : false),
+ NULL, &color_rule->matcher, &flow_err)) {
+ DRV_LOG(ERR, "Failed to create color matcher.");
+ goto err_exit;
}
/* Create flow, matching color. */
- if (acts[i].actions_n)
- if (__flow_dv_create_policy_flow(dev,
+ if (__flow_dv_create_policy_flow(dev,
color_reg_c_idx, (enum rte_color)i,
- sub_policy->color_matcher[i]->matcher_object,
+ color_rule->matcher->matcher_object,
acts[i].actions_n,
acts[i].dv_actions,
- match_src_port,
- &sub_policy->color_rule[i],
- &attr))
- return -1;
+ (i != RTE_COLOR_RED ? match_src_port : false),
+ NULL, &color_rule->rule,
+ &attr)) {
+ DRV_LOG(ERR, "Failed to create color rule.");
+ goto err_exit;
+ }
+ TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
+ color_rule, next_port);
}
return 0;
+err_exit:
+ if (color_rule) {
+ if (color_rule->rule)
+ mlx5_flow_os_destroy_flow(color_rule->rule);
+ if (color_rule->matcher) {
+ struct mlx5_flow_tbl_data_entry *tbl =
+ container_of(color_rule->matcher->tbl,
+ typeof(*tbl), tbl);
+ mlx5_cache_unregister(&tbl->matchers,
+ &color_rule->matcher->entry);
+ }
+ mlx5_free(color_rule);
+ }
+ return -1;
}
static int
@@ -15734,8 +15799,6 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
}
}
}
- egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
- transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
egress, transfer, match_src_port, acts)) {
DRV_LOG(ERR,
@@ -16291,6 +16354,156 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
return NULL;
}
+/**
+ * Create the sub policy tag rule for all meters in hierarchy.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] fm
+ * Meter information table.
+ * @param[in] src_port
+ * The src port this extra rule should use.
+ * @param[in] item
+ * The src port match item.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_info *fm,
+ int32_t src_port,
+ const struct rte_flow_item *item,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_policy *mtr_policy;
+ struct mlx5_flow_meter_sub_policy *sub_policy;
+ struct mlx5_flow_meter_info *next_fm = NULL;
+ struct mlx5_flow_meter_policy *next_policy;
+ struct mlx5_flow_meter_sub_policy *next_sub_policy;
+ struct mlx5_flow_tbl_data_entry *tbl_data;
+ struct mlx5_sub_policy_color_rule *color_rule;
+ struct mlx5_meter_policy_acts acts;
+ uint32_t color_reg_c_idx;
+ bool mtr_first = (src_port != 0xffff) ? true : false;
+ struct rte_flow_attr attr = {
+ .group = MLX5_FLOW_TABLE_LEVEL_POLICY,
+ .priority = 0,
+ .ingress = 0,
+ .egress = 0,
+ .transfer = 1,
+ .reserved = 0,
+ };
+ uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
+ int i;
+
+ mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
+ MLX5_ASSERT(mtr_policy);
+ if (!mtr_policy->is_hierarchy)
+ return 0;
+ next_fm = mlx5_flow_meter_find(priv,
+ mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
+ if (!next_fm) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to find next meter in hierarchy.");
+ }
+ if (!next_fm->drop_cnt)
+ goto exit;
+ color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
+ sub_policy = mtr_policy->sub_policys[domain][0];
+ for (i = 0; i < RTE_COLORS; i++) {
+ bool rule_exist = false;
+ struct mlx5_meter_policy_action_container *act_cnt;
+
+ if (i >= RTE_COLOR_YELLOW)
+ break;
+ TAILQ_FOREACH(color_rule,
+ &sub_policy->color_rules[i], next_port)
+ if (color_rule->src_port == src_port) {
+ rule_exist = true;
+ break;
+ }
+ if (rule_exist)
+ continue;
+ color_rule = mlx5_malloc(MLX5_MEM_ZERO,
+ sizeof(struct mlx5_sub_policy_color_rule),
+ 0, SOCKET_ID_ANY);
+ if (!color_rule)
+ return rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "No memory to create tag color rule.");
+ color_rule->src_port = src_port;
+ attr.priority = i;
+ next_policy = mlx5_flow_meter_policy_find(dev,
+ next_fm->policy_id, NULL);
+ MLX5_ASSERT(next_policy);
+ next_sub_policy = next_policy->sub_policys[domain][0];
+ tbl_data = container_of(next_sub_policy->tbl_rsc,
+ struct mlx5_flow_tbl_data_entry, tbl);
+ act_cnt = &mtr_policy->act_cnt[i];
+ if (mtr_first) {
+ acts.dv_actions[0] = next_fm->meter_action;
+ acts.dv_actions[1] = act_cnt->modify_hdr->action;
+ } else {
+ acts.dv_actions[0] = act_cnt->modify_hdr->action;
+ acts.dv_actions[1] = next_fm->meter_action;
+ }
+ acts.dv_actions[2] = tbl_data->jump.action;
+ acts.actions_n = 3;
+ if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) {
+ next_fm = NULL;
+ goto err_exit;
+ }
+ if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
+ i, sub_policy, &attr, true, item,
+ &color_rule->matcher, error)) {
+ rte_flow_error_set(error, errno,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Failed to create hierarchy meter matcher.");
+ goto err_exit;
+ }
+ if (__flow_dv_create_policy_flow(dev, color_reg_c_idx,
+ (enum rte_color)i,
+ color_rule->matcher->matcher_object,
+ acts.actions_n, acts.dv_actions,
+ true, item,
+ &color_rule->rule, &attr)) {
+ rte_flow_error_set(error, errno,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Failed to create hierarchy meter rule.");
+ goto err_exit;
+ }
+ TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
+ color_rule, next_port);
+ }
+exit:
+ /**
+ * Recursive call to iterate all meters in hierarchy and
+ * create needed rules.
+ */
+ return flow_dv_meter_hierarchy_rule_create(dev, next_fm,
+ src_port, item, error);
+err_exit:
+ if (color_rule) {
+ if (color_rule->rule)
+ mlx5_flow_os_destroy_flow(color_rule->rule);
+ if (color_rule->matcher) {
+ struct mlx5_flow_tbl_data_entry *tbl =
+ container_of(color_rule->matcher->tbl,
+ typeof(*tbl), tbl);
+ mlx5_cache_unregister(&tbl->matchers,
+ &color_rule->matcher->entry);
+ }
+ mlx5_free(color_rule);
+ }
+ if (next_fm)
+ mlx5_flow_meter_detach(priv, next_fm);
+ return -rte_errno;
+}
+
/**
* Destroy the sub policy table with RX queue.
*
@@ -16966,6 +17179,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
.create_def_policy = flow_dv_create_def_policy,
.destroy_def_policy = flow_dv_destroy_def_policy,
.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
+ .meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create,
.destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq,
.counter_alloc = flow_dv_counter_allocate,
.counter_free = flow_dv_counter_free,
--
2.21.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [dpdk-dev] [PATCH v1 3/4] net/mlx5: meter hierarchy destroy and cleanup
2021-07-06 13:14 [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Shun Hao
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 1/4] net/mlx5: support meter action in meter policy Shun Hao
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 2/4] net/mlx5: support meter hierarchy drop count Shun Hao
@ 2021-07-06 13:14 ` Shun Hao
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 4/4] net/mlx5: validate meter action in policy Shun Hao
2021-07-07 7:19 ` [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Raslan Darawsheh
4 siblings, 0 replies; 6+ messages in thread
From: Shun Hao @ 2021-07-06 13:14 UTC (permalink / raw)
To: orika, viacheslavo, matan, Shahaf Shuler; +Cc: dev, thomas, rasland
When creating hierarchy meter, its color rules will increase next
meter's reference count, so when destroy the hierarchy meter, also
need to dereference the next meter's count.
During flushing all meters of a port, need to destroy all hierarchy
meters and their policies first, to dereference the last meter in
hierarchy. Then all meters have no reference and can be destroyed.
Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
drivers/net/mlx5/mlx5_flow_dv.c | 15 +++-
drivers/net/mlx5/mlx5_flow_meter.c | 132 +++++++++++++++++++++++++++++
2 files changed, 145 insertions(+), 2 deletions(-)
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 119de09809..681e6fb07c 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14588,12 +14588,20 @@ static void
__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_sub_policy *sub_policy)
{
+ struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_tbl_data_entry *tbl;
+ struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
+ struct mlx5_flow_meter_info *next_fm;
struct mlx5_sub_policy_color_rule *color_rule;
void *tmp;
- int i;
+ uint32_t i;
for (i = 0; i < RTE_COLORS; i++) {
+ next_fm = NULL;
+ if (i == RTE_COLOR_GREEN && policy &&
+ policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
+ next_fm = mlx5_flow_meter_find(priv,
+ policy->act_cnt[i].next_mtr_id, NULL);
TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
next_port, tmp) {
claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
@@ -14604,11 +14612,14 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
TAILQ_REMOVE(&sub_policy->color_rules[i],
color_rule, next_port);
mlx5_free(color_rule);
+ if (next_fm)
+ mlx5_flow_meter_detach(priv, next_fm);
}
}
for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
if (sub_policy->rix_hrxq[i]) {
- mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+ if (policy && !policy->is_hierarchy)
+ mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
sub_policy->rix_hrxq[i] = 0;
}
if (sub_policy->jump_tbl[i]) {
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 03f7e120e1..78eb2a60f9 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -1891,6 +1891,136 @@ mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev)
}
}
+/**
+ * Iterate a meter hierarchy and flush all meters and policies if possible.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] fm
+ * Pointer to flow meter.
+ * @param[in] mtr_idx
+ * .Meter's index
+ * @param[out] error
+ * Pointer to rte meter error structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_info *fm,
+ uint32_t mtr_idx,
+ struct rte_mtr_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_policy *policy;
+ uint32_t policy_id;
+ struct mlx5_flow_meter_info *next_fm;
+ uint32_t next_mtr_idx;
+ struct mlx5_flow_meter_policy *next_policy = NULL;
+
+ policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
+ MLX5_ASSERT(policy);
+ while (!fm->ref_cnt && policy->is_hierarchy) {
+ policy_id = fm->policy_id;
+ next_fm = mlx5_flow_meter_find(priv,
+ policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
+ &next_mtr_idx);
+ if (next_fm) {
+ next_policy = mlx5_flow_meter_policy_find(dev,
+ next_fm->policy_id,
+ NULL);
+ MLX5_ASSERT(next_policy);
+ }
+ if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
+ return -rte_mtr_error_set(error, ENOTSUP,
+ RTE_MTR_ERROR_TYPE_MTR_ID,
+ NULL,
+ "Failed to flush meter.");
+ if (policy->ref_cnt)
+ break;
+ if (__mlx5_flow_meter_policy_delete(dev, policy_id,
+ policy, error, true))
+ return -rte_errno;
+ mlx5_free(policy);
+ if (!next_fm || !next_policy)
+ break;
+ fm = next_fm;
+ mtr_idx = next_mtr_idx;
+ policy = next_policy;
+ }
+ return 0;
+}
+
+/**
+ * Flush all the hierarchy meters and their policies.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[out] error
+ * Pointer to rte meter error structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev,
+ struct rte_mtr_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_info *fm;
+ struct mlx5_flow_meter_policy *policy;
+ struct mlx5_flow_meter_sub_policy *sub_policy;
+ struct mlx5_flow_meter_info *next_fm;
+ struct mlx5_aso_mtr *aso_mtr;
+ uint32_t mtr_idx = 0;
+ uint32_t i, policy_idx;
+ void *entry;
+
+ if (!priv->mtr_idx_tbl || !priv->policy_idx_tbl)
+ return 0;
+ MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
+ mtr_idx = *(uint32_t *)entry;
+ if (!mtr_idx)
+ continue;
+ aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+ fm = &aso_mtr->fm;
+ if (fm->ref_cnt || fm->def_policy)
+ continue;
+ if (mlx5_flow_meter_flush_hierarchy(dev, fm, mtr_idx, error))
+ return -rte_errno;
+ }
+ MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
+ policy_idx = *(uint32_t *)entry;
+ sub_policy = mlx5_ipool_get
+ (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+ policy_idx);
+ if (!sub_policy)
+ return -rte_mtr_error_set(error,
+ EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+ NULL, "Meter policy invalid.");
+ policy = sub_policy->main_policy;
+ if (!policy || !policy->is_hierarchy || policy->ref_cnt)
+ continue;
+ next_fm = mlx5_flow_meter_find(priv,
+ policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
+ &mtr_idx);
+ if (__mlx5_flow_meter_policy_delete(dev, i, policy,
+ error, true))
+ return -rte_mtr_error_set(error,
+ EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+ NULL, "Meter policy invalid.");
+ mlx5_free(policy);
+ if (!next_fm || next_fm->ref_cnt || next_fm->def_policy)
+ continue;
+ if (mlx5_flow_meter_flush_hierarchy(dev, next_fm,
+ mtr_idx, error))
+ return -rte_errno;
+ }
+ return 0;
+}
/**
* Flush meter configuration.
*
@@ -1919,6 +2049,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
if (!priv->mtr_en)
return 0;
if (priv->sh->meter_aso_en) {
+ if (mlx5_flow_meter_flush_all_hierarchies(dev, error))
+ return -rte_errno;
if (priv->mtr_idx_tbl) {
MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
mtr_idx = *(uint32_t *)entry;
--
2.21.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [dpdk-dev] [PATCH v1 4/4] net/mlx5: validate meter action in policy
2021-07-06 13:14 [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Shun Hao
` (2 preceding siblings ...)
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 3/4] net/mlx5: meter hierarchy destroy and cleanup Shun Hao
@ 2021-07-06 13:14 ` Shun Hao
2021-07-07 7:19 ` [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Raslan Darawsheh
4 siblings, 0 replies; 6+ messages in thread
From: Shun Hao @ 2021-07-06 13:14 UTC (permalink / raw)
To: orika, viacheslavo, matan, Shahaf Shuler; +Cc: dev, thomas, rasland
This adds the validation when creating a policy with meter action.
Currently meter action is only allowed for green color in policy, and
8 meters are supported at maximum in one meter hierarchy.
Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
doc/guides/nics/mlx5.rst | 15 ++++
doc/guides/rel_notes/release_21_08.rst | 6 ++
drivers/net/mlx5/mlx5_flow_dv.c | 98 ++++++++++++++++++++++++++
3 files changed, 119 insertions(+)
diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index a16af32e67..de04931f80 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -107,6 +107,7 @@ Features
- 21844 flow priorities for ingress or egress flow groups greater than 0 and for any transfer
flow group.
- Flow metering, including meter policy API.
+- Flow meter hierarchy.
- Flow integrity offload API.
- Connection tracking.
- Sub-Function representors.
@@ -1927,3 +1928,17 @@ This section demonstrates how to use the shared meter. A meter M can be created
on port X and to be shared with a port Y on the same switch domain by the next way:
flow create X ingress transfer pattern eth / port_id id is Y / end actions meter mtr_id M / end
+
+How to use meter hierarchy
+--------------------------
+
+This section demonstrates how to create and use a meter hierarchy.
+A termination meter M can be the policy green action of another termination meter N.
+The two meters are chained together as a chain. Using meter N in a flow will apply
+both the meters in hierarchy on that flow.
+
+ add port meter policy 0 1 g_actions queue index 0 / end y_actions end r_actions drop / end
+ create port meter 0 M 1 1 yes 0xffff 1 0
+ add port meter policy 0 2 g_actions meter mtr_id M / end y_actions end r_actions drop / end
+ create port meter 0 N 2 2 yes 0xffff 1 0
+ flow create 0 ingress group 1 pattern eth / end actions meter mtr_id N / end
diff --git a/doc/guides/rel_notes/release_21_08.rst b/doc/guides/rel_notes/release_21_08.rst
index 0a05cb02fa..b29d78f4de 100644
--- a/doc/guides/rel_notes/release_21_08.rst
+++ b/doc/guides/rel_notes/release_21_08.rst
@@ -68,6 +68,12 @@ New Features
usecases. Configuration happens via standard rawdev enq/deq operations. See
the :doc:`../rawdevs/cnxk_bphy` rawdev guide for more details on this driver.
+* **Updated Mellanox mlx5 driver.**
+
+ Updated the Mellanox mlx5 driver with new features and improvements, including:
+
+ * Added support for Meter hierarchy.
+
Removed Items
-------------
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 681e6fb07c..c085deed50 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -16858,6 +16858,78 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
}
}
+/**
+ * Validate the meter hierarchy chain for meter policy.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] meter_id
+ * Meter id.
+ * @param[in] action_flags
+ * Holds the actions detected until now.
+ * @param[out] is_rss
+ * Is RSS or not.
+ * @param[out] hierarchy_domain
+ * The domain bitmap for hierarchy policy.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL. Initialized in case of
+ * error only.
+ *
+ * @return
+ * 0 on success, otherwise negative errno value with error set.
+ */
+static int
+flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev,
+ uint32_t meter_id,
+ uint64_t action_flags,
+ bool *is_rss,
+ uint8_t *hierarchy_domain,
+ struct rte_mtr_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_meter_info *fm;
+ struct mlx5_flow_meter_policy *policy;
+ uint8_t cnt = 1;
+
+ if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
+ MLX5_FLOW_FATE_ESWITCH_ACTIONS))
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
+ NULL,
+ "Multiple fate actions not supported.");
+ while (true) {
+ fm = mlx5_flow_meter_find(priv, meter_id, NULL);
+ if (!fm)
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+ "Meter not found in meter hierarchy.");
+ if (fm->def_policy)
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+ "Non termination meter not supported in hierarchy.");
+ policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
+ MLX5_ASSERT(policy);
+ if (!policy->is_hierarchy) {
+ if (policy->transfer)
+ *hierarchy_domain |=
+ MLX5_MTR_DOMAIN_TRANSFER_BIT;
+ if (policy->ingress)
+ *hierarchy_domain |=
+ MLX5_MTR_DOMAIN_INGRESS_BIT;
+ if (policy->egress)
+ *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT;
+ *is_rss = policy->is_rss;
+ break;
+ }
+ meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id;
+ if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM)
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+ "Exceed max hierarchy meter number.");
+ }
+ return 0;
+}
+
/**
* Validate meter policy actions.
* Dispatcher for action type specific validation.
@@ -16893,6 +16965,8 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
struct rte_flow_error flow_err;
uint8_t domain_color[RTE_COLORS] = {0};
uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
+ uint8_t hierarchy_domain = 0;
+ const struct rte_flow_action_meter *mtr;
if (!priv->config.dv_esw_en)
def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
@@ -17070,6 +17144,27 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
++actions_n;
action_flags |= MLX5_FLOW_ACTION_JUMP;
break;
+ case RTE_FLOW_ACTION_TYPE_METER:
+ if (i != RTE_COLOR_GREEN)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, flow_err.message ?
+ flow_err.message :
+ "Meter hierarchy only supports GREEN color.");
+ mtr = act->conf;
+ ret = flow_dv_validate_policy_mtr_hierarchy(dev,
+ mtr->mtr_id,
+ action_flags,
+ is_rss,
+ &hierarchy_domain,
+ error);
+ if (ret)
+ return ret;
+ ++actions_n;
+ action_flags |=
+ MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
+ break;
default:
return -rte_mtr_error_set(error, ENOTSUP,
RTE_MTR_ERROR_TYPE_METER_POLICY,
@@ -17090,6 +17185,9 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
* so MARK action only in ingress domain.
*/
domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
+ else if (action_flags &
+ MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
+ domain_color[i] = hierarchy_domain;
else
domain_color[i] = def_domain;
/*
--
2.21.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy
2021-07-06 13:14 [dpdk-dev] [PATCH v1 0/4] Add support for meter hierarchy Shun Hao
` (3 preceding siblings ...)
2021-07-06 13:14 ` [dpdk-dev] [PATCH v1 4/4] net/mlx5: validate meter action in policy Shun Hao
@ 2021-07-07 7:19 ` Raslan Darawsheh
4 siblings, 0 replies; 6+ messages in thread
From: Raslan Darawsheh @ 2021-07-07 7:19 UTC (permalink / raw)
To: Shun Hao, Ori Kam, Slava Ovsiienko, Matan Azrad
Cc: dev, NBU-Contact-Thomas Monjalon
Hi,
> -----Original Message-----
> From: Shun Hao <shunh@nvidia.com>
> Sent: Tuesday, July 6, 2021 4:15 PM
> To: Ori Kam <orika@nvidia.com>; Slava Ovsiienko
> <viacheslavo@nvidia.com>; Matan Azrad <matan@nvidia.com>
> Cc: dev@dpdk.org; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; Raslan Darawsheh <rasland@nvidia.com>
> Subject: [PATCH v1 0/4] Add support for meter hierarchy
>
> This adds support for meter hierarchy, which means multiple meters can
> be chained together, and using the header meter of hierarchy in a flow
> will apply all meters in hierarchy to that flow.
>
> Shun Hao (4):
> net/mlx5: support meter action in meter policy
> net/mlx5: support meter hierarchy drop count
> net/mlx5: meter hierarchy destroy and cleanup
> net/mlx5: validate meter action in policy
>
> doc/guides/nics/mlx5.rst | 15 +
> doc/guides/rel_notes/release_21_08.rst | 6 +
> drivers/net/mlx5/mlx5.h | 32 +-
> drivers/net/mlx5/mlx5_flow.c | 123 +++--
> drivers/net/mlx5/mlx5_flow.h | 12 +
> drivers/net/mlx5/mlx5_flow_dv.c | 701 +++++++++++++++++++++----
> drivers/net/mlx5/mlx5_flow_meter.c | 175 +++++-
> 7 files changed, 935 insertions(+), 129 deletions(-)
>
> --
> 2.21.0
Series applied to next-net-mlx,
Kindest regards,
Raslan Darawsheh
^ permalink raw reply [flat|nested] 6+ messages in thread