net/mlx5: add meter attach and detach
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_meter.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright 2018 Mellanox Technologies, Ltd
4  */
5 #include <math.h>
6
7 #include <rte_malloc.h>
8 #include <rte_mtr.h>
9 #include <rte_mtr_driver.h>
10
11 #include "mlx5.h"
12 #include "mlx5_flow.h"
13
14 /**
15  * Create the meter action.
16  *
17  * @param priv
18  *   Pointer to mlx5_priv.
19  * @param[in] fm
20  *   Pointer to flow meter to be converted.
21  *
22  * @return
23  *   Pointer to the meter action on success, NULL otherwise.
24  */
25 static void *
26 mlx5_flow_meter_action_create(struct mlx5_priv *priv,
27                               struct mlx5_flow_meter *fm)
28 {
29 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
30         struct mlx5dv_dr_flow_meter_attr mtr_init;
31         void *attr = fm->mfts->fmp;
32         struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
33                                                      &fm->profile->srtcm_prm;
34
35         fm->mfts->fmp_size = MLX5_ST_SZ_BYTES(flow_meter_parameters);
36         memset(attr, 0, fm->mfts->fmp_size);
37         MLX5_SET(flow_meter_parameters, attr, valid, 1);
38         MLX5_SET(flow_meter_parameters, attr, bucket_overflow, 1);
39         MLX5_SET(flow_meter_parameters, attr,
40                  start_color, MLX5_FLOW_COLOR_GREEN);
41         MLX5_SET(flow_meter_parameters, attr, both_buckets_on_green, 0);
42         MLX5_SET(flow_meter_parameters,
43                  attr, cbs_exponent, srtcm->cbs_exponent);
44         MLX5_SET(flow_meter_parameters,
45                  attr, cbs_mantissa, srtcm->cbs_mantissa);
46         MLX5_SET(flow_meter_parameters,
47                  attr, cir_exponent, srtcm->cir_exponent);
48         MLX5_SET(flow_meter_parameters,
49                  attr, cir_mantissa, srtcm->cir_mantissa);
50         MLX5_SET(flow_meter_parameters,
51                  attr, ebs_exponent, srtcm->ebs_exponent);
52         MLX5_SET(flow_meter_parameters,
53                  attr, ebs_mantissa, srtcm->ebs_mantissa);
54         mtr_init.next_table =
55                 fm->attr.transfer ? fm->mfts->transfer.tbl->obj :
56                     fm->attr.egress ? fm->mfts->egress.tbl->obj :
57                                        fm->mfts->ingress.tbl->obj;
58         mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
59         mtr_init.flow_meter_parameter = fm->mfts->fmp;
60         mtr_init.flow_meter_parameter_sz = fm->mfts->fmp_size;
61         mtr_init.active = fm->active_state;
62         return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
63 #else
64         (void)priv;
65         (void)fm;
66         return NULL;
67 #endif
68 }
69
70 /**
71  * Find meter profile by id.
72  *
73  * @param priv
74  *   Pointer to mlx5_priv.
75  * @param meter_profile_id
76  *   Meter profile id.
77  *
78  * @return
79  *   Pointer to the profile found on success, NULL otherwise.
80  */
81 static struct mlx5_flow_meter_profile *
82 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
83 {
84         struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
85         struct mlx5_flow_meter_profile *fmp;
86
87         TAILQ_FOREACH(fmp, fmps, next)
88                 if (meter_profile_id == fmp->meter_profile_id)
89                         return fmp;
90         return NULL;
91 }
92
93 /**
94  * Validate the MTR profile.
95  *
96  * @param[in] dev
97  *   Pointer to Ethernet device.
98  * @param[in] meter_profile_id
99  *   Meter profile id.
100  * @param[in] profile
101  *   Pointer to meter profile detail.
102  * @param[out] error
103  *   Pointer to the error structure.
104  *
105  * @return
106  *   0 on success, a negative errno value otherwise and rte_errno is set.
107  */
108 static int
109 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
110                                  uint32_t meter_profile_id,
111                                  struct rte_mtr_meter_profile *profile,
112                                  struct rte_mtr_error *error)
113 {
114         struct mlx5_priv *priv = dev->data->dev_private;
115         struct mlx5_flow_meter_profile *fmp;
116
117         /* Profile must not be NULL. */
118         if (profile == NULL)
119                 return -rte_mtr_error_set(error, EINVAL,
120                                           RTE_MTR_ERROR_TYPE_METER_PROFILE,
121                                           NULL, "Meter profile is null.");
122         /* Meter profile ID must be valid. */
123         if (meter_profile_id == UINT32_MAX)
124                 return -rte_mtr_error_set(error, EINVAL,
125                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
126                                           NULL, "Meter profile id not valid.");
127         /* Meter profile must not exist. */
128         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
129         if (fmp)
130                 return -rte_mtr_error_set(error, EEXIST,
131                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
132                                           NULL,
133                                           "Meter profile already exists.");
134         if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
135                 if (priv->config.hca_attr.qos.srtcm_sup) {
136                         /* Verify support for flow meter parameters. */
137                         if (profile->srtcm_rfc2697.cir > 0 &&
138                             profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
139                             profile->srtcm_rfc2697.cbs > 0 &&
140                             profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
141                             profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
142                                 return 0;
143                         else
144                                 return -rte_mtr_error_set
145                                              (error, ENOTSUP,
146                                               RTE_MTR_ERROR_TYPE_MTR_PARAMS,
147                                               NULL,
148                                               profile->srtcm_rfc2697.ebs ?
149                                               "Metering value ebs must be 0." :
150                                               "Invalid metering parameters.");
151                 }
152         }
153         return -rte_mtr_error_set(error, ENOTSUP,
154                                   RTE_MTR_ERROR_TYPE_METER_PROFILE,
155                                   NULL, "Metering algorithm not supported.");
156 }
157
158 /**
159  * Calculate mantissa and exponent for cir.
160  *
161  * @param[in] cir
162  *   Value to be calculated.
163  * @param[out] man
164  *   Pointer to the mantissa.
165  * @param[out] exp
166  *   Pointer to the exp.
167  */
168 static void
169 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
170 {
171         int64_t _cir;
172         int64_t delta = INT64_MAX;
173         uint8_t _man = 0;
174         uint8_t _exp = 0;
175         uint64_t m, e;
176
177         for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
178                 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
179                         _cir = (1000000000ULL * m) >> e;
180                         if (llabs(cir - _cir) <= delta) {
181                                 delta = llabs(cir - _cir);
182                                 _man = m;
183                                 _exp = e;
184                         }
185                 }
186         }
187         *man = _man;
188         *exp = _exp;
189 }
190
191 /**
192  * Calculate mantissa and exponent for xbs.
193  *
194  * @param[in] xbs
195  *   Value to be calculated.
196  * @param[out] man
197  *   Pointer to the mantissa.
198  * @param[out] exp
199  *   Pointer to the exp.
200  */
201 static void
202 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
203 {
204         int _exp;
205         double _man;
206
207         /* Special case xbs == 0 ? both exp and matissa are 0. */
208         if (xbs == 0) {
209                 *man = 0;
210                 *exp = 0;
211                 return;
212         }
213         /* xbs = xbs_mantissa * 2^xbs_exponent */
214         _man = frexp(xbs, &_exp);
215         _man = _man * pow(2, MLX5_MAN_WIDTH);
216         _exp = _exp - MLX5_MAN_WIDTH;
217         *man = (uint8_t)ceil(_man);
218         *exp = _exp;
219 }
220
221 /**
222  * Fill the prm meter parameter.
223  *
224  * @param[in,out] fmp
225  *   Pointer to meter profie to be converted.
226  * @param[out] error
227  *   Pointer to the error structure.
228  *
229  * @return
230  *   0 on success, a negative errno value otherwise and rte_errno is set.
231  */
232 static int
233 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
234                           struct rte_mtr_error *error)
235 {
236         struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
237         uint8_t man, exp;
238
239         if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
240                 return -rte_mtr_error_set(error, ENOTSUP,
241                                 RTE_MTR_ERROR_TYPE_METER_PROFILE,
242                                 NULL, "Metering algorithm not supported.");
243          /* cbs = cbs_mantissa * 2^cbs_exponent */
244         mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
245                                     &man, &exp);
246         srtcm->cbs_mantissa = man;
247         srtcm->cbs_exponent = exp;
248         /* Check if cbs mantissa is too large. */
249         if (srtcm->cbs_exponent != exp)
250                 return -rte_mtr_error_set(error, EINVAL,
251                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
252                                           "Metering profile parameter cbs is"
253                                           " invalid.");
254         /* ebs = ebs_mantissa * 2^ebs_exponent */
255         mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
256                                     &man, &exp);
257         srtcm->ebs_mantissa = man;
258         srtcm->ebs_exponent = exp;
259         /* Check if ebs mantissa is too large. */
260         if (srtcm->ebs_exponent != exp)
261                 return -rte_mtr_error_set(error, EINVAL,
262                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
263                                           "Metering profile parameter ebs is"
264                                           " invalid.");
265         /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
266         mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
267                                     &man, &exp);
268         srtcm->cir_mantissa = man;
269         srtcm->cir_exponent = exp;
270         /* Check if cir mantissa is too large. */
271         if (srtcm->cir_exponent != exp)
272                 return -rte_mtr_error_set(error, EINVAL,
273                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
274                                           "Metering profile parameter cir is"
275                                           " invalid.");
276         return 0;
277 }
278
279 /**
280  * Callback to get MTR capabilities.
281  *
282  * @param[in] dev
283  *   Pointer to Ethernet device.
284  * @param[out] cap
285  *   Pointer to save MTR capabilities.
286  * @param[out] error
287  *   Pointer to the error structure.
288  *
289  * @return
290  *   0 on success, a negative errno value otherwise and rte_errno is set.
291  */
292 static int
293 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
294                  struct rte_mtr_capabilities *cap,
295                  struct rte_mtr_error *error __rte_unused)
296 {
297         struct mlx5_priv *priv = dev->data->dev_private;
298         struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
299
300         if (!priv->mtr_en)
301                 return -rte_mtr_error_set(error, ENOTSUP,
302                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
303                                           "Meter is not support");
304         memset(cap, 0, sizeof(*cap));
305         cap->n_max = 1 << qattr->log_max_flow_meter;
306         cap->n_shared_max = cap->n_max;
307         cap->identical = 1;
308         cap->shared_identical = 1;
309         cap->shared_n_flows_per_mtr_max = 4 << 20;
310         /* 2M flows can share the same meter. */
311         cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
312         cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0;
313         cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
314         cap->policer_action_drop_supported = 1;
315         cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
316                           RTE_MTR_STATS_N_PKTS_DROPPED;
317         return 0;
318 }
319
320 /**
321  * Callback to add MTR profile.
322  *
323  * @param[in] dev
324  *   Pointer to Ethernet device.
325  * @param[in] meter_profile_id
326  *   Meter profile id.
327  * @param[in] profile
328  *   Pointer to meter profile detail.
329  * @param[out] error
330  *   Pointer to the error structure.
331  *
332  * @return
333  *   0 on success, a negative errno value otherwise and rte_errno is set.
334  */
335 static int
336 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
337                        uint32_t meter_profile_id,
338                        struct rte_mtr_meter_profile *profile,
339                        struct rte_mtr_error *error)
340 {
341         struct mlx5_priv *priv = dev->data->dev_private;
342         struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
343         struct mlx5_flow_meter_profile *fmp;
344         int ret;
345
346         if (!priv->mtr_en)
347                 return -rte_mtr_error_set(error, ENOTSUP,
348                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
349                                           "Meter is not support");
350         /* Check input params. */
351         ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
352                                                profile, error);
353         if (ret)
354                 return ret;
355         /* Meter profile memory allocation. */
356         fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
357                          RTE_CACHE_LINE_SIZE);
358         if (fmp == NULL)
359                 return -rte_mtr_error_set(error, ENOMEM,
360                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
361                                           NULL, "Meter profile memory "
362                                           "alloc failed.");
363         /* Fill profile info. */
364         fmp->meter_profile_id = meter_profile_id;
365         fmp->profile = *profile;
366         /* Fill the flow meter parameters for the PRM. */
367         ret = mlx5_flow_meter_param_fill(fmp, error);
368         if (ret)
369                 goto error;
370         /* Add to list. */
371         TAILQ_INSERT_TAIL(fmps, fmp, next);
372         return 0;
373 error:
374         rte_free(fmp);
375         return ret;
376 }
377
378 /**
379  * Callback to delete MTR profile.
380  *
381  * @param[in] dev
382  *   Pointer to Ethernet device.
383  * @param[in] meter_profile_id
384  *   Meter profile id.
385  * @param[out] error
386  *   Pointer to the error structure.
387  *
388  * @return
389  *   0 on success, a negative errno value otherwise and rte_errno is set.
390  */
391 static int
392 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
393                           uint32_t meter_profile_id,
394                           struct rte_mtr_error *error)
395 {
396         struct mlx5_priv *priv = dev->data->dev_private;
397         struct mlx5_flow_meter_profile *fmp;
398
399         if (!priv->mtr_en)
400                 return -rte_mtr_error_set(error, ENOTSUP,
401                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
402                                           "Meter is not support");
403         /* Meter profile must exist. */
404         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
405         if (fmp == NULL)
406                 return -rte_mtr_error_set(error, ENOENT,
407                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
408                                           &meter_profile_id,
409                                           "Meter profile id invalid.");
410         /* Check profile is unused. */
411         if (fmp->ref_cnt)
412                 return -rte_mtr_error_set(error, EBUSY,
413                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
414                                           NULL, "Meter profile in use.");
415         /* Remove from list. */
416         TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
417         rte_free(fmp);
418         return 0;
419 }
420
421 /**
422  * Convert wrong color setting action to verbose error.
423  *
424  * @param[in] action
425  *   Policy color action.
426  *
427  * @return
428  *   Verbose meter color error type.
429  */
430 static inline enum rte_mtr_error_type
431 action2error(enum rte_mtr_policer_action action)
432 {
433         switch (action) {
434         case MTR_POLICER_ACTION_COLOR_GREEN:
435                 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN;
436         case MTR_POLICER_ACTION_COLOR_YELLOW:
437                 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW;
438         case MTR_POLICER_ACTION_COLOR_RED:
439                 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED;
440         default:
441                 break;
442         }
443         return RTE_MTR_ERROR_TYPE_UNSPECIFIED;
444 }
445
446 /**
447  * Check meter validation.
448  *
449  * @param[in] priv
450  *   Pointer to mlx5 private data structure.
451  * @param[in] meter_id
452  *   Meter id.
453  * @param[in] params
454  *   Pointer to rte meter parameters.
455  * @param[out] error
456  *   Pointer to rte meter error structure.
457  *
458  * @return
459  *   0 on success, a negative errno value otherwise and rte_errno is set.
460  */
461 static int
462 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
463                          struct rte_mtr_params *params,
464                          struct rte_mtr_error *error)
465 {
466         static enum rte_mtr_policer_action
467                                 valid_recol_action[RTE_COLORS] = {
468                                                MTR_POLICER_ACTION_COLOR_GREEN,
469                                                MTR_POLICER_ACTION_COLOR_YELLOW,
470                                                MTR_POLICER_ACTION_COLOR_RED };
471         int i;
472
473         /* Meter params must not be NULL. */
474         if (params == NULL)
475                 return -rte_mtr_error_set(error, EINVAL,
476                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
477                                           NULL, "Meter object params null.");
478         /* Previous meter color is not supported. */
479         if (params->use_prev_mtr_color)
480                 return -rte_mtr_error_set(error, ENOTSUP,
481                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
482                                           NULL,
483                                           "Previous meter color "
484                                           "not supported.");
485         /* Validate policer settings. */
486         for (i = 0; i < RTE_COLORS; i++)
487                 if (params->action[i] != valid_recol_action[i] &&
488                     params->action[i] != MTR_POLICER_ACTION_DROP)
489                         return -rte_mtr_error_set
490                                         (error, ENOTSUP,
491                                          action2error(params->action[i]), NULL,
492                                          "Recolor action not supported.");
493         /* Validate meter id. */
494         if (mlx5_flow_meter_find(priv, meter_id))
495                 return -rte_mtr_error_set(error, EEXIST,
496                                           RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
497                                           "Meter object already exists.");
498         return 0;
499 }
500
501 /**
502  * Modify the flow meter action.
503  *
504  * @param[in] priv
505  *   Pointer to mlx5 private data structure.
506  * @param[in] fm
507  *   Pointer to flow meter to be modified.
508  * @param[in] srtcm
509  *   Pointer to meter srtcm description parameter.
510  * @param[in] modify_bits
511  *   The bit in srtcm to be updated.
512  * @param[in] active_state
513  *   The state to be updated.
514  * @return
515  *   0 on success, o negative value otherwise.
516  */
517 static int
518 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
519                 struct mlx5_flow_meter *fm,
520                 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
521                 uint64_t modify_bits, uint32_t active_state)
522 {
523 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
524         uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
525         uint32_t *attr;
526         struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
527         int ret;
528
529         /* Fill command parameters. */
530         mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
531         mod_attr.flow_meter_parameter = in;
532         mod_attr.flow_meter_parameter_sz = fm->mfts->fmp_size;
533         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
534                 mod_attr.active = !!active_state;
535         else
536                 mod_attr.active = 0;
537         attr = in;
538         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
539                 MLX5_SET(flow_meter_parameters,
540                          attr, cbs_exponent, srtcm->cbs_exponent);
541                 MLX5_SET(flow_meter_parameters,
542                          attr, cbs_mantissa, srtcm->cbs_mantissa);
543         }
544         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
545                 MLX5_SET(flow_meter_parameters,
546                          attr, cir_exponent, srtcm->cir_exponent);
547                 MLX5_SET(flow_meter_parameters,
548                          attr, cir_mantissa, srtcm->cir_mantissa);
549         }
550         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
551                 MLX5_SET(flow_meter_parameters,
552                          attr, ebs_exponent, srtcm->ebs_exponent);
553                 MLX5_SET(flow_meter_parameters,
554                          attr, ebs_mantissa, srtcm->ebs_mantissa);
555         }
556         /* Apply modifications to meter only if it was created. */
557         if (fm->mfts->meter_action) {
558                 ret = mlx5_glue->dv_modify_flow_action_meter
559                                         (fm->mfts->meter_action, &mod_attr,
560                                         rte_cpu_to_be_64(modify_bits));
561                 if (ret)
562                         return ret;
563         }
564         /* Update succeedded modify meter parameters. */
565         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
566                 fm->active_state = !!active_state;
567         attr = fm->mfts->fmp;
568         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
569                 MLX5_SET(flow_meter_parameters,
570                          attr, cbs_exponent, srtcm->cbs_exponent);
571                 MLX5_SET(flow_meter_parameters,
572                          attr, cbs_mantissa, srtcm->cbs_mantissa);
573         }
574         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
575                 MLX5_SET(flow_meter_parameters,
576                          attr, cir_exponent, srtcm->cir_exponent);
577                 MLX5_SET(flow_meter_parameters,
578                          attr, cir_mantissa, srtcm->cir_mantissa);
579         }
580         if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
581                 MLX5_SET(flow_meter_parameters,
582                          attr, ebs_exponent, srtcm->ebs_exponent);
583                 MLX5_SET(flow_meter_parameters,
584                          attr, ebs_mantissa, srtcm->ebs_mantissa);
585         }
586
587         return 0;
588 #else
589         (void)priv;
590         (void)fm;
591         (void)srtcm;
592         (void)modify_bits;
593         (void)active_state;
594         return -ENOTSUP;
595 #endif
596 }
597
598 /**
599  * Create meter rules.
600  *
601  * @param[in] dev
602  *   Pointer to Ethernet device.
603  * @param[in] meter_id
604  *   Meter id.
605  * @param[in] params
606  *   Pointer to rte meter parameters.
607  * @param[in] shared
608  *   Meter shared with other flow or not.
609  * @param[out] error
610  *   Pointer to rte meter error structure.
611  *
612  * @return
613  *   0 on success, a negative errno value otherwise and rte_errno is set.
614  */
615 static int
616 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
617                        struct rte_mtr_params *params, int shared,
618                        struct rte_mtr_error *error)
619 {
620         struct mlx5_priv *priv = dev->data->dev_private;
621         struct mlx5_flow_meters *fms = &priv->flow_meters;
622         struct mlx5_flow_meter_profile *fmp;
623         struct mlx5_flow_meter *fm;
624         const struct rte_flow_attr attr = {
625                                 .ingress = 1,
626                                 .egress = 1,
627                                 .transfer = priv->config.dv_esw_en ? 1 : 0,
628                         };
629         int ret;
630         unsigned int i;
631
632         if (!priv->mtr_en)
633                 return -rte_mtr_error_set(error, ENOTSUP,
634                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
635                                           "Meter is not support");
636         /* Validate the parameters. */
637         ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
638         if (ret)
639                 return ret;
640         /* Meter profile must exist. */
641         fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
642         if (fmp == NULL)
643                 return -rte_mtr_error_set(error, ENOENT,
644                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
645                                           NULL, "Meter profile id not valid.");
646         /* Allocate the flow meter memory. */
647         fm = rte_calloc(__func__, 1,
648                         sizeof(struct mlx5_flow_meter), RTE_CACHE_LINE_SIZE);
649         if (fm == NULL)
650                 return -rte_mtr_error_set(error, ENOMEM,
651                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
652                                           "Memory alloc failed for meter.");
653         /* Fill the flow meter parameters. */
654         fm->meter_id = meter_id;
655         fm->profile = fmp;
656         fm->params = *params;
657         /* Alloc policer counters. */
658         for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) {
659                 fm->policer_stats.cnt[i] = mlx5_counter_alloc(dev);
660                 if (!fm->policer_stats.cnt[i])
661                         goto error;
662         }
663         fm->mfts = mlx5_flow_create_mtr_tbls(dev, fm);
664         if (!fm->mfts)
665                 goto error;
666         ret = mlx5_flow_create_policer_rules(dev, fm, &attr);
667         if (ret)
668                 goto error;
669         /* Add to the flow meter list. */
670         TAILQ_INSERT_TAIL(fms, fm, next);
671         fm->active_state = 1; /* Config meter starts as active. */
672         fm->shared = !!shared;
673         fm->policer_stats.stats_mask = params->stats_mask;
674         fm->profile->ref_cnt++;
675         return 0;
676 error:
677         mlx5_flow_destroy_policer_rules(dev, fm, &attr);
678         mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
679         /* Free policer counters. */
680         for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
681                 if (fm->policer_stats.cnt[i])
682                         mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
683         rte_free(fm);
684         return -rte_mtr_error_set(error, -ret,
685                                   RTE_MTR_ERROR_TYPE_UNSPECIFIED,
686                                   NULL, "Failed to create devx meter.");
687 }
688
689 /**
690  * Destroy meter rules.
691  *
692  * @param[in] dev
693  *   Pointer to Ethernet device.
694  * @param[in] meter_id
695  *   Meter id.
696  * @param[out] error
697  *   Pointer to rte meter error structure.
698  *
699  * @return
700  *   0 on success, a negative errno value otherwise and rte_errno is set.
701  */
702 static int
703 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
704                         struct rte_mtr_error *error)
705 {
706         struct mlx5_priv *priv = dev->data->dev_private;
707         struct mlx5_flow_meters *fms = &priv->flow_meters;
708         struct mlx5_flow_meter_profile *fmp;
709         struct mlx5_flow_meter *fm;
710         const struct rte_flow_attr attr = {
711                                 .ingress = 1,
712                                 .egress = 1,
713                                 .transfer = priv->config.dv_esw_en ? 1 : 0,
714                         };
715         unsigned int i;
716
717         if (!priv->mtr_en)
718                 return -rte_mtr_error_set(error, ENOTSUP,
719                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
720                                           "Meter is not support");
721         /* Meter object must exist. */
722         fm = mlx5_flow_meter_find(priv, meter_id);
723         if (fm == NULL)
724                 return -rte_mtr_error_set(error, ENOENT,
725                                           RTE_MTR_ERROR_TYPE_MTR_ID,
726                                           NULL, "Meter object id not valid.");
727         /* Meter object must not have any owner. */
728         if (fm->ref_cnt > 0)
729                 return -rte_mtr_error_set(error, EBUSY,
730                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
731                                           NULL, "Meter object is being used.");
732         /* Get the meter profile. */
733         fmp = fm->profile;
734         RTE_ASSERT(fmp);
735         /* Update dependencies. */
736         fmp->ref_cnt--;
737         /* Remove from the flow meter list. */
738         TAILQ_REMOVE(fms, fm, next);
739         /* Free policer counters. */
740         for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
741                 if (fm->policer_stats.cnt[i])
742                         mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
743         /* Free meter flow table */
744         mlx5_flow_destroy_policer_rules(dev, fm, &attr);
745         mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
746         rte_free(fm);
747         return 0;
748 }
749
750 /**
751  * Modify meter state.
752  *
753  * @param[in] priv
754  *   Pointer to mlx5 private data structure.
755  * @param[in] fm
756  *   Pointer to flow meter.
757  * @param[in] new_state
758  *   New state to update.
759  * @param[out] error
760  *   Pointer to rte meter error structure.
761  *
762  * @return
763  *   0 on success, a negative errno value otherwise and rte_errno is set.
764  */
765 static int
766 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
767                              struct mlx5_flow_meter *fm,
768                              uint32_t new_state,
769                              struct rte_mtr_error *error)
770 {
771         static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
772                 .cbs_exponent = 20,
773                 .cbs_mantissa = 191,
774                 .cir_exponent = 0,
775                 .cir_mantissa = 200,
776                 .ebs_exponent = 0,
777                 .ebs_mantissa = 0,
778         };
779         uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
780                                MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
781         int ret;
782
783         if (new_state == MLX5_FLOW_METER_DISABLE)
784                 ret = mlx5_flow_meter_action_modify(priv, fm, &srtcm,
785                                                     modify_bits, 0);
786         else
787                 ret = mlx5_flow_meter_action_modify(priv, fm,
788                                                    &fm->profile->srtcm_prm,
789                                                     modify_bits, 0);
790         if (ret)
791                 return -rte_mtr_error_set(error, -ret,
792                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
793                                           NULL,
794                                           new_state ?
795                                           "Failed to enable meter." :
796                                           "Failed to disable meter.");
797         return 0;
798 }
799
800 /**
801  * Callback to enable flow meter.
802  *
803  * @param[in] dev
804  *   Pointer to Ethernet device.
805  * @param[in] meter_id
806  *   Meter id.
807  * @param[out] error
808  *   Pointer to rte meter error structure.
809  *
810  * @return
811  *   0 on success, a negative errno value otherwise and rte_errno is set.
812  */
813 static int
814 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
815                        uint32_t meter_id,
816                        struct rte_mtr_error *error)
817 {
818         struct mlx5_priv *priv = dev->data->dev_private;
819         struct mlx5_flow_meter *fm;
820         int ret;
821
822         if (!priv->mtr_en)
823                 return -rte_mtr_error_set(error, ENOTSUP,
824                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
825                                           "Meter is not support");
826         /* Meter object must exist. */
827         fm = mlx5_flow_meter_find(priv, meter_id);
828         if (fm == NULL)
829                 return -rte_mtr_error_set(error, ENOENT,
830                                           RTE_MTR_ERROR_TYPE_MTR_ID,
831                                           NULL, "Meter not found.");
832         if (fm->active_state == MLX5_FLOW_METER_ENABLE)
833                 return 0;
834         ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
835                                            error);
836         if (!ret)
837                 fm->active_state = MLX5_FLOW_METER_ENABLE;
838         return ret;
839 }
840
841 /**
842  * Callback to disable flow meter.
843  *
844  * @param[in] dev
845  *   Pointer to Ethernet device.
846  * @param[in] meter_id
847  *   Meter id.
848  * @param[out] error
849  *   Pointer to rte meter error structure.
850  *
851  * @return
852  *   0 on success, a negative errno value otherwise and rte_errno is set.
853  */
854 static int
855 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
856                         uint32_t meter_id,
857                         struct rte_mtr_error *error)
858 {
859         struct mlx5_priv *priv = dev->data->dev_private;
860         struct mlx5_flow_meter *fm;
861         int ret;
862
863         if (!priv->mtr_en)
864                 return -rte_mtr_error_set(error, ENOTSUP,
865                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
866                                           "Meter is not support");
867         /* Meter object must exist. */
868         fm = mlx5_flow_meter_find(priv, meter_id);
869         if (fm == NULL)
870                 return -rte_mtr_error_set(error, ENOENT,
871                                           RTE_MTR_ERROR_TYPE_MTR_ID,
872                                           NULL, "Meter not found.");
873         if (fm->active_state == MLX5_FLOW_METER_DISABLE)
874                 return 0;
875         ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
876                                            error);
877         if (!ret)
878                 fm->active_state = MLX5_FLOW_METER_DISABLE;
879         return ret;
880 }
881
882 /**
883  * Callback to update meter profile.
884  *
885  * @param[in] dev
886  *   Pointer to Ethernet device.
887  * @param[in] meter_id
888  *   Meter id.
889  * @param[in] meter_profile_id
890  *   To be updated meter profile id.
891  * @param[out] error
892  *   Pointer to rte meter error structure.
893  *
894  * @return
895  *   0 on success, a negative errno value otherwise and rte_errno is set.
896  */
897 static int
898 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
899                                uint32_t meter_id,
900                                uint32_t meter_profile_id,
901                                struct rte_mtr_error *error)
902 {
903         struct mlx5_priv *priv = dev->data->dev_private;
904         struct mlx5_flow_meter_profile *fmp;
905         struct mlx5_flow_meter_profile *old_fmp;
906         struct mlx5_flow_meter *fm;
907         uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
908                                MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
909         int ret;
910
911         if (!priv->mtr_en)
912                 return -rte_mtr_error_set(error, ENOTSUP,
913                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
914                                           "Meter is not support");
915         /* Meter profile must exist. */
916         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
917         if (fmp == NULL)
918                 return -rte_mtr_error_set(error, ENOENT,
919                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
920                                           NULL, "Meter profile not found.");
921         /* Meter object must exist. */
922         fm = mlx5_flow_meter_find(priv, meter_id);
923         if (fm == NULL)
924                 return -rte_mtr_error_set(error, ENOENT,
925                                           RTE_MTR_ERROR_TYPE_MTR_ID,
926                                           NULL, "Meter not found.");
927         /* MTR object already set to meter profile id. */
928         old_fmp = fm->profile;
929         if (fmp == old_fmp)
930                 return 0;
931         /* Update the profile. */
932         fm->profile = fmp;
933         /* Update meter params in HW (if not disabled). */
934         if (fm->active_state == MLX5_FLOW_METER_DISABLE)
935                 return 0;
936         ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
937                                               modify_bits, fm->active_state);
938         if (ret) {
939                 fm->profile = old_fmp;
940                 return -rte_mtr_error_set(error, -ret,
941                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
942                                           NULL, "Failed to update meter"
943                                           " parmeters in hardware.");
944         }
945         old_fmp->ref_cnt--;
946         fmp->ref_cnt++;
947         return 0;
948 }
949
950 /**
951  * Callback to update meter stats mask.
952  *
953  * @param[in] dev
954  *   Pointer to Ethernet device.
955  * @param[in] meter_id
956  *   Meter id.
957  * @param[in] stats_mask
958  *   To be updated stats_mask.
959  * @param[out] error
960  *   Pointer to rte meter error structure.
961  *
962  * @return
963  *   0 on success, a negative errno value otherwise and rte_errno is set.
964  */
965 static int
966 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
967                              uint32_t meter_id,
968                              uint64_t stats_mask,
969                              struct rte_mtr_error *error)
970 {
971         struct mlx5_priv *priv = dev->data->dev_private;
972         struct mlx5_flow_meter *fm;
973
974         if (!priv->mtr_en)
975                 return -rte_mtr_error_set(error, ENOTSUP,
976                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
977                                           "Meter is not support");
978         /* Meter object must exist. */
979         fm = mlx5_flow_meter_find(priv, meter_id);
980         if (fm == NULL)
981                 return -rte_mtr_error_set(error, ENOENT,
982                                           RTE_MTR_ERROR_TYPE_MTR_ID,
983                                           NULL, "Meter object id not valid.");
984         fm->policer_stats.stats_mask = stats_mask;
985         return 0;
986 }
987
988 /**
989  * Callback to read meter statistics.
990  *
991  * @param[in] dev
992  *   Pointer to Ethernet device.
993  * @param[in] meter_id
994  *   Meter id.
995  * @param[out] stats
996  *   Pointer to store the statistics.
997  * @param[out] stats_mask
998  *   Pointer to store the stats_mask.
999  * @param[in] clear
1000  *   Statistic to be cleared after read or not.
1001  * @param[out] error
1002  *   Pointer to rte meter error structure.
1003  *
1004  * @return
1005  *   0 on success, a negative errno value otherwise and rte_errno is set.
1006  */
1007 static int
1008 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
1009                            uint32_t meter_id,
1010                            struct rte_mtr_stats *stats,
1011                            uint64_t *stats_mask,
1012                            int clear,
1013                            struct rte_mtr_error *error)
1014 {
1015         static uint64_t meter2mask[RTE_MTR_DROPPED + 1] = {
1016                 RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_BYTES_GREEN,
1017                 RTE_MTR_STATS_N_PKTS_YELLOW | RTE_MTR_STATS_N_BYTES_YELLOW,
1018                 RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED,
1019                 RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED
1020         };
1021         struct mlx5_priv *priv = dev->data->dev_private;
1022         struct mlx5_flow_meter *fm;
1023         struct mlx5_flow_policer_stats *ps;
1024         uint64_t pkts_dropped = 0;
1025         uint64_t bytes_dropped = 0;
1026         uint64_t pkts;
1027         uint64_t bytes;
1028         int i;
1029         int ret = 0;
1030
1031         if (!priv->mtr_en)
1032                 return -rte_mtr_error_set(error, ENOTSUP,
1033                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1034                                           "Meter is not support");
1035         /* Meter object must exist. */
1036         fm = mlx5_flow_meter_find(priv, meter_id);
1037         if (fm == NULL)
1038                 return -rte_mtr_error_set(error, ENOENT,
1039                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1040                                           NULL, "Meter object id not valid.");
1041         ps = &fm->policer_stats;
1042         *stats_mask = ps->stats_mask;
1043         for (i = 0; i < RTE_MTR_DROPPED; i++) {
1044                 if (*stats_mask & meter2mask[i]) {
1045                         ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
1046                                                  &bytes);
1047                         if (ret)
1048                                 goto error;
1049                         if (fm->params.action[i] == MTR_POLICER_ACTION_DROP) {
1050                                 pkts_dropped += pkts;
1051                                 bytes_dropped += bytes;
1052                         }
1053                         /* If need to read the packets, set it. */
1054                         if ((1 << i) & (*stats_mask & meter2mask[i]))
1055                                 stats->n_pkts[i] = pkts;
1056                         /* If need to read the bytes, set it. */
1057                         if ((1 << (RTE_MTR_DROPPED + 1 + i)) &
1058                            (*stats_mask & meter2mask[i]))
1059                                 stats->n_bytes[i] = bytes;
1060                 }
1061         }
1062         /* Dropped packets/bytes are treated differently. */
1063         if (*stats_mask & meter2mask[i]) {
1064                 ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
1065                                          &bytes);
1066                 if (ret)
1067                         goto error;
1068                 pkts += pkts_dropped;
1069                 bytes += bytes_dropped;
1070                 /* If need to read the packets, set it. */
1071                 if ((*stats_mask & meter2mask[i]) &
1072                    RTE_MTR_STATS_N_PKTS_DROPPED)
1073                         stats->n_pkts_dropped = pkts;
1074                 /* If need to read the bytes, set it. */
1075                 if ((*stats_mask & meter2mask[i]) &
1076                    RTE_MTR_STATS_N_BYTES_DROPPED)
1077                         stats->n_bytes_dropped = bytes;
1078         }
1079         return 0;
1080 error:
1081         return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
1082                                  "Failed to read policer counters.");
1083 }
1084
1085 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
1086         .capabilities_get = mlx5_flow_mtr_cap_get,
1087         .meter_profile_add = mlx5_flow_meter_profile_add,
1088         .meter_profile_delete = mlx5_flow_meter_profile_delete,
1089         .create = mlx5_flow_meter_create,
1090         .destroy = mlx5_flow_meter_destroy,
1091         .meter_enable = mlx5_flow_meter_enable,
1092         .meter_disable = mlx5_flow_meter_disable,
1093         .meter_profile_update = mlx5_flow_meter_profile_update,
1094         .meter_dscp_table_update = NULL,
1095         .policer_actions_update = NULL,
1096         .stats_update = mlx5_flow_meter_stats_update,
1097         .stats_read = mlx5_flow_meter_stats_read,
1098 };
1099
1100 /**
1101  * Get meter operations.
1102  *
1103  * @param dev
1104  *   Pointer to Ethernet device structure.
1105  * @param arg
1106  *   Pointer to set the mtr operations.
1107  *
1108  * @return
1109  *   Always 0.
1110  */
1111 int
1112 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
1113 {
1114         *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
1115         return 0;
1116 }
1117
1118 /**
1119  * Find meter by id.
1120  *
1121  * @param priv
1122  *   Pointer to mlx5_priv.
1123  * @param meter_id
1124  *   Meter id.
1125  *
1126  * @return
1127  *   Pointer to the profile found on success, NULL otherwise.
1128  */
1129 struct mlx5_flow_meter *
1130 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
1131 {
1132         struct mlx5_flow_meters *fms = &priv->flow_meters;
1133         struct mlx5_flow_meter *fm;
1134
1135         TAILQ_FOREACH(fm, fms, next)
1136                 if (meter_id == fm->meter_id)
1137                         return fm;
1138         return NULL;
1139 }
1140
1141 /**
1142  * Attach meter to flow.
1143  * Unidirectional Meter creation can only be done
1144  * when flow direction is known, i.e. when calling meter_attach.
1145  *
1146  * @param [in] priv
1147  *  Pointer to mlx5 private data.
1148  * @param [in] meter_id
1149  *  Flow meter id.
1150  * @param [in] attr
1151  *  Pointer to flow attributes.
1152  * @param [out] error
1153  *  Pointer to error structure.
1154  *
1155  * @return the flow meter pointer, NULL otherwise.
1156  */
1157 struct mlx5_flow_meter *
1158 mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,
1159                        const struct rte_flow_attr *attr,
1160                        struct rte_flow_error *error)
1161 {
1162         struct mlx5_flow_meter *fm;
1163
1164         fm = mlx5_flow_meter_find(priv, meter_id);
1165         if (fm == NULL) {
1166                 rte_flow_error_set(error, ENOENT,
1167                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1168                                    "Meter object id not valid");
1169                 goto error;
1170         }
1171         if (!fm->shared && fm->ref_cnt) {
1172                 DRV_LOG(ERR, "Cannot share a non-shared meter.");
1173                 rte_flow_error_set(error, EINVAL,
1174                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1175                                   "Meter can't be shared");
1176                 goto error;
1177         }
1178         if (!fm->ref_cnt++) {
1179                 RTE_ASSERT(!fm->mfts->meter_action);
1180                 fm->attr = *attr;
1181                 /* This also creates the meter object. */
1182                 fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
1183                                                                        fm);
1184                 if (!fm->mfts->meter_action)
1185                         goto error_detach;
1186         } else {
1187                 RTE_ASSERT(fm->mfts->meter_action);
1188                 if (attr->transfer != fm->attr.transfer ||
1189                     attr->ingress != fm->attr.ingress ||
1190                     attr->egress != fm->attr.egress) {
1191                         DRV_LOG(ERR, "meter I/O attributes do not "
1192                                 "match flow I/O attributes.");
1193                         goto error_detach;
1194                 }
1195         }
1196         return fm;
1197 error_detach:
1198         mlx5_flow_meter_detach(fm);
1199         rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1200                           fm->mfts->meter_action ? "Meter attr not match" :
1201                           "Meter action create failed");
1202 error:
1203         return NULL;
1204 }
1205
1206 /**
1207  * Detach meter from flow.
1208  *
1209  * @param [in] fm
1210  *  Pointer to flow meter.
1211  */
1212 void
1213 mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
1214 {
1215         const struct rte_flow_attr attr = { 0 };
1216
1217         RTE_ASSERT(fm->ref_cnt);
1218         if (--fm->ref_cnt)
1219                 return;
1220         if (fm->mfts->meter_action)
1221                 mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
1222         fm->mfts->meter_action = NULL;
1223         fm->attr = attr;
1224 }