@@ -686,10 +686,14 @@ mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
aso_mtr = &mtr_pool->mtrs[i];
- if (aso_mtr->fm.meter_action)
+ if (aso_mtr->fm.meter_action_g)
claim_zero
(mlx5_glue->destroy_flow_action
- (aso_mtr->fm.meter_action));
+ (aso_mtr->fm.meter_action_g));
+ if (aso_mtr->fm.meter_action_y)
+ claim_zero
+ (mlx5_glue->destroy_flow_action
+ (aso_mtr->fm.meter_action_y));
}
#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
claim_zero(mlx5_devx_cmd_destroy
@@ -869,8 +869,10 @@ struct mlx5_flow_meter_info {
/**< Use count. */
struct mlx5_indexed_pool *flow_ipool;
/**< Index pool for flow id. */
- void *meter_action;
+ void *meter_action_g;
/**< Flow meter action. */
+ void *meter_action_y;
+ /**< Flow meter action for yellow init_color. */
};
/* PPS(packets per second) map to BPS(Bytes per second).
@@ -1873,6 +1875,10 @@ 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_info *
+mlx5_flow_meter_hierarchy_next_meter(struct mlx5_priv *priv,
+ struct mlx5_flow_meter_policy *policy,
+ uint32_t *mtr_idx);
struct mlx5_flow_meter_policy *
mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
struct mlx5_flow_meter_policy *policy);
@@ -6534,13 +6534,13 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
struct mlx5_aso_mtr_pool,
mtrs[mtr_free->offset]);
mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
- if (!mtr_free->fm.meter_action) {
+ if (!mtr_free->fm.meter_action_g) {
#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
struct rte_flow_error error;
uint8_t reg_id;
reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
- mtr_free->fm.meter_action =
+ mtr_free->fm.meter_action_g =
mlx5_glue->dv_create_flow_action_aso
(priv->sh->rx_domain,
pool->devx_obj->obj,
@@ -6548,7 +6548,7 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
(1 << MLX5_FLOW_COLOR_GREEN),
reg_id - REG_C_0);
#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
- if (!mtr_free->fm.meter_action) {
+ if (!mtr_free->fm.meter_action_g) {
flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
return 0;
}
@@ -13401,7 +13401,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
NULL, "Failed to get meter in flow.");
/* Set the meter action. */
dev_flow->dv.actions[actions_n++] =
- wks->fm->meter_action;
+ wks->fm->meter_action_g;
action_flags |= MLX5_FLOW_ACTION_METER;
break;
case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
@@ -15427,7 +15427,7 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
for (i = 0; i < RTE_COLORS; i++) {
next_fm = NULL;
- if (i == RTE_COLOR_GREEN && policy &&
+ if (i <= RTE_COLOR_YELLOW && 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);
@@ -15551,6 +15551,51 @@ flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
mtr_policy->dr_drop_action[j] = NULL;
}
+/**
+ * Create yellow action for color aware meter.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] fm
+ * Meter information table.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL. Initialized in case of
+ * error only.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+__flow_dv_create_mtr_yellow_action(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_info *fm,
+ struct rte_mtr_error *error)
+{
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct rte_flow_error flow_err;
+ struct mlx5_aso_mtr *aso_mtr;
+ struct mlx5_aso_mtr_pool *pool;
+ uint8_t reg_id;
+
+ aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+ pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, mtrs[aso_mtr->offset]);
+ reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
+ fm->meter_action_y =
+ mlx5_glue->dv_create_flow_action_aso(priv->sh->rx_domain,
+ pool->devx_obj->obj,
+ aso_mtr->offset,
+ (1 << MLX5_FLOW_COLOR_YELLOW),
+ reg_id - REG_C_0);
+#else
+ RTE_SET_USED(dev);
+#endif
+ if (!fm->meter_action_y) {
+ return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+ "Fail to create yellow meter action.");
+ }
+ return 0;
+}
+
/**
* Create policy action per domain, lock free,
* (mutex should be acquired by caller).
@@ -15870,7 +15915,7 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
break;
}
/*
- * No need to check meter hierarchy for Y or R colors
+ * No need to check meter hierarchy for R colors
* here since it is done in the validation stage.
*/
case RTE_FLOW_ACTION_TYPE_METER:
@@ -15921,6 +15966,10 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
action_flags |=
MLX5_FLOW_ACTION_SET_TAG;
}
+ if (i == RTE_COLOR_YELLOW && next_fm->color_aware &&
+ !next_fm->meter_action_y)
+ if (__flow_dv_create_mtr_yellow_action(dev, next_fm, error))
+ return -rte_errno;
act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
act_cnt->next_mtr_id = next_fm->meter_id;
act_cnt->next_sub_policy = NULL;
@@ -16519,7 +16568,7 @@ __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;
- struct mlx5_flow_meter_info *next_fm = NULL;
+ struct mlx5_flow_meter_info *next_fm[RTE_COLORS] = {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;
@@ -16540,30 +16589,31 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
acts[i].actions_n = 1;
continue;
}
- if (i == RTE_COLOR_GREEN &&
- mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
+ 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,
+ next_fm[i] = mlx5_flow_meter_find(priv,
mtr_policy->act_cnt[i].next_mtr_id,
NULL);
- if (!next_fm) {
+ if (!next_fm[i]) {
DRV_LOG(ERR,
"Failed to get next hierarchy meter.");
goto err_exit;
}
- if (mlx5_flow_meter_attach(priv, next_fm,
+ if (mlx5_flow_meter_attach(priv, next_fm[i],
&attr, &error)) {
DRV_LOG(ERR, "%s", error.message);
- next_fm = NULL;
+ next_fm[i] = 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;
+ (next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ?
+ next_fm[i]->meter_action_y :
+ next_fm[i]->meter_action_g;
acts[i].actions_n++;
}
}
@@ -16621,14 +16671,16 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
acts[i].actions_n++;
break;
case MLX5_FLOW_FATE_MTR:
- if (!next_fm) {
+ if (!next_fm[i]) {
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;
+ (next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ?
+ next_fm[i]->meter_action_y :
+ next_fm[i]->meter_action_g;
acts[i].actions_n++;
}
if (mtr_policy->act_cnt[i].next_sub_policy) {
@@ -16637,7 +16689,7 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
} else {
next_policy =
mlx5_flow_meter_policy_find(dev,
- next_fm->policy_id, NULL);
+ next_fm[i]->policy_id, NULL);
MLX5_ASSERT(next_policy);
next_sub_policy =
next_policy->sub_policys[domain][0];
@@ -16664,8 +16716,9 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
}
return 0;
err_exit:
- if (next_fm)
- mlx5_flow_meter_detach(priv, next_fm);
+ for (i = 0; i < RTE_COLORS; i++)
+ if (next_fm[i])
+ mlx5_flow_meter_detach(priv, next_fm[i]);
return -1;
}
@@ -17181,8 +17234,9 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
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);
+ rte_spinlock_lock(&mtr_policy->sl);
+ next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, mtr_policy, NULL);
+ rte_spinlock_unlock(&mtr_policy->sl);
if (!next_fm) {
DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
return NULL;
@@ -17330,11 +17384,11 @@ flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
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[0] = next_fm->meter_action_g;
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[1] = next_fm->meter_action_g;
}
acts.dv_actions[2] = tbl_data->jump.action;
acts.actions_n = 3;
@@ -611,6 +611,36 @@ mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
return NULL;
}
+/**
+ * Get the next meter from one meter's policy in hierarchy chain.
+ * Lock free, mutex should be acquired by caller.
+ *
+ * @param[in] priv
+ * Pointer to mlx5_priv.
+ * @param[in] policy
+ * Pointer to flow meter policy.
+ * @param[out] mtr_idx
+ * Pointer to Meter index.
+ *
+ * @return
+ * Pointer to the next meter, or NULL when fail.
+ */
+struct mlx5_flow_meter_info *
+mlx5_flow_meter_hierarchy_next_meter(struct mlx5_priv *priv,
+ struct mlx5_flow_meter_policy *policy,
+ uint32_t *mtr_idx)
+{
+ int i;
+
+ for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+ if (policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
+ return mlx5_flow_meter_find(priv,
+ policy->act_cnt[i].next_mtr_id,
+ mtr_idx);
+ }
+ return NULL;
+}
+
/**
* Get the last meter's policy from one meter's policy in hierarchy.
*
@@ -631,8 +661,9 @@ mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
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);
+ rte_spinlock_lock(&next_policy->sl);
+ next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, next_policy, NULL);
+ rte_spinlock_unlock(&next_policy->sl);
if (!next_fm || next_fm->def_policy)
return NULL;
next_policy = mlx5_flow_meter_policy_find(dev,
@@ -1105,9 +1136,9 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
ebs_mantissa, val);
}
/* Apply modifications to meter only if it was created. */
- if (fm->meter_action) {
+ if (fm->meter_action_g) {
ret = mlx5_glue->dv_modify_flow_action_meter
- (fm->meter_action, &mod_attr,
+ (fm->meter_action_g, &mod_attr,
rte_cpu_to_be_64(modify_bits));
if (ret)
return ret;
@@ -1908,7 +1939,7 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv,
rte_spinlock_unlock(&fm->sl);
} else {
rte_spinlock_lock(&fm->sl);
- if (fm->meter_action) {
+ if (fm->meter_action_g) {
if (fm->shared &&
attr->transfer == fm->transfer &&
attr->ingress == fm->ingress &&
@@ -1928,9 +1959,9 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv,
fm->transfer = attr->transfer;
fm->ref_cnt = 1;
/* This also creates the meter object. */
- fm->meter_action = mlx5_flow_meter_action_create(priv,
+ fm->meter_action_g = mlx5_flow_meter_action_create(priv,
fm);
- if (!fm->meter_action) {
+ if (!fm->meter_action_g) {
fm->ref_cnt = 0;
fm->ingress = 0;
fm->egress = 0;
@@ -1962,8 +1993,8 @@ mlx5_flow_meter_detach(struct mlx5_priv *priv,
rte_spinlock_lock(&fm->sl);
MLX5_ASSERT(fm->ref_cnt);
if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
- mlx5_glue->destroy_flow_action(fm->meter_action);
- fm->meter_action = NULL;
+ mlx5_glue->destroy_flow_action(fm->meter_action_g);
+ fm->meter_action_g = NULL;
fm->ingress = 0;
fm->egress = 0;
fm->transfer = 0;
@@ -2040,9 +2071,7 @@ mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev,
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);
+ next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &next_mtr_idx);
if (next_fm) {
next_policy = mlx5_flow_meter_policy_find(dev,
next_fm->policy_id,
@@ -2120,9 +2149,7 @@ mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev,
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);
+ next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &mtr_idx);
if (__mlx5_flow_meter_policy_delete(dev, i, policy,
error, true))
return -rte_mtr_error_set(error,