From: Suanming Mou Date: Fri, 8 Nov 2019 03:49:10 +0000 (+0200) Subject: net/mlx5: support meter profile operations X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=3bd26b23cefc78c71d8cd7234224ffe14bbb7e45;p=dpdk.git net/mlx5: support meter profile operations This commit add the support of meter profile add and delete operations. New internal functions in rte_mtr_ops callback: 1. meter_profile_add() 2. meter_profile_delete() Only RTE_MTR_SRTCM_RFC2697 algorithm is supported and can be added. To add other algorithm will report an error. Signed-off-by: Suanming Mou Acked-by: Matan Azrad --- diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile index 0065e5589d..d01fa731fa 100644 --- a/drivers/net/mlx5/Makefile +++ b/drivers/net/mlx5/Makefile @@ -64,6 +64,7 @@ LDLIBS += $(shell $(RTE_SDK)/buildtools/options-ibverbs-static.sh) else LDLIBS += -libverbs -lmlx5 endif +LDLIBS += -lm LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs LDLIBS += -lrte_bus_pci diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 3b30169e08..3bebad3216 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -2403,6 +2403,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, mlx5_nl_mac_addr_sync(eth_dev); TAILQ_INIT(&priv->flows); TAILQ_INIT(&priv->ctrl_flows); + TAILQ_INIT(&priv->flow_meter_profiles); /* Hint libmlx5 to use PMD allocator for data plane resources */ struct mlx5dv_ctx_allocators alctr = { .alloc = &mlx5_alloc_verbs_buf, diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index f19ea23923..dbeab2b984 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -684,6 +684,9 @@ struct mlx5_proc_priv { /* Table of UAR registers for each process. */ }; +/* MTR profile list. */ +TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile); + #define MLX5_PROC_PRIV(port_id) \ ((struct mlx5_proc_priv *)rte_eth_devices[port_id].process_private) @@ -754,6 +757,7 @@ struct mlx5_priv { /* Hash table of Rx metadata register copy table. */ uint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */ uint8_t mtr_color_reg; /* Meter color match REG_C. */ + struct mlx5_mtr_profiles flow_meter_profiles; /* MTR profile list. */ #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]; diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index ac1675456d..d755d1138a 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -23,6 +23,7 @@ #include #include +#include #include "mlx5.h" #include "mlx5_prm.h" @@ -522,6 +523,34 @@ struct mlx5_flow { bool external; /**< true if the flow is created external to PMD. */ }; +#define MLX5_MAN_WIDTH 8 + +/* RFC2697 parameter structure. */ +struct mlx5_flow_meter_srtcm_rfc2697_prm { + /* green_saturation_value = cbs_mantissa * 2^cbs_exponent */ + uint32_t cbs_exponent:5; + uint32_t cbs_mantissa:8; + /* cir = 8G * cir_mantissa * 1/(2^cir_exponent) Bytes/Sec */ + uint32_t cir_exponent:5; + uint32_t cir_mantissa:8; + /* yellow _saturation_value = ebs_mantissa * 2^ebs_exponent */ + uint32_t ebs_exponent:5; + uint32_t ebs_mantissa:8; +}; + +/* Flow meter profile structure. */ +struct mlx5_flow_meter_profile { + TAILQ_ENTRY(mlx5_flow_meter_profile) next; + /**< Pointer to the next flow meter structure. */ + uint32_t meter_profile_id; /**< Profile id. */ + struct rte_mtr_meter_profile profile; /**< Profile detail. */ + union { + struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm_prm; + /**< srtcm_rfc2697 struct. */ + }; + uint32_t ref_cnt; /**< Use count. */ +}; + /* Flow structure. */ struct rte_flow { TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */ diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c index 9103b6de37..b11962fa9f 100644 --- a/drivers/net/mlx5/mlx5_flow_meter.c +++ b/drivers/net/mlx5/mlx5_flow_meter.c @@ -4,12 +4,157 @@ */ #include +#include #include #include #include "mlx5.h" #include "mlx5_flow.h" +/** + * Find meter profile by id. + * + * @param priv + * Pointer to mlx5_priv. + * @param meter_profile_id + * Meter profile id. + * + * @return + * Pointer to the profile found on success, NULL otherwise. + */ +static struct mlx5_flow_meter_profile * +mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id) +{ + struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles; + struct mlx5_flow_meter_profile *fmp; + + TAILQ_FOREACH(fmp, fmps, next) + if (meter_profile_id == fmp->meter_profile_id) + return fmp; + return NULL; +} + +/** + * Calculate mantissa and exponent for cir. + * + * @param[in] cir + * Value to be calculated. + * @param[out] man + * Pointer to the mantissa. + * @param[out] exp + * Pointer to the exp. + */ +static void +mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp) +{ + int64_t _cir; + int64_t delta = INT64_MAX; + uint8_t _man = 0; + uint8_t _exp = 0; + uint64_t m, e; + + for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */ + for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */ + _cir = (1000000000ULL * m) >> e; + if (llabs(cir - _cir) <= delta) { + delta = llabs(cir - _cir); + _man = m; + _exp = e; + } + } + } + *man = _man; + *exp = _exp; +} + +/** + * Calculate mantissa and exponent for xbs. + * + * @param[in] xbs + * Value to be calculated. + * @param[out] man + * Pointer to the mantissa. + * @param[out] exp + * Pointer to the exp. + */ +static void +mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp) +{ + int _exp; + double _man; + + /* Special case xbs == 0 ? both exp and matissa are 0. */ + if (xbs == 0) { + *man = 0; + *exp = 0; + return; + } + /* xbs = xbs_mantissa * 2^xbs_exponent */ + _man = frexp(xbs, &_exp); + _man = _man * pow(2, MLX5_MAN_WIDTH); + _exp = _exp - MLX5_MAN_WIDTH; + *man = (uint8_t)ceil(_man); + *exp = _exp; +} + +/** + * Fill the prm meter parameter. + * + * @param[in,out] fmp + * Pointer to meter profie to be converted. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp, + struct rte_mtr_error *error) +{ + struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm; + uint8_t man, exp; + + if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, "Metering algorithm not supported."); + /* cbs = cbs_mantissa * 2^cbs_exponent */ + mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs, + &man, &exp); + srtcm->cbs_mantissa = man; + srtcm->cbs_exponent = exp; + /* Check if cbs mantissa is too large. */ + if (srtcm->cbs_exponent != exp) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, + "Metering profile parameter cbs is" + " invalid."); + /* ebs = ebs_mantissa * 2^ebs_exponent */ + mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs, + &man, &exp); + srtcm->ebs_mantissa = man; + srtcm->ebs_exponent = exp; + /* Check if ebs mantissa is too large. */ + if (srtcm->ebs_exponent != exp) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, + "Metering profile parameter ebs is" + " invalid."); + /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */ + mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir, + &man, &exp); + srtcm->cir_mantissa = man; + srtcm->cir_exponent = exp; + /* Check if cir mantissa is too large. */ + if (srtcm->cir_exponent != exp) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, + "Metering profile parameter cir is" + " invalid."); + return 0; +} + /** * Callback to get MTR capabilities. * @@ -51,10 +196,106 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev, return 0; } +/** + * Callback to add MTR profile. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_profile_id + * Meter profile id. + * @param[in] profile + * Pointer to meter profile detail. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_profile_add(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_meter_profile *profile, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles; + struct mlx5_flow_meter_profile *fmp; + int ret; + + if (!priv->mtr_en) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter is not support"); + /* Meter profile memory allocation. */ + fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile), + RTE_CACHE_LINE_SIZE); + if (fmp == NULL) + return -rte_mtr_error_set(error, ENOMEM, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter profile memory " + "alloc failed."); + /* Fill profile info. */ + fmp->meter_profile_id = meter_profile_id; + fmp->profile = *profile; + /* Fill the flow meter parameters for the PRM. */ + ret = mlx5_flow_meter_param_fill(fmp, error); + if (ret) + goto error; + /* Add to list. */ + TAILQ_INSERT_TAIL(fmps, fmp, next); + return 0; +error: + rte_free(fmp); + return ret; +} + +/** + * Callback to delete MTR profile. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_profile_id + * Meter profile id. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_meter_profile *fmp; + + if (!priv->mtr_en) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter is not support"); + /* Meter profile must exist. */ + fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); + if (fmp == NULL) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + &meter_profile_id, + "Meter profile id invalid."); + /* Check profile is unused. */ + if (fmp->ref_cnt) + return -rte_mtr_error_set(error, EBUSY, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile in use."); + /* Remove from list. */ + TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next); + rte_free(fmp); + return 0; +} + static const struct rte_mtr_ops mlx5_flow_mtr_ops = { .capabilities_get = mlx5_flow_mtr_cap_get, - .meter_profile_add = NULL, - .meter_profile_delete = NULL, + .meter_profile_add = mlx5_flow_meter_profile_add, + .meter_profile_delete = mlx5_flow_meter_profile_delete, .create = NULL, .destroy = NULL, .meter_enable = NULL,