1 // SPDX-License-Identifier: BSD-3-Clause
3 * Copyright 2018 Mellanox Technologies, Ltd
8 #include <rte_malloc.h>
10 #include <rte_mtr_driver.h>
13 #include "mlx5_flow.h"
16 * Create the meter action.
19 * Pointer to mlx5_priv.
21 * Pointer to flow meter to be converted.
24 * Pointer to the meter action on success, NULL otherwise.
27 mlx5_flow_meter_action_create(struct mlx5_priv *priv,
28 struct mlx5_flow_meter *fm)
30 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
31 struct mlx5dv_dr_flow_meter_attr mtr_init;
32 void *attr = fm->mfts->fmp;
33 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
34 &fm->profile->srtcm_prm;
36 fm->mfts->fmp_size = MLX5_ST_SZ_BYTES(flow_meter_parameters);
37 memset(attr, 0, fm->mfts->fmp_size);
38 MLX5_SET(flow_meter_parameters, attr, valid, 1);
39 MLX5_SET(flow_meter_parameters, attr, bucket_overflow, 1);
40 MLX5_SET(flow_meter_parameters, attr,
41 start_color, MLX5_FLOW_COLOR_GREEN);
42 MLX5_SET(flow_meter_parameters, attr, both_buckets_on_green, 0);
43 MLX5_SET(flow_meter_parameters,
44 attr, cbs_exponent, srtcm->cbs_exponent);
45 MLX5_SET(flow_meter_parameters,
46 attr, cbs_mantissa, srtcm->cbs_mantissa);
47 MLX5_SET(flow_meter_parameters,
48 attr, cir_exponent, srtcm->cir_exponent);
49 MLX5_SET(flow_meter_parameters,
50 attr, cir_mantissa, srtcm->cir_mantissa);
51 MLX5_SET(flow_meter_parameters,
52 attr, ebs_exponent, srtcm->ebs_exponent);
53 MLX5_SET(flow_meter_parameters,
54 attr, ebs_mantissa, srtcm->ebs_mantissa);
56 fm->attr.transfer ? fm->mfts->transfer.tbl->obj :
57 fm->attr.egress ? fm->mfts->egress.tbl->obj :
58 fm->mfts->ingress.tbl->obj;
59 mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
60 mtr_init.flow_meter_parameter = fm->mfts->fmp;
61 mtr_init.flow_meter_parameter_sz = fm->mfts->fmp_size;
62 mtr_init.active = fm->active_state;
63 return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
72 * Find meter profile by id.
75 * Pointer to mlx5_priv.
76 * @param meter_profile_id
80 * Pointer to the profile found on success, NULL otherwise.
82 static struct mlx5_flow_meter_profile *
83 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
85 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
86 struct mlx5_flow_meter_profile *fmp;
88 TAILQ_FOREACH(fmp, fmps, next)
89 if (meter_profile_id == fmp->meter_profile_id)
95 * Validate the MTR profile.
98 * Pointer to Ethernet device.
99 * @param[in] meter_profile_id
102 * Pointer to meter profile detail.
104 * Pointer to the error structure.
107 * 0 on success, a negative errno value otherwise and rte_errno is set.
110 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
111 uint32_t meter_profile_id,
112 struct rte_mtr_meter_profile *profile,
113 struct rte_mtr_error *error)
115 struct mlx5_priv *priv = dev->data->dev_private;
116 struct mlx5_flow_meter_profile *fmp;
118 /* Profile must not be NULL. */
120 return -rte_mtr_error_set(error, EINVAL,
121 RTE_MTR_ERROR_TYPE_METER_PROFILE,
122 NULL, "Meter profile is null.");
123 /* Meter profile ID must be valid. */
124 if (meter_profile_id == UINT32_MAX)
125 return -rte_mtr_error_set(error, EINVAL,
126 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
127 NULL, "Meter profile id not valid.");
128 /* Meter profile must not exist. */
129 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
131 return -rte_mtr_error_set(error, EEXIST,
132 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
134 "Meter profile already exists.");
135 if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
136 if (priv->config.hca_attr.qos.srtcm_sup) {
137 /* Verify support for flow meter parameters. */
138 if (profile->srtcm_rfc2697.cir > 0 &&
139 profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
140 profile->srtcm_rfc2697.cbs > 0 &&
141 profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
142 profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
145 return -rte_mtr_error_set
147 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
149 profile->srtcm_rfc2697.ebs ?
150 "Metering value ebs must be 0." :
151 "Invalid metering parameters.");
154 return -rte_mtr_error_set(error, ENOTSUP,
155 RTE_MTR_ERROR_TYPE_METER_PROFILE,
156 NULL, "Metering algorithm not supported.");
160 * Calculate mantissa and exponent for cir.
163 * Value to be calculated.
165 * Pointer to the mantissa.
167 * Pointer to the exp.
170 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
173 int64_t delta = INT64_MAX;
178 for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
179 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
180 _cir = (1000000000ULL * m) >> e;
181 if (llabs(cir - _cir) <= delta) {
182 delta = llabs(cir - _cir);
193 * Calculate mantissa and exponent for xbs.
196 * Value to be calculated.
198 * Pointer to the mantissa.
200 * Pointer to the exp.
203 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
208 /* Special case xbs == 0 ? both exp and matissa are 0. */
214 /* xbs = xbs_mantissa * 2^xbs_exponent */
215 _man = frexp(xbs, &_exp);
216 _man = _man * pow(2, MLX5_MAN_WIDTH);
217 _exp = _exp - MLX5_MAN_WIDTH;
218 *man = (uint8_t)ceil(_man);
223 * Fill the prm meter parameter.
226 * Pointer to meter profie to be converted.
228 * Pointer to the error structure.
231 * 0 on success, a negative errno value otherwise and rte_errno is set.
234 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
235 struct rte_mtr_error *error)
237 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
240 if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
241 return -rte_mtr_error_set(error, ENOTSUP,
242 RTE_MTR_ERROR_TYPE_METER_PROFILE,
243 NULL, "Metering algorithm not supported.");
244 /* cbs = cbs_mantissa * 2^cbs_exponent */
245 mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
247 srtcm->cbs_mantissa = man;
248 srtcm->cbs_exponent = exp;
249 /* Check if cbs mantissa is too large. */
250 if (srtcm->cbs_exponent != exp)
251 return -rte_mtr_error_set(error, EINVAL,
252 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
253 "Metering profile parameter cbs is"
255 /* ebs = ebs_mantissa * 2^ebs_exponent */
256 mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
258 srtcm->ebs_mantissa = man;
259 srtcm->ebs_exponent = exp;
260 /* Check if ebs mantissa is too large. */
261 if (srtcm->ebs_exponent != exp)
262 return -rte_mtr_error_set(error, EINVAL,
263 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
264 "Metering profile parameter ebs is"
266 /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
267 mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
269 srtcm->cir_mantissa = man;
270 srtcm->cir_exponent = exp;
271 /* Check if cir mantissa is too large. */
272 if (srtcm->cir_exponent != exp)
273 return -rte_mtr_error_set(error, EINVAL,
274 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
275 "Metering profile parameter cir is"
281 * Callback to get MTR capabilities.
284 * Pointer to Ethernet device.
286 * Pointer to save MTR capabilities.
288 * Pointer to the error structure.
291 * 0 on success, a negative errno value otherwise and rte_errno is set.
294 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
295 struct rte_mtr_capabilities *cap,
296 struct rte_mtr_error *error __rte_unused)
298 struct mlx5_priv *priv = dev->data->dev_private;
299 struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
302 return -rte_mtr_error_set(error, ENOTSUP,
303 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
304 "Meter is not support");
305 memset(cap, 0, sizeof(*cap));
306 cap->n_max = 1 << qattr->log_max_flow_meter;
307 cap->n_shared_max = cap->n_max;
309 cap->shared_identical = 1;
310 cap->shared_n_flows_per_mtr_max = 4 << 20;
311 /* 2M flows can share the same meter. */
312 cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
313 cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0;
314 cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
315 cap->policer_action_drop_supported = 1;
316 cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
317 RTE_MTR_STATS_N_PKTS_DROPPED;
322 * Callback to add MTR profile.
325 * Pointer to Ethernet device.
326 * @param[in] meter_profile_id
329 * Pointer to meter profile detail.
331 * Pointer to the error structure.
334 * 0 on success, a negative errno value otherwise and rte_errno is set.
337 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
338 uint32_t meter_profile_id,
339 struct rte_mtr_meter_profile *profile,
340 struct rte_mtr_error *error)
342 struct mlx5_priv *priv = dev->data->dev_private;
343 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
344 struct mlx5_flow_meter_profile *fmp;
348 return -rte_mtr_error_set(error, ENOTSUP,
349 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
350 "Meter is not support");
351 /* Check input params. */
352 ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
356 /* Meter profile memory allocation. */
357 fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
358 RTE_CACHE_LINE_SIZE);
360 return -rte_mtr_error_set(error, ENOMEM,
361 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
362 NULL, "Meter profile memory "
364 /* Fill profile info. */
365 fmp->meter_profile_id = meter_profile_id;
366 fmp->profile = *profile;
367 /* Fill the flow meter parameters for the PRM. */
368 ret = mlx5_flow_meter_param_fill(fmp, error);
372 TAILQ_INSERT_TAIL(fmps, fmp, next);
380 * Callback to delete MTR profile.
383 * Pointer to Ethernet device.
384 * @param[in] meter_profile_id
387 * Pointer to the error structure.
390 * 0 on success, a negative errno value otherwise and rte_errno is set.
393 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
394 uint32_t meter_profile_id,
395 struct rte_mtr_error *error)
397 struct mlx5_priv *priv = dev->data->dev_private;
398 struct mlx5_flow_meter_profile *fmp;
401 return -rte_mtr_error_set(error, ENOTSUP,
402 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
403 "Meter is not support");
404 /* Meter profile must exist. */
405 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
407 return -rte_mtr_error_set(error, ENOENT,
408 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
410 "Meter profile id invalid.");
411 /* Check profile is unused. */
413 return -rte_mtr_error_set(error, EBUSY,
414 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
415 NULL, "Meter profile in use.");
416 /* Remove from list. */
417 TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
423 * Convert wrong color setting action to verbose error.
426 * Policy color action.
429 * Verbose meter color error type.
431 static inline enum rte_mtr_error_type
432 action2error(enum rte_mtr_policer_action action)
435 case MTR_POLICER_ACTION_COLOR_GREEN:
436 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN;
437 case MTR_POLICER_ACTION_COLOR_YELLOW:
438 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW;
439 case MTR_POLICER_ACTION_COLOR_RED:
440 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED;
444 return RTE_MTR_ERROR_TYPE_UNSPECIFIED;
448 * Check meter validation.
451 * Pointer to mlx5 private data structure.
452 * @param[in] meter_id
455 * Pointer to rte meter parameters.
457 * Pointer to rte meter error structure.
460 * 0 on success, a negative errno value otherwise and rte_errno is set.
463 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
464 struct rte_mtr_params *params,
465 struct rte_mtr_error *error)
467 static enum rte_mtr_policer_action
468 valid_recol_action[RTE_COLORS] = {
469 MTR_POLICER_ACTION_COLOR_GREEN,
470 MTR_POLICER_ACTION_COLOR_YELLOW,
471 MTR_POLICER_ACTION_COLOR_RED };
474 /* Meter params must not be NULL. */
476 return -rte_mtr_error_set(error, EINVAL,
477 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
478 NULL, "Meter object params null.");
479 /* Previous meter color is not supported. */
480 if (params->use_prev_mtr_color)
481 return -rte_mtr_error_set(error, ENOTSUP,
482 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
484 "Previous meter color "
486 /* Validate policer settings. */
487 for (i = 0; i < RTE_COLORS; i++)
488 if (params->action[i] != valid_recol_action[i] &&
489 params->action[i] != MTR_POLICER_ACTION_DROP)
490 return -rte_mtr_error_set
492 action2error(params->action[i]), NULL,
493 "Recolor action not supported.");
494 /* Validate meter id. */
495 if (mlx5_flow_meter_find(priv, meter_id))
496 return -rte_mtr_error_set(error, EEXIST,
497 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
498 "Meter object already exists.");
503 * Modify the flow meter action.
506 * Pointer to mlx5 private data structure.
508 * Pointer to flow meter to be modified.
510 * Pointer to meter srtcm description parameter.
511 * @param[in] modify_bits
512 * The bit in srtcm to be updated.
513 * @param[in] active_state
514 * The state to be updated.
516 * 0 on success, o negative value otherwise.
519 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
520 struct mlx5_flow_meter *fm,
521 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
522 uint64_t modify_bits, uint32_t active_state)
524 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
525 uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
527 struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
530 /* Fill command parameters. */
531 mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
532 mod_attr.flow_meter_parameter = in;
533 mod_attr.flow_meter_parameter_sz = fm->mfts->fmp_size;
534 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
535 mod_attr.active = !!active_state;
539 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
540 MLX5_SET(flow_meter_parameters,
541 attr, cbs_exponent, srtcm->cbs_exponent);
542 MLX5_SET(flow_meter_parameters,
543 attr, cbs_mantissa, srtcm->cbs_mantissa);
545 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
546 MLX5_SET(flow_meter_parameters,
547 attr, cir_exponent, srtcm->cir_exponent);
548 MLX5_SET(flow_meter_parameters,
549 attr, cir_mantissa, srtcm->cir_mantissa);
551 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
552 MLX5_SET(flow_meter_parameters,
553 attr, ebs_exponent, srtcm->ebs_exponent);
554 MLX5_SET(flow_meter_parameters,
555 attr, ebs_mantissa, srtcm->ebs_mantissa);
557 /* Apply modifications to meter only if it was created. */
558 if (fm->mfts->meter_action) {
559 ret = mlx5_glue->dv_modify_flow_action_meter
560 (fm->mfts->meter_action, &mod_attr,
561 rte_cpu_to_be_64(modify_bits));
565 /* Update succeedded modify meter parameters. */
566 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
567 fm->active_state = !!active_state;
568 attr = fm->mfts->fmp;
569 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
570 MLX5_SET(flow_meter_parameters,
571 attr, cbs_exponent, srtcm->cbs_exponent);
572 MLX5_SET(flow_meter_parameters,
573 attr, cbs_mantissa, srtcm->cbs_mantissa);
575 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
576 MLX5_SET(flow_meter_parameters,
577 attr, cir_exponent, srtcm->cir_exponent);
578 MLX5_SET(flow_meter_parameters,
579 attr, cir_mantissa, srtcm->cir_mantissa);
581 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
582 MLX5_SET(flow_meter_parameters,
583 attr, ebs_exponent, srtcm->ebs_exponent);
584 MLX5_SET(flow_meter_parameters,
585 attr, ebs_mantissa, srtcm->ebs_mantissa);
600 * Create meter rules.
603 * Pointer to Ethernet device.
604 * @param[in] meter_id
607 * Pointer to rte meter parameters.
609 * Meter shared with other flow or not.
611 * Pointer to rte meter error structure.
614 * 0 on success, a negative errno value otherwise and rte_errno is set.
617 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
618 struct rte_mtr_params *params, int shared,
619 struct rte_mtr_error *error)
621 struct mlx5_priv *priv = dev->data->dev_private;
622 struct mlx5_flow_meters *fms = &priv->flow_meters;
623 struct mlx5_flow_meter_profile *fmp;
624 struct mlx5_flow_meter *fm;
625 const struct rte_flow_attr attr = {
628 .transfer = priv->config.dv_esw_en ? 1 : 0,
634 return -rte_mtr_error_set(error, ENOTSUP,
635 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
636 "Meter is not support");
637 /* Validate the parameters. */
638 ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
641 /* Meter profile must exist. */
642 fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
644 return -rte_mtr_error_set(error, ENOENT,
645 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
646 NULL, "Meter profile id not valid.");
647 /* Allocate the flow meter memory. */
648 fm = rte_calloc(__func__, 1,
649 sizeof(struct mlx5_flow_meter), RTE_CACHE_LINE_SIZE);
651 return -rte_mtr_error_set(error, ENOMEM,
652 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
653 "Memory alloc failed for meter.");
654 /* Fill the flow meter parameters. */
655 fm->meter_id = meter_id;
657 fm->params = *params;
658 /* Alloc policer counters. */
659 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) {
660 fm->policer_stats.cnt[i] = mlx5_counter_alloc(dev);
661 if (!fm->policer_stats.cnt[i])
664 fm->mfts = mlx5_flow_create_mtr_tbls(dev, fm);
667 ret = mlx5_flow_create_policer_rules(dev, fm, &attr);
670 /* Add to the flow meter list. */
671 TAILQ_INSERT_TAIL(fms, fm, next);
672 fm->active_state = 1; /* Config meter starts as active. */
673 fm->shared = !!shared;
674 fm->policer_stats.stats_mask = params->stats_mask;
675 fm->profile->ref_cnt++;
678 mlx5_flow_destroy_policer_rules(dev, fm, &attr);
679 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
680 /* Free policer counters. */
681 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
682 if (fm->policer_stats.cnt[i])
683 mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
685 return -rte_mtr_error_set(error, -ret,
686 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
687 NULL, "Failed to create devx meter.");
691 * Destroy meter rules.
694 * Pointer to Ethernet device.
695 * @param[in] meter_id
698 * Pointer to rte meter error structure.
701 * 0 on success, a negative errno value otherwise and rte_errno is set.
704 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
705 struct rte_mtr_error *error)
707 struct mlx5_priv *priv = dev->data->dev_private;
708 struct mlx5_flow_meters *fms = &priv->flow_meters;
709 struct mlx5_flow_meter_profile *fmp;
710 struct mlx5_flow_meter *fm;
711 const struct rte_flow_attr attr = {
714 .transfer = priv->config.dv_esw_en ? 1 : 0,
719 return -rte_mtr_error_set(error, ENOTSUP,
720 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
721 "Meter is not support");
722 /* Meter object must exist. */
723 fm = mlx5_flow_meter_find(priv, meter_id);
725 return -rte_mtr_error_set(error, ENOENT,
726 RTE_MTR_ERROR_TYPE_MTR_ID,
727 NULL, "Meter object id not valid.");
728 /* Meter object must not have any owner. */
730 return -rte_mtr_error_set(error, EBUSY,
731 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
732 NULL, "Meter object is being used.");
733 /* Get the meter profile. */
736 /* Update dependencies. */
738 /* Remove from the flow meter list. */
739 TAILQ_REMOVE(fms, fm, next);
740 /* Free policer counters. */
741 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
742 if (fm->policer_stats.cnt[i])
743 mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
744 /* Free meter flow table */
745 mlx5_flow_destroy_policer_rules(dev, fm, &attr);
746 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
752 * Modify meter state.
755 * Pointer to mlx5 private data structure.
757 * Pointer to flow meter.
758 * @param[in] new_state
759 * New state to update.
761 * Pointer to rte meter error structure.
764 * 0 on success, a negative errno value otherwise and rte_errno is set.
767 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
768 struct mlx5_flow_meter *fm,
770 struct rte_mtr_error *error)
772 static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
780 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
781 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
784 if (new_state == MLX5_FLOW_METER_DISABLE)
785 ret = mlx5_flow_meter_action_modify(priv, fm, &srtcm,
788 ret = mlx5_flow_meter_action_modify(priv, fm,
789 &fm->profile->srtcm_prm,
792 return -rte_mtr_error_set(error, -ret,
793 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
796 "Failed to enable meter." :
797 "Failed to disable meter.");
802 * Callback to enable flow meter.
805 * Pointer to Ethernet device.
806 * @param[in] meter_id
809 * Pointer to rte meter error structure.
812 * 0 on success, a negative errno value otherwise and rte_errno is set.
815 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
817 struct rte_mtr_error *error)
819 struct mlx5_priv *priv = dev->data->dev_private;
820 struct mlx5_flow_meter *fm;
824 return -rte_mtr_error_set(error, ENOTSUP,
825 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
826 "Meter is not support");
827 /* Meter object must exist. */
828 fm = mlx5_flow_meter_find(priv, meter_id);
830 return -rte_mtr_error_set(error, ENOENT,
831 RTE_MTR_ERROR_TYPE_MTR_ID,
832 NULL, "Meter not found.");
833 if (fm->active_state == MLX5_FLOW_METER_ENABLE)
835 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
838 fm->active_state = MLX5_FLOW_METER_ENABLE;
843 * Callback to disable flow meter.
846 * Pointer to Ethernet device.
847 * @param[in] meter_id
850 * Pointer to rte meter error structure.
853 * 0 on success, a negative errno value otherwise and rte_errno is set.
856 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
858 struct rte_mtr_error *error)
860 struct mlx5_priv *priv = dev->data->dev_private;
861 struct mlx5_flow_meter *fm;
865 return -rte_mtr_error_set(error, ENOTSUP,
866 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
867 "Meter is not support");
868 /* Meter object must exist. */
869 fm = mlx5_flow_meter_find(priv, meter_id);
871 return -rte_mtr_error_set(error, ENOENT,
872 RTE_MTR_ERROR_TYPE_MTR_ID,
873 NULL, "Meter not found.");
874 if (fm->active_state == MLX5_FLOW_METER_DISABLE)
876 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
879 fm->active_state = MLX5_FLOW_METER_DISABLE;
884 * Callback to update meter profile.
887 * Pointer to Ethernet device.
888 * @param[in] meter_id
890 * @param[in] meter_profile_id
891 * To be updated meter profile id.
893 * Pointer to rte meter error structure.
896 * 0 on success, a negative errno value otherwise and rte_errno is set.
899 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
901 uint32_t meter_profile_id,
902 struct rte_mtr_error *error)
904 struct mlx5_priv *priv = dev->data->dev_private;
905 struct mlx5_flow_meter_profile *fmp;
906 struct mlx5_flow_meter_profile *old_fmp;
907 struct mlx5_flow_meter *fm;
908 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
909 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
913 return -rte_mtr_error_set(error, ENOTSUP,
914 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
915 "Meter is not support");
916 /* Meter profile must exist. */
917 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
919 return -rte_mtr_error_set(error, ENOENT,
920 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
921 NULL, "Meter profile not found.");
922 /* Meter object must exist. */
923 fm = mlx5_flow_meter_find(priv, meter_id);
925 return -rte_mtr_error_set(error, ENOENT,
926 RTE_MTR_ERROR_TYPE_MTR_ID,
927 NULL, "Meter not found.");
928 /* MTR object already set to meter profile id. */
929 old_fmp = fm->profile;
932 /* Update the profile. */
934 /* Update meter params in HW (if not disabled). */
935 if (fm->active_state == MLX5_FLOW_METER_DISABLE)
937 ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
938 modify_bits, fm->active_state);
940 fm->profile = old_fmp;
941 return -rte_mtr_error_set(error, -ret,
942 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
943 NULL, "Failed to update meter"
944 " parmeters in hardware.");
952 * Callback to update meter stats mask.
955 * Pointer to Ethernet device.
956 * @param[in] meter_id
958 * @param[in] stats_mask
959 * To be updated stats_mask.
961 * Pointer to rte meter error structure.
964 * 0 on success, a negative errno value otherwise and rte_errno is set.
967 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
970 struct rte_mtr_error *error)
972 struct mlx5_priv *priv = dev->data->dev_private;
973 struct mlx5_flow_meter *fm;
976 return -rte_mtr_error_set(error, ENOTSUP,
977 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
978 "Meter is not support");
979 /* Meter object must exist. */
980 fm = mlx5_flow_meter_find(priv, meter_id);
982 return -rte_mtr_error_set(error, ENOENT,
983 RTE_MTR_ERROR_TYPE_MTR_ID,
984 NULL, "Meter object id not valid.");
985 fm->policer_stats.stats_mask = stats_mask;
990 * Callback to read meter statistics.
993 * Pointer to Ethernet device.
994 * @param[in] meter_id
997 * Pointer to store the statistics.
998 * @param[out] stats_mask
999 * Pointer to store the stats_mask.
1001 * Statistic to be cleared after read or not.
1003 * Pointer to rte meter error structure.
1006 * 0 on success, a negative errno value otherwise and rte_errno is set.
1009 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
1011 struct rte_mtr_stats *stats,
1012 uint64_t *stats_mask,
1014 struct rte_mtr_error *error)
1016 static uint64_t meter2mask[RTE_MTR_DROPPED + 1] = {
1017 RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_BYTES_GREEN,
1018 RTE_MTR_STATS_N_PKTS_YELLOW | RTE_MTR_STATS_N_BYTES_YELLOW,
1019 RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED,
1020 RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED
1022 struct mlx5_priv *priv = dev->data->dev_private;
1023 struct mlx5_flow_meter *fm;
1024 struct mlx5_flow_policer_stats *ps;
1025 uint64_t pkts_dropped = 0;
1026 uint64_t bytes_dropped = 0;
1033 return -rte_mtr_error_set(error, ENOTSUP,
1034 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1035 "Meter is not support");
1036 /* Meter object must exist. */
1037 fm = mlx5_flow_meter_find(priv, meter_id);
1039 return -rte_mtr_error_set(error, ENOENT,
1040 RTE_MTR_ERROR_TYPE_MTR_ID,
1041 NULL, "Meter object id not valid.");
1042 ps = &fm->policer_stats;
1043 *stats_mask = ps->stats_mask;
1044 for (i = 0; i < RTE_MTR_DROPPED; i++) {
1045 if (*stats_mask & meter2mask[i]) {
1046 ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
1050 if (fm->params.action[i] == MTR_POLICER_ACTION_DROP) {
1051 pkts_dropped += pkts;
1052 bytes_dropped += bytes;
1054 /* If need to read the packets, set it. */
1055 if ((1 << i) & (*stats_mask & meter2mask[i]))
1056 stats->n_pkts[i] = pkts;
1057 /* If need to read the bytes, set it. */
1058 if ((1 << (RTE_MTR_DROPPED + 1 + i)) &
1059 (*stats_mask & meter2mask[i]))
1060 stats->n_bytes[i] = bytes;
1063 /* Dropped packets/bytes are treated differently. */
1064 if (*stats_mask & meter2mask[i]) {
1065 ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
1069 pkts += pkts_dropped;
1070 bytes += bytes_dropped;
1071 /* If need to read the packets, set it. */
1072 if ((*stats_mask & meter2mask[i]) &
1073 RTE_MTR_STATS_N_PKTS_DROPPED)
1074 stats->n_pkts_dropped = pkts;
1075 /* If need to read the bytes, set it. */
1076 if ((*stats_mask & meter2mask[i]) &
1077 RTE_MTR_STATS_N_BYTES_DROPPED)
1078 stats->n_bytes_dropped = bytes;
1082 return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
1083 "Failed to read policer counters.");
1086 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
1087 .capabilities_get = mlx5_flow_mtr_cap_get,
1088 .meter_profile_add = mlx5_flow_meter_profile_add,
1089 .meter_profile_delete = mlx5_flow_meter_profile_delete,
1090 .create = mlx5_flow_meter_create,
1091 .destroy = mlx5_flow_meter_destroy,
1092 .meter_enable = mlx5_flow_meter_enable,
1093 .meter_disable = mlx5_flow_meter_disable,
1094 .meter_profile_update = mlx5_flow_meter_profile_update,
1095 .meter_dscp_table_update = NULL,
1096 .policer_actions_update = NULL,
1097 .stats_update = mlx5_flow_meter_stats_update,
1098 .stats_read = mlx5_flow_meter_stats_read,
1102 * Get meter operations.
1105 * Pointer to Ethernet device structure.
1107 * Pointer to set the mtr operations.
1113 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
1115 *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
1123 * Pointer to mlx5_priv.
1128 * Pointer to the profile found on success, NULL otherwise.
1130 struct mlx5_flow_meter *
1131 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
1133 struct mlx5_flow_meters *fms = &priv->flow_meters;
1134 struct mlx5_flow_meter *fm;
1136 TAILQ_FOREACH(fm, fms, next)
1137 if (meter_id == fm->meter_id)
1143 * Attach meter to flow.
1144 * Unidirectional Meter creation can only be done
1145 * when flow direction is known, i.e. when calling meter_attach.
1148 * Pointer to mlx5 private data.
1149 * @param [in] meter_id
1152 * Pointer to flow attributes.
1153 * @param [out] error
1154 * Pointer to error structure.
1156 * @return the flow meter pointer, NULL otherwise.
1158 struct mlx5_flow_meter *
1159 mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,
1160 const struct rte_flow_attr *attr,
1161 struct rte_flow_error *error)
1163 struct mlx5_flow_meter *fm;
1165 fm = mlx5_flow_meter_find(priv, meter_id);
1167 rte_flow_error_set(error, ENOENT,
1168 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1169 "Meter object id not valid");
1172 if (!fm->shared && fm->ref_cnt) {
1173 DRV_LOG(ERR, "Cannot share a non-shared meter.");
1174 rte_flow_error_set(error, EINVAL,
1175 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1176 "Meter can't be shared");
1179 if (!fm->ref_cnt++) {
1180 RTE_ASSERT(!fm->mfts->meter_action);
1182 /* This also creates the meter object. */
1183 fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
1185 if (!fm->mfts->meter_action)
1188 RTE_ASSERT(fm->mfts->meter_action);
1189 if (attr->transfer != fm->attr.transfer ||
1190 attr->ingress != fm->attr.ingress ||
1191 attr->egress != fm->attr.egress) {
1192 DRV_LOG(ERR, "meter I/O attributes do not "
1193 "match flow I/O attributes.");
1199 mlx5_flow_meter_detach(fm);
1200 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1201 fm->mfts->meter_action ? "Meter attr not match" :
1202 "Meter action create failed");
1208 * Detach meter from flow.
1211 * Pointer to flow meter.
1214 mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
1216 const struct rte_flow_attr attr = { 0 };
1218 RTE_ASSERT(fm->ref_cnt);
1221 if (fm->mfts->meter_action)
1222 mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
1223 fm->mfts->meter_action = NULL;
1228 * Flush meter configuration.
1231 * Pointer to Ethernet device.
1233 * Pointer to rte meter error structure.
1236 * 0 on success, a negative errno value otherwise and rte_errno is set.
1239 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
1241 struct mlx5_priv *priv = dev->data->dev_private;
1242 struct mlx5_flow_meters *fms = &priv->flow_meters;
1243 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
1244 struct mlx5_flow_meter_profile *fmp;
1245 struct mlx5_flow_meter *fm;
1246 const struct rte_flow_attr attr = {
1249 .transfer = priv->config.dv_esw_en ? 1 : 0,
1254 TAILQ_FOREACH_SAFE(fm, fms, next, tmp) {
1255 /* Meter object must not have any owner. */
1256 RTE_ASSERT(!fm->ref_cnt);
1257 /* Get meter profile. */
1260 return -rte_mtr_error_set(error, EINVAL,
1261 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1262 NULL, "MTR object meter profile invalid.");
1263 /* Update dependencies. */
1265 /* Remove from list. */
1266 TAILQ_REMOVE(fms, fm, next);
1267 /* Free policer counters. */
1268 for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
1269 if (fm->policer_stats.cnt[i])
1270 mlx5_counter_free(dev,
1271 fm->policer_stats.cnt[i]);
1272 /* Free meter flow table. */
1273 mlx5_flow_destroy_policer_rules(dev, fm, &attr);
1274 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
1277 TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
1279 RTE_ASSERT(!fmp->ref_cnt);
1280 /* Remove from list. */
1281 TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);