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