From: Li Zhang Date: Tue, 20 Apr 2021 10:55:19 +0000 (+0300) Subject: net/mlx5: support ASO meter action X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=c99b4f8bc2f1;p=dpdk.git net/mlx5: support ASO meter action When ASO action is available, use it as the meter action Signed-off-by: Shun Hao Signed-off-by: Li Zhang Acked-by: Matan Azrad --- diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst index b949e580e1..b136f1fb27 100644 --- a/doc/guides/rel_notes/release_21_05.rst +++ b/doc/guides/rel_notes/release_21_05.rst @@ -156,6 +156,7 @@ New Features * Added support for VXLAN and NVGRE encap as sample actions. * Support push VLAN on ingress traffic and pop VLAN on egress traffic in E-Switch mode. + * Added support for ASO (Advanced Steering Operation) meter. * **Updated NXP DPAA driver.** diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index 336cdbe3a8..41622c1bf7 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1255,7 +1255,9 @@ err_secondary: "required for coalescing is %d bytes", config->hca_attr.lro_min_mss_size); } -#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER) +#if defined(HAVE_MLX5DV_DR) && \ + (defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER) || \ + defined(HAVE_MLX5_DR_CREATE_ACTION_ASO)) if (config->hca_attr.qos.sup && config->hca_attr.qos.flow_meter_old && config->dv_flow_en) { diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 00055e33d6..e5ffb8f017 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -609,11 +609,23 @@ mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh) struct mlx5_aso_mtr_pool *mtr_pool; struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng; uint32_t idx; +#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO + struct mlx5_aso_mtr *aso_mtr; + int i; +#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER); idx = mtrmng->n_valid; while (idx--) { mtr_pool = mtrmng->pools[idx]; +#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) + claim_zero(mlx5_glue->destroy_flow_action + (aso_mtr->fm.meter_action)); + } +#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ claim_zero(mlx5_devx_cmd_destroy (mtr_pool->devx_obj)); mtrmng->n_valid--; diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index adf24f087b..a045cf4415 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -634,8 +634,6 @@ struct mlx5_meter_domains_infos { /**< Counters for green rule. */ void *drop_count; /**< Counters for green rule. */ - void *meter_action; - /**< Flow meter action. */ }; /* Meter parameter structure. */ @@ -698,6 +696,8 @@ struct mlx5_flow_meter_info { /**< Use count. */ struct mlx5_indexed_pool *flow_ipool; /**< Index pool for flow id. */ + void *meter_action; + /**< Flow meter action. */ }; /* RFC2697 parameter structure. */ @@ -1487,7 +1487,8 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv, struct mlx5_flow_meter_info *fm, const struct rte_flow_attr *attr, struct rte_flow_error *error); -void mlx5_flow_meter_detach(struct mlx5_flow_meter_info *fm); +void mlx5_flow_meter_detach(struct mlx5_priv *priv, + struct mlx5_flow_meter_info *fm); /* mlx5_os.c */ struct rte_pci_driver; diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 7a6d6f8675..cf93ab079c 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -4363,6 +4363,8 @@ flow_create_split_inner(struct rte_eth_dev *dev, * Parent flow structure pointer. * @param[in] fm * Pointer to flow meter structure. + * @param[in] attr + * Flow rule attributes. * @param[in] items * Pattern specification (list terminated by the END pattern item). * @param[out] sfx_items @@ -4383,6 +4385,7 @@ static uint32_t flow_meter_split_prep(struct rte_eth_dev *dev, struct rte_flow *flow, struct mlx5_flow_meter_info *fm, + const struct rte_flow_attr *attr, const struct rte_flow_item items[], struct rte_flow_item sfx_items[], const struct rte_flow_action actions[], @@ -4400,6 +4403,12 @@ flow_meter_split_prep(struct rte_eth_dev *dev, struct mlx5_rte_flow_item_tag *tag_item_mask; uint32_t tag_id = 0; bool copy_vlan = false; + struct rte_flow_action *hw_mtr_action; + struct rte_flow_action_jump *jump_data; + struct rte_flow_action *action_pre_head = NULL; + bool mtr_first = priv->sh->meter_aso_en && + (attr->egress || + (attr->transfer && priv->representor_id != UINT16_MAX)); uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0; uint8_t mtr_reg_bits = priv->mtr_reg_share ? MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS; @@ -4408,29 +4417,39 @@ flow_meter_split_prep(struct rte_eth_dev *dev, uint8_t flow_id_bits = 0; int shift; + /* For ASO meter, meter must be before tag in TX direction. */ + if (mtr_first) { + action_pre_head = actions_pre++; + /* Leave space for tag action. */ + tag_action = actions_pre++; + } /* Prepare the actions for prefix and suffix flow. */ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { - struct rte_flow_action **action_cur = NULL; + struct rte_flow_action *action_cur = NULL; switch (actions->type) { case RTE_FLOW_ACTION_TYPE_METER: - /* Add the extra tag action first. */ - tag_action = actions_pre++; - action_cur = &actions_pre; + if (mtr_first) { + action_cur = action_pre_head; + } else { + /* Leave space for tag action. */ + tag_action = actions_pre++; + action_cur = actions_pre++; + } break; case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: - action_cur = &actions_pre; + action_cur = actions_pre++; break; case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: raw_encap = actions->conf; if (raw_encap->size < MLX5_ENCAPSULATION_DECISION_SIZE) - action_cur = &actions_pre; + action_cur = actions_pre++; break; case RTE_FLOW_ACTION_TYPE_RAW_DECAP: raw_decap = actions->conf; if (raw_decap->size > MLX5_ENCAPSULATION_DECISION_SIZE) - action_cur = &actions_pre; + action_cur = actions_pre++; break; case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: @@ -4440,14 +4459,32 @@ flow_meter_split_prep(struct rte_eth_dev *dev, break; } if (!action_cur) - action_cur = &actions_sfx; - memcpy(*action_cur, actions, sizeof(struct rte_flow_action)); - (*action_cur)++; + action_cur = actions_sfx++; + memcpy(action_cur, actions, sizeof(struct rte_flow_action)); } /* Add end action to the actions. */ actions_sfx->type = RTE_FLOW_ACTION_TYPE_END; - actions_pre->type = RTE_FLOW_ACTION_TYPE_END; - actions_pre++; + if (priv->sh->meter_aso_en) { + /** + * For ASO meter, need to add an extra jump action explicitly, + * to jump from meter to policer table. + */ + hw_mtr_action = actions_pre; + hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP; + actions_pre++; + actions_pre->type = RTE_FLOW_ACTION_TYPE_END; + actions_pre++; + jump_data = (struct rte_flow_action_jump *)actions_pre; + jump_data->group = attr->transfer ? + (MLX5_FLOW_TABLE_LEVEL_METER - 1) : + MLX5_FLOW_TABLE_LEVEL_METER; + hw_mtr_action->conf = jump_data; + actions_pre = (struct rte_flow_action *)(jump_data + 1); + } else { + actions_pre->type = RTE_FLOW_ACTION_TYPE_END; + actions_pre++; + } + /* Generate meter flow_id only if support multiple flows per meter. */ mlx5_ipool_malloc(fm->flow_ipool, &tag_id); if (!tag_id) return rte_flow_error_set(error, ENOMEM, @@ -5272,10 +5309,11 @@ flow_create_split_meter(struct rte_eth_dev *dev, flow->meter = mtr_idx; } wks->fm = fm; - /* The prefix actions: meter, decap, encap, tag, end. */ - act_size = sizeof(struct rte_flow_action) * (actions_n + 5) + - sizeof(struct mlx5_rte_flow_action_set_tag); - /* The suffix items: tag, vlan, port id, end. */ + /* Prefix actions: meter, decap, encap, tag, jump, end. */ + act_size = sizeof(struct rte_flow_action) * (actions_n + 6) + + sizeof(struct mlx5_rte_flow_action_set_tag) + + sizeof(struct rte_flow_action_jump); + /* Suffix items: tag, vlan, port id, end. */ #define METER_SUFFIX_ITEM 4 item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM + sizeof(struct mlx5_rte_flow_item_tag) * 2; @@ -5289,8 +5327,8 @@ flow_create_split_meter(struct rte_eth_dev *dev, sfx_items = (struct rte_flow_item *)((char *)sfx_actions + act_size); pre_actions = sfx_actions + actions_n; - mtr_tag_id = flow_meter_split_prep(dev, flow, fm, items, - sfx_items, actions, + mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr, + items, sfx_items, actions, sfx_actions, pre_actions, error); if (!mtr_tag_id) { diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index a621417a33..a64933931d 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -4891,9 +4891,11 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev, return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Meter not found"); - if (fm->ref_cnt && (!(fm->transfer == attr->transfer || + /* aso meter can always be shared by different domains */ + if (fm->ref_cnt && !priv->sh->meter_aso_en && + !(fm->transfer == attr->transfer || (!fm->ingress && !attr->ingress && attr->egress) || - (!fm->egress && !attr->egress && attr->ingress)))) + (!fm->egress && !attr->egress && attr->ingress))) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Flow attributes are either invalid " @@ -6096,6 +6098,25 @@ 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) { +#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 = + mlx5_glue->dv_create_flow_action_aso + (priv->sh->rx_domain, + pool->devx_obj->obj, + mtr_free->offset, + (1 << MLX5_FLOW_COLOR_GREEN), + reg_id - REG_C_0); +#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ + if (!mtr_free->fm.meter_action) { + flow_dv_aso_mtr_release_to_pool(dev, mtr_idx); + return 0; + } + } return mtr_idx; } @@ -11595,7 +11616,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->mfts->meter_action; + wks->fm->meter_action; action_flags |= MLX5_FLOW_ACTION_METER; break; case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: @@ -12757,7 +12778,7 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) if (flow->meter) { fm = flow_dv_meter_find_by_idx(priv, flow->meter); if (fm) - mlx5_flow_meter_detach(fm); + mlx5_flow_meter_detach(priv, fm); flow->meter = 0; } if (flow->age) diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c index fcefc135b4..714b382d55 100644 --- a/drivers/net/mlx5/mlx5_flow_meter.c +++ b/drivers/net/mlx5/mlx5_flow_meter.c @@ -602,9 +602,9 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv, ebs_mantissa, val); } /* Apply modifications to meter only if it was created. */ - if (fm->mfts->meter_action) { + if (fm->meter_action) { ret = mlx5_glue->dv_modify_flow_action_meter - (fm->mfts->meter_action, &mod_attr, + (fm->meter_action, &mod_attr, rte_cpu_to_be_64(modify_bits)); if (ret) return ret; @@ -620,6 +620,7 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv, (void)srtcm; (void)modify_bits; (void)active_state; + (void)is_enable; return -ENOTSUP; #endif } @@ -1405,63 +1406,91 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv, { int ret = 0; - rte_spinlock_lock(&fm->sl); - if (fm->mfts->meter_action) { - if (fm->shared && - attr->transfer == fm->transfer && - attr->ingress == fm->ingress && - attr->egress == fm->egress) + if (priv->sh->meter_aso_en) { + struct mlx5_aso_mtr *aso_mtr; + + aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); + if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) { + return rte_flow_error_set(error, ENOENT, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Timeout in meter configuration"); + } + rte_spinlock_lock(&fm->sl); + if (fm->shared || !fm->ref_cnt) { fm->ref_cnt++; - else + } else { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter cannot be shared"); ret = -1; + } + rte_spinlock_unlock(&fm->sl); } else { - fm->ingress = attr->ingress; - fm->egress = attr->egress; - fm->transfer = attr->transfer; - fm->ref_cnt = 1; - /* This also creates the meter object. */ - fm->mfts->meter_action = mlx5_flow_meter_action_create(priv, - fm); - if (!fm->mfts->meter_action) { - fm->ref_cnt = 0; - fm->ingress = 0; - fm->egress = 0; - fm->transfer = 0; - ret = -1; - DRV_LOG(ERR, "Meter action create failed."); + rte_spinlock_lock(&fm->sl); + if (fm->meter_action) { + if (fm->shared && + attr->transfer == fm->transfer && + attr->ingress == fm->ingress && + attr->egress == fm->egress) { + fm->ref_cnt++; + } else { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + fm->shared ? + "Meter attr not match." : + "Meter cannot be shared."); + ret = -1; + } + } else { + fm->ingress = attr->ingress; + fm->egress = attr->egress; + fm->transfer = attr->transfer; + fm->ref_cnt = 1; + /* This also creates the meter object. */ + fm->meter_action = mlx5_flow_meter_action_create(priv, + fm); + if (!fm->meter_action) { + fm->ref_cnt = 0; + fm->ingress = 0; + fm->egress = 0; + fm->transfer = 0; + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter action create failed."); + ret = -1; + } } + rte_spinlock_unlock(&fm->sl); } - rte_spinlock_unlock(&fm->sl); - if (ret) - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - fm->mfts->meter_action ? - "Meter attr not match" : - "Meter action create failed"); return ret ? -rte_errno : 0; } /** * Detach meter from flow. * + * @param [in] priv + * Pointer to mlx5 private data. * @param [in] fm * Pointer to flow meter. */ void -mlx5_flow_meter_detach(struct mlx5_flow_meter_info *fm) +mlx5_flow_meter_detach(struct mlx5_priv *priv, + struct mlx5_flow_meter_info *fm) { #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER rte_spinlock_lock(&fm->sl); MLX5_ASSERT(fm->ref_cnt); - if (--fm->ref_cnt == 0) { - mlx5_glue->destroy_flow_action(fm->mfts->meter_action); - fm->mfts->meter_action = NULL; + if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) { + mlx5_glue->destroy_flow_action(fm->meter_action); + fm->meter_action = NULL; fm->ingress = 0; fm->egress = 0; fm->transfer = 0; } rte_spinlock_unlock(&fm->sl); #else + (void)priv; (void)fm; #endif }