76a3180e652e0679b8bed3692b9d85ca698710a8
[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  * Find meter profile by id.
16  *
17  * @param priv
18  *   Pointer to mlx5_priv.
19  * @param meter_profile_id
20  *   Meter profile id.
21  *
22  * @return
23  *   Pointer to the profile found on success, NULL otherwise.
24  */
25 static struct mlx5_flow_meter_profile *
26 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
27 {
28         struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
29         struct mlx5_flow_meter_profile *fmp;
30
31         TAILQ_FOREACH(fmp, fmps, next)
32                 if (meter_profile_id == fmp->meter_profile_id)
33                         return fmp;
34         return NULL;
35 }
36
37 /**
38  * Validate the MTR profile.
39  *
40  * @param[in] dev
41  *   Pointer to Ethernet device.
42  * @param[in] meter_profile_id
43  *   Meter profile id.
44  * @param[in] profile
45  *   Pointer to meter profile detail.
46  * @param[out] error
47  *   Pointer to the error structure.
48  *
49  * @return
50  *   0 on success, a negative errno value otherwise and rte_errno is set.
51  */
52 static int
53 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
54                                  uint32_t meter_profile_id,
55                                  struct rte_mtr_meter_profile *profile,
56                                  struct rte_mtr_error *error)
57 {
58         struct mlx5_priv *priv = dev->data->dev_private;
59         struct mlx5_flow_meter_profile *fmp;
60
61         /* Profile must not be NULL. */
62         if (profile == NULL)
63                 return -rte_mtr_error_set(error, EINVAL,
64                                           RTE_MTR_ERROR_TYPE_METER_PROFILE,
65                                           NULL, "Meter profile is null.");
66         /* Meter profile ID must be valid. */
67         if (meter_profile_id == UINT32_MAX)
68                 return -rte_mtr_error_set(error, EINVAL,
69                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
70                                           NULL, "Meter profile id not valid.");
71         /* Meter profile must not exist. */
72         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
73         if (fmp)
74                 return -rte_mtr_error_set(error, EEXIST,
75                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
76                                           NULL,
77                                           "Meter profile already exists.");
78         if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
79                 if (priv->config.hca_attr.qos.srtcm_sup) {
80                         /* Verify support for flow meter parameters. */
81                         if (profile->srtcm_rfc2697.cir > 0 &&
82                             profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
83                             profile->srtcm_rfc2697.cbs > 0 &&
84                             profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
85                             profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
86                                 return 0;
87                         else
88                                 return -rte_mtr_error_set
89                                              (error, ENOTSUP,
90                                               RTE_MTR_ERROR_TYPE_MTR_PARAMS,
91                                               NULL,
92                                               profile->srtcm_rfc2697.ebs ?
93                                               "Metering value ebs must be 0." :
94                                               "Invalid metering parameters.");
95                 }
96         }
97         return -rte_mtr_error_set(error, ENOTSUP,
98                                   RTE_MTR_ERROR_TYPE_METER_PROFILE,
99                                   NULL, "Metering algorithm not supported.");
100 }
101
102 /**
103  * Calculate mantissa and exponent for cir.
104  *
105  * @param[in] cir
106  *   Value to be calculated.
107  * @param[out] man
108  *   Pointer to the mantissa.
109  * @param[out] exp
110  *   Pointer to the exp.
111  */
112 static void
113 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
114 {
115         int64_t _cir;
116         int64_t delta = INT64_MAX;
117         uint8_t _man = 0;
118         uint8_t _exp = 0;
119         uint64_t m, e;
120
121         for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
122                 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
123                         _cir = (1000000000ULL * m) >> e;
124                         if (llabs(cir - _cir) <= delta) {
125                                 delta = llabs(cir - _cir);
126                                 _man = m;
127                                 _exp = e;
128                         }
129                 }
130         }
131         *man = _man;
132         *exp = _exp;
133 }
134
135 /**
136  * Calculate mantissa and exponent for xbs.
137  *
138  * @param[in] xbs
139  *   Value to be calculated.
140  * @param[out] man
141  *   Pointer to the mantissa.
142  * @param[out] exp
143  *   Pointer to the exp.
144  */
145 static void
146 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
147 {
148         int _exp;
149         double _man;
150
151         /* Special case xbs == 0 ? both exp and matissa are 0. */
152         if (xbs == 0) {
153                 *man = 0;
154                 *exp = 0;
155                 return;
156         }
157         /* xbs = xbs_mantissa * 2^xbs_exponent */
158         _man = frexp(xbs, &_exp);
159         _man = _man * pow(2, MLX5_MAN_WIDTH);
160         _exp = _exp - MLX5_MAN_WIDTH;
161         *man = (uint8_t)ceil(_man);
162         *exp = _exp;
163 }
164
165 /**
166  * Fill the prm meter parameter.
167  *
168  * @param[in,out] fmp
169  *   Pointer to meter profie to be converted.
170  * @param[out] error
171  *   Pointer to the error structure.
172  *
173  * @return
174  *   0 on success, a negative errno value otherwise and rte_errno is set.
175  */
176 static int
177 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
178                           struct rte_mtr_error *error)
179 {
180         struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
181         uint8_t man, exp;
182
183         if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
184                 return -rte_mtr_error_set(error, ENOTSUP,
185                                 RTE_MTR_ERROR_TYPE_METER_PROFILE,
186                                 NULL, "Metering algorithm not supported.");
187          /* cbs = cbs_mantissa * 2^cbs_exponent */
188         mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
189                                     &man, &exp);
190         srtcm->cbs_mantissa = man;
191         srtcm->cbs_exponent = exp;
192         /* Check if cbs mantissa is too large. */
193         if (srtcm->cbs_exponent != exp)
194                 return -rte_mtr_error_set(error, EINVAL,
195                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
196                                           "Metering profile parameter cbs is"
197                                           " invalid.");
198         /* ebs = ebs_mantissa * 2^ebs_exponent */
199         mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
200                                     &man, &exp);
201         srtcm->ebs_mantissa = man;
202         srtcm->ebs_exponent = exp;
203         /* Check if ebs mantissa is too large. */
204         if (srtcm->ebs_exponent != exp)
205                 return -rte_mtr_error_set(error, EINVAL,
206                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
207                                           "Metering profile parameter ebs is"
208                                           " invalid.");
209         /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
210         mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
211                                     &man, &exp);
212         srtcm->cir_mantissa = man;
213         srtcm->cir_exponent = exp;
214         /* Check if cir mantissa is too large. */
215         if (srtcm->cir_exponent != exp)
216                 return -rte_mtr_error_set(error, EINVAL,
217                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
218                                           "Metering profile parameter cir is"
219                                           " invalid.");
220         return 0;
221 }
222
223 /**
224  * Callback to get MTR capabilities.
225  *
226  * @param[in] dev
227  *   Pointer to Ethernet device.
228  * @param[out] cap
229  *   Pointer to save MTR capabilities.
230  * @param[out] error
231  *   Pointer to the error structure.
232  *
233  * @return
234  *   0 on success, a negative errno value otherwise and rte_errno is set.
235  */
236 static int
237 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
238                  struct rte_mtr_capabilities *cap,
239                  struct rte_mtr_error *error __rte_unused)
240 {
241         struct mlx5_priv *priv = dev->data->dev_private;
242         struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
243
244         if (!priv->mtr_en)
245                 return -rte_mtr_error_set(error, ENOTSUP,
246                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
247                                           "Meter is not support");
248         memset(cap, 0, sizeof(*cap));
249         cap->n_max = 1 << qattr->log_max_flow_meter;
250         cap->n_shared_max = cap->n_max;
251         cap->identical = 1;
252         cap->shared_identical = 1;
253         cap->shared_n_flows_per_mtr_max = 4 << 20;
254         /* 2M flows can share the same meter. */
255         cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
256         cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0;
257         cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
258         cap->policer_action_drop_supported = 1;
259         cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
260                           RTE_MTR_STATS_N_PKTS_DROPPED;
261         return 0;
262 }
263
264 /**
265  * Callback to add MTR profile.
266  *
267  * @param[in] dev
268  *   Pointer to Ethernet device.
269  * @param[in] meter_profile_id
270  *   Meter profile id.
271  * @param[in] profile
272  *   Pointer to meter profile detail.
273  * @param[out] error
274  *   Pointer to the error structure.
275  *
276  * @return
277  *   0 on success, a negative errno value otherwise and rte_errno is set.
278  */
279 static int
280 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
281                        uint32_t meter_profile_id,
282                        struct rte_mtr_meter_profile *profile,
283                        struct rte_mtr_error *error)
284 {
285         struct mlx5_priv *priv = dev->data->dev_private;
286         struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
287         struct mlx5_flow_meter_profile *fmp;
288         int ret;
289
290         if (!priv->mtr_en)
291                 return -rte_mtr_error_set(error, ENOTSUP,
292                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
293                                           "Meter is not support");
294         /* Check input params. */
295         ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
296                                                profile, error);
297         if (ret)
298                 return ret;
299         /* Meter profile memory allocation. */
300         fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
301                          RTE_CACHE_LINE_SIZE);
302         if (fmp == NULL)
303                 return -rte_mtr_error_set(error, ENOMEM,
304                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
305                                           NULL, "Meter profile memory "
306                                           "alloc failed.");
307         /* Fill profile info. */
308         fmp->meter_profile_id = meter_profile_id;
309         fmp->profile = *profile;
310         /* Fill the flow meter parameters for the PRM. */
311         ret = mlx5_flow_meter_param_fill(fmp, error);
312         if (ret)
313                 goto error;
314         /* Add to list. */
315         TAILQ_INSERT_TAIL(fmps, fmp, next);
316         return 0;
317 error:
318         rte_free(fmp);
319         return ret;
320 }
321
322 /**
323  * Callback to delete MTR profile.
324  *
325  * @param[in] dev
326  *   Pointer to Ethernet device.
327  * @param[in] meter_profile_id
328  *   Meter profile id.
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_delete(struct rte_eth_dev *dev,
337                           uint32_t meter_profile_id,
338                           struct rte_mtr_error *error)
339 {
340         struct mlx5_priv *priv = dev->data->dev_private;
341         struct mlx5_flow_meter_profile *fmp;
342
343         if (!priv->mtr_en)
344                 return -rte_mtr_error_set(error, ENOTSUP,
345                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
346                                           "Meter is not support");
347         /* Meter profile must exist. */
348         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
349         if (fmp == NULL)
350                 return -rte_mtr_error_set(error, ENOENT,
351                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
352                                           &meter_profile_id,
353                                           "Meter profile id invalid.");
354         /* Check profile is unused. */
355         if (fmp->ref_cnt)
356                 return -rte_mtr_error_set(error, EBUSY,
357                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
358                                           NULL, "Meter profile in use.");
359         /* Remove from list. */
360         TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
361         rte_free(fmp);
362         return 0;
363 }
364
365 /**
366  * Convert wrong color setting action to verbose error.
367  *
368  * @param[in] action
369  *   Policy color action.
370  *
371  * @return
372  *   Verbose meter color error type.
373  */
374 static inline enum rte_mtr_error_type
375 action2error(enum rte_mtr_policer_action action)
376 {
377         switch (action) {
378         case MTR_POLICER_ACTION_COLOR_GREEN:
379                 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN;
380         case MTR_POLICER_ACTION_COLOR_YELLOW:
381                 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW;
382         case MTR_POLICER_ACTION_COLOR_RED:
383                 return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED;
384         default:
385                 break;
386         }
387         return RTE_MTR_ERROR_TYPE_UNSPECIFIED;
388 }
389
390 /**
391  * Check meter validation.
392  *
393  * @param[in] priv
394  *   Pointer to mlx5 private data structure.
395  * @param[in] meter_id
396  *   Meter id.
397  * @param[in] params
398  *   Pointer to rte meter parameters.
399  * @param[out] error
400  *   Pointer to rte meter error structure.
401  *
402  * @return
403  *   0 on success, a negative errno value otherwise and rte_errno is set.
404  */
405 static int
406 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
407                          struct rte_mtr_params *params,
408                          struct rte_mtr_error *error)
409 {
410         static enum rte_mtr_policer_action
411                                 valid_recol_action[RTE_COLORS] = {
412                                                MTR_POLICER_ACTION_COLOR_GREEN,
413                                                MTR_POLICER_ACTION_COLOR_YELLOW,
414                                                MTR_POLICER_ACTION_COLOR_RED };
415         int i;
416
417         /* Meter params must not be NULL. */
418         if (params == NULL)
419                 return -rte_mtr_error_set(error, EINVAL,
420                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
421                                           NULL, "Meter object params null.");
422         /* Previous meter color is not supported. */
423         if (params->use_prev_mtr_color)
424                 return -rte_mtr_error_set(error, ENOTSUP,
425                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
426                                           NULL,
427                                           "Previous meter color "
428                                           "not supported.");
429         /* Validate policer settings. */
430         for (i = 0; i < RTE_COLORS; i++)
431                 if (params->action[i] != valid_recol_action[i] &&
432                     params->action[i] != MTR_POLICER_ACTION_DROP)
433                         return -rte_mtr_error_set
434                                         (error, ENOTSUP,
435                                          action2error(params->action[i]), NULL,
436                                          "Recolor action not supported.");
437         /* Validate meter id. */
438         if (mlx5_flow_meter_find(priv, meter_id))
439                 return -rte_mtr_error_set(error, EEXIST,
440                                           RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
441                                           "Meter object already exists.");
442         return 0;
443 }
444
445 /**
446  * Create meter rules.
447  *
448  * @param[in] dev
449  *   Pointer to Ethernet device.
450  * @param[in] meter_id
451  *   Meter id.
452  * @param[in] params
453  *   Pointer to rte meter parameters.
454  * @param[in] shared
455  *   Meter shared with other flow or not.
456  * @param[out] error
457  *   Pointer to rte meter error structure.
458  *
459  * @return
460  *   0 on success, a negative errno value otherwise and rte_errno is set.
461  */
462 static int
463 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
464                        struct rte_mtr_params *params, int shared,
465                        struct rte_mtr_error *error)
466 {
467         struct mlx5_priv *priv = dev->data->dev_private;
468         struct mlx5_flow_meters *fms = &priv->flow_meters;
469         struct mlx5_flow_meter_profile *fmp;
470         struct mlx5_flow_meter *fm;
471         const struct rte_flow_attr attr = {
472                                 .ingress = 1,
473                                 .egress = 1,
474                                 .transfer = priv->config.dv_esw_en ? 1 : 0,
475                         };
476         int ret;
477
478         if (!priv->mtr_en)
479                 return -rte_mtr_error_set(error, ENOTSUP,
480                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
481                                           "Meter is not support");
482         /* Validate the parameters. */
483         ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
484         if (ret)
485                 return ret;
486         /* Meter profile must exist. */
487         fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
488         if (fmp == NULL)
489                 return -rte_mtr_error_set(error, ENOENT,
490                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
491                                           NULL, "Meter profile id not valid.");
492         /* Allocate the flow meter memory. */
493         fm = rte_calloc(__func__, 1,
494                         sizeof(struct mlx5_flow_meter), RTE_CACHE_LINE_SIZE);
495         if (fm == NULL)
496                 return -rte_mtr_error_set(error, ENOMEM,
497                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
498                                           "Memory alloc failed for meter.");
499         /* Fill the flow meter parameters. */
500         fm->meter_id = meter_id;
501         fm->profile = fmp;
502         fm->params = *params;
503         fm->mfts = mlx5_flow_create_mtr_tbls(dev);
504         if (!fm->mfts)
505                 goto error;
506         ret = mlx5_flow_create_policer_rules(dev, fm, &attr);
507         if (ret)
508                 goto error;
509         /* Add to the flow meter list. */
510         TAILQ_INSERT_TAIL(fms, fm, next);
511         fm->active_state = 1; /* Config meter starts as active. */
512         fm->shared = !!shared;
513         fm->profile->ref_cnt++;
514         return 0;
515 error:
516         mlx5_flow_destroy_policer_rules(dev, fm, &attr);
517         mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
518         rte_free(fm);
519         return -rte_mtr_error_set(error, -ret,
520                                   RTE_MTR_ERROR_TYPE_UNSPECIFIED,
521                                   NULL, "Failed to create devx meter.");
522 }
523
524 /**
525  * Destroy meter rules.
526  *
527  * @param[in] dev
528  *   Pointer to Ethernet device.
529  * @param[in] meter_id
530  *   Meter id.
531  * @param[out] error
532  *   Pointer to rte meter error structure.
533  *
534  * @return
535  *   0 on success, a negative errno value otherwise and rte_errno is set.
536  */
537 static int
538 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
539                         struct rte_mtr_error *error)
540 {
541         struct mlx5_priv *priv = dev->data->dev_private;
542         struct mlx5_flow_meters *fms = &priv->flow_meters;
543         struct mlx5_flow_meter_profile *fmp;
544         struct mlx5_flow_meter *fm;
545         const struct rte_flow_attr attr = {
546                                 .ingress = 1,
547                                 .egress = 1,
548                                 .transfer = priv->config.dv_esw_en ? 1 : 0,
549                         };
550
551         if (!priv->mtr_en)
552                 return -rte_mtr_error_set(error, ENOTSUP,
553                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
554                                           "Meter is not support");
555         /* Meter object must exist. */
556         fm = mlx5_flow_meter_find(priv, meter_id);
557         if (fm == NULL)
558                 return -rte_mtr_error_set(error, ENOENT,
559                                           RTE_MTR_ERROR_TYPE_MTR_ID,
560                                           NULL, "Meter object id not valid.");
561         /* Meter object must not have any owner. */
562         if (fm->ref_cnt > 0)
563                 return -rte_mtr_error_set(error, EBUSY,
564                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
565                                           NULL, "Meter object is being used.");
566         /* Get the meter profile. */
567         fmp = fm->profile;
568         RTE_ASSERT(fmp);
569         /* Update dependencies. */
570         fmp->ref_cnt--;
571         /* Remove from the flow meter list. */
572         TAILQ_REMOVE(fms, fm, next);
573         /* Free meter flow table */
574         mlx5_flow_destroy_policer_rules(dev, fm, &attr);
575         mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
576         rte_free(fm);
577         return 0;
578 }
579
580 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
581         .capabilities_get = mlx5_flow_mtr_cap_get,
582         .meter_profile_add = mlx5_flow_meter_profile_add,
583         .meter_profile_delete = mlx5_flow_meter_profile_delete,
584         .create = mlx5_flow_meter_create,
585         .destroy = mlx5_flow_meter_destroy,
586         .meter_enable = NULL,
587         .meter_disable = NULL,
588         .meter_profile_update = NULL,
589         .meter_dscp_table_update = NULL,
590         .policer_actions_update = NULL,
591         .stats_update = NULL,
592         .stats_read = NULL,
593 };
594
595 /**
596  * Get meter operations.
597  *
598  * @param dev
599  *   Pointer to Ethernet device structure.
600  * @param arg
601  *   Pointer to set the mtr operations.
602  *
603  * @return
604  *   Always 0.
605  */
606 int
607 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
608 {
609         *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
610         return 0;
611 }
612
613 /**
614  * Find meter by id.
615  *
616  * @param priv
617  *   Pointer to mlx5_priv.
618  * @param meter_id
619  *   Meter id.
620  *
621  * @return
622  *   Pointer to the profile found on success, NULL otherwise.
623  */
624 struct mlx5_flow_meter *
625 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
626 {
627         struct mlx5_flow_meters *fms = &priv->flow_meters;
628         struct mlx5_flow_meter *fm;
629
630         TAILQ_FOREACH(fm, fms, next)
631                 if (meter_id == fm->meter_id)
632                         return fm;
633         return NULL;
634 }