1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4 
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <rte_mtr.h>
10 #include <rte_mtr_driver.h>
11 
12 #include "rte_eth_softnic_internals.h"
13 
14 int
softnic_mtr_init(struct pmd_internals * p)15 softnic_mtr_init(struct pmd_internals *p)
16 {
17 	/* Initialize meter profiles list */
18 	TAILQ_INIT(&p->mtr.meter_profiles);
19 
20 	/* Initialize MTR objects list */
21 	TAILQ_INIT(&p->mtr.mtrs);
22 
23 	return 0;
24 }
25 
26 void
softnic_mtr_free(struct pmd_internals * p)27 softnic_mtr_free(struct pmd_internals *p)
28 {
29 	/* Remove MTR objects */
30 	for ( ; ; ) {
31 		struct softnic_mtr *m;
32 
33 		m = TAILQ_FIRST(&p->mtr.mtrs);
34 		if (m == NULL)
35 			break;
36 
37 		TAILQ_REMOVE(&p->mtr.mtrs, m, node);
38 		free(m);
39 	}
40 
41 	/* Remove meter profiles */
42 	for ( ; ; ) {
43 		struct softnic_mtr_meter_profile *mp;
44 
45 		mp = TAILQ_FIRST(&p->mtr.meter_profiles);
46 		if (mp == NULL)
47 			break;
48 
49 		TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node);
50 		free(mp);
51 	}
52 }
53 
54 struct softnic_mtr_meter_profile *
softnic_mtr_meter_profile_find(struct pmd_internals * p,uint32_t meter_profile_id)55 softnic_mtr_meter_profile_find(struct pmd_internals *p,
56 	uint32_t meter_profile_id)
57 {
58 	struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles;
59 	struct softnic_mtr_meter_profile *mp;
60 
61 	TAILQ_FOREACH(mp, mpl, node)
62 		if (meter_profile_id == mp->meter_profile_id)
63 			return mp;
64 
65 	return NULL;
66 }
67 
68 enum rte_table_action_policer
softnic_table_action_policer(enum rte_mtr_policer_action action)69 softnic_table_action_policer(enum rte_mtr_policer_action action)
70 {
71 	switch (action) {
72 	case MTR_POLICER_ACTION_COLOR_GREEN:
73 		return RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
74 
75 		/* FALLTHROUGH */
76 	case MTR_POLICER_ACTION_COLOR_YELLOW:
77 		return RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
78 
79 		/* FALLTHROUGH */
80 	case MTR_POLICER_ACTION_COLOR_RED:
81 		return RTE_TABLE_ACTION_POLICER_COLOR_RED;
82 
83 		/* FALLTHROUGH */
84 	default:
85 		return RTE_TABLE_ACTION_POLICER_DROP;
86 	}
87 }
88 
89 static int
meter_profile_check(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_meter_profile * profile,struct rte_mtr_error * error)90 meter_profile_check(struct rte_eth_dev *dev,
91 	uint32_t meter_profile_id,
92 	struct rte_mtr_meter_profile *profile,
93 	struct rte_mtr_error *error)
94 {
95 	struct pmd_internals *p = dev->data->dev_private;
96 	struct softnic_mtr_meter_profile *mp;
97 
98 	/* Meter profile ID must be valid. */
99 	if (meter_profile_id == UINT32_MAX)
100 		return -rte_mtr_error_set(error,
101 			EINVAL,
102 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
103 			NULL,
104 			"Meter profile id not valid");
105 
106 	/* Meter profile must not exist. */
107 	mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
108 	if (mp)
109 		return -rte_mtr_error_set(error,
110 			EEXIST,
111 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
112 			NULL,
113 			"Meter prfile already exists");
114 
115 	/* Profile must not be NULL. */
116 	if (profile == NULL)
117 		return -rte_mtr_error_set(error,
118 			EINVAL,
119 			RTE_MTR_ERROR_TYPE_METER_PROFILE,
120 			NULL,
121 			"profile null");
122 
123 	/* Traffic metering algorithm : TRTCM_RFC2698 */
124 	if (profile->alg != RTE_MTR_TRTCM_RFC2698)
125 		return -rte_mtr_error_set(error,
126 			EINVAL,
127 			RTE_MTR_ERROR_TYPE_METER_PROFILE,
128 			NULL,
129 			"Metering alg not supported");
130 
131 	return 0;
132 }
133 
134 /* MTR meter profile add */
135 static int
pmd_mtr_meter_profile_add(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_meter_profile * profile,struct rte_mtr_error * error)136 pmd_mtr_meter_profile_add(struct rte_eth_dev *dev,
137 	uint32_t meter_profile_id,
138 	struct rte_mtr_meter_profile *profile,
139 	struct rte_mtr_error *error)
140 {
141 	struct pmd_internals *p = dev->data->dev_private;
142 	struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles;
143 	struct softnic_mtr_meter_profile *mp;
144 	int status;
145 
146 	/* Check input params */
147 	status = meter_profile_check(dev, meter_profile_id, profile, error);
148 	if (status)
149 		return status;
150 
151 	/* Memory allocation */
152 	mp = calloc(1, sizeof(struct softnic_mtr_meter_profile));
153 	if (mp == NULL)
154 		return -rte_mtr_error_set(error,
155 			ENOMEM,
156 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
157 			NULL,
158 			"Memory alloc failed");
159 
160 	/* Fill in */
161 	mp->meter_profile_id = meter_profile_id;
162 	memcpy(&mp->params, profile, sizeof(mp->params));
163 
164 	/* Add to list */
165 	TAILQ_INSERT_TAIL(mpl, mp, node);
166 
167 	return 0;
168 }
169 
170 /* MTR meter profile delete */
171 static int
pmd_mtr_meter_profile_delete(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_error * error)172 pmd_mtr_meter_profile_delete(struct rte_eth_dev *dev,
173 	uint32_t meter_profile_id,
174 	struct rte_mtr_error *error)
175 {
176 	struct pmd_internals *p = dev->data->dev_private;
177 	struct softnic_mtr_meter_profile *mp;
178 
179 	/* Meter profile must exist */
180 	mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
181 	if (mp == NULL)
182 		return -rte_mtr_error_set(error,
183 			EINVAL,
184 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
185 			NULL,
186 			"Meter profile id invalid");
187 
188 	/* Check unused */
189 	if (mp->n_users)
190 		return -rte_mtr_error_set(error,
191 			EBUSY,
192 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
193 			NULL,
194 			"Meter profile in use");
195 
196 	/* Remove from list */
197 	TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node);
198 	free(mp);
199 
200 	return 0;
201 }
202 
203 struct softnic_mtr *
softnic_mtr_find(struct pmd_internals * p,uint32_t mtr_id)204 softnic_mtr_find(struct pmd_internals *p, uint32_t mtr_id)
205 {
206 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
207 	struct softnic_mtr *m;
208 
209 	TAILQ_FOREACH(m, ml, node)
210 		if (m->mtr_id == mtr_id)
211 			return m;
212 
213 	return NULL;
214 }
215 
216 
217 static int
mtr_check(struct pmd_internals * p,uint32_t mtr_id,struct rte_mtr_params * params,int shared,struct rte_mtr_error * error)218 mtr_check(struct pmd_internals *p,
219 	uint32_t mtr_id,
220 	struct rte_mtr_params *params,
221 	int shared,
222 	struct rte_mtr_error *error)
223 {
224 	/* MTR id valid  */
225 	if (softnic_mtr_find(p, mtr_id))
226 		return -rte_mtr_error_set(error,
227 			EEXIST,
228 			RTE_MTR_ERROR_TYPE_MTR_ID,
229 			NULL,
230 			"MTR object already exists");
231 
232 	/* MTR params must not be NULL */
233 	if (params == NULL)
234 		return -rte_mtr_error_set(error,
235 			EINVAL,
236 			RTE_MTR_ERROR_TYPE_MTR_PARAMS,
237 			NULL,
238 			"MTR object params null");
239 
240 	/* Previous meter color not supported */
241 	if (params->use_prev_mtr_color)
242 		return -rte_mtr_error_set(error,
243 			EINVAL,
244 			RTE_MTR_ERROR_TYPE_MTR_PARAMS,
245 			NULL,
246 			"Previous meter color not supported");
247 
248 	/* Shared MTR object not supported */
249 	if (shared)
250 		return -rte_mtr_error_set(error,
251 			EINVAL,
252 			RTE_MTR_ERROR_TYPE_SHARED,
253 			NULL,
254 			"Shared MTR object not supported");
255 
256 	return 0;
257 }
258 
259 /* MTR object create */
260 static int
pmd_mtr_create(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_params * params,int shared,struct rte_mtr_error * error)261 pmd_mtr_create(struct rte_eth_dev *dev,
262 	uint32_t mtr_id,
263 	struct rte_mtr_params *params,
264 	int shared,
265 	struct rte_mtr_error *error)
266 {
267 	struct pmd_internals *p = dev->data->dev_private;
268 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
269 	struct softnic_mtr_meter_profile *mp;
270 	struct softnic_mtr *m;
271 	int status;
272 
273 	/* Check parameters */
274 	status = mtr_check(p, mtr_id, params, shared, error);
275 	if (status)
276 		return status;
277 
278 	/* Meter profile must exist */
279 	mp = softnic_mtr_meter_profile_find(p, params->meter_profile_id);
280 	if (mp == NULL)
281 		return -rte_mtr_error_set(error,
282 			EINVAL,
283 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
284 			NULL,
285 			"Meter profile id not valid");
286 
287 	/* Memory allocation */
288 	m = calloc(1, sizeof(struct softnic_mtr));
289 	if (m == NULL)
290 		return -rte_mtr_error_set(error,
291 			ENOMEM,
292 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
293 			NULL,
294 			"Memory alloc failed");
295 
296 	/* Fill in */
297 	m->mtr_id = mtr_id;
298 	memcpy(&m->params, params, sizeof(m->params));
299 
300 	/* Add to list */
301 	TAILQ_INSERT_TAIL(ml, m, node);
302 
303 	/* Update dependencies */
304 	mp->n_users++;
305 
306 	return 0;
307 }
308 
309 /* MTR object destroy */
310 static int
pmd_mtr_destroy(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)311 pmd_mtr_destroy(struct rte_eth_dev *dev,
312 	uint32_t mtr_id,
313 	struct rte_mtr_error *error)
314 {
315 	struct pmd_internals *p = dev->data->dev_private;
316 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
317 	struct softnic_mtr_meter_profile *mp;
318 	struct softnic_mtr *m;
319 
320 	/* MTR object must exist */
321 	m = softnic_mtr_find(p, mtr_id);
322 	if (m == NULL)
323 		return -rte_mtr_error_set(error,
324 			EEXIST,
325 			RTE_MTR_ERROR_TYPE_MTR_ID,
326 			NULL,
327 			"MTR object id not valid");
328 
329 	/* MTR object must not have any owner */
330 	if (m->flow != NULL)
331 		return -rte_mtr_error_set(error,
332 			EINVAL,
333 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
334 			NULL,
335 			"MTR object is being used");
336 
337 	/* Get meter profile */
338 	mp = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
339 	if (mp == NULL)
340 		return -rte_mtr_error_set(error,
341 			EINVAL,
342 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
343 			NULL,
344 			"MTR object meter profile invalid");
345 
346 	/* Update dependencies */
347 	mp->n_users--;
348 
349 	/* Remove from list */
350 	TAILQ_REMOVE(ml, m, node);
351 	free(m);
352 
353 	return 0;
354 }
355 
356 /* MTR object meter profile update */
357 static int
pmd_mtr_meter_profile_update(struct rte_eth_dev * dev,uint32_t mtr_id,uint32_t meter_profile_id,struct rte_mtr_error * error)358 pmd_mtr_meter_profile_update(struct rte_eth_dev *dev,
359 	uint32_t mtr_id,
360 	uint32_t meter_profile_id,
361 	struct rte_mtr_error *error)
362 {
363 	struct pmd_internals *p = dev->data->dev_private;
364 	struct softnic_mtr_meter_profile *mp_new, *mp_old;
365 	struct softnic_mtr *m;
366 	int status;
367 
368 	/* MTR object id must be valid */
369 	m = softnic_mtr_find(p, mtr_id);
370 	if (m == NULL)
371 		return -rte_mtr_error_set(error,
372 			EEXIST,
373 			RTE_MTR_ERROR_TYPE_MTR_ID,
374 			NULL,
375 			"MTR object id not valid");
376 
377 	/* Meter profile id must be valid */
378 	mp_new = softnic_mtr_meter_profile_find(p, meter_profile_id);
379 	if (mp_new == NULL)
380 		return -rte_mtr_error_set(error,
381 			EINVAL,
382 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
383 			NULL,
384 			"Meter profile not valid");
385 
386 	/* MTR object already set to meter profile id */
387 	if (m->params.meter_profile_id == meter_profile_id)
388 		return 0;
389 
390 	/*  MTR object owner table update */
391 	if (m->flow) {
392 		uint32_t table_id = m->flow->table_id;
393 		struct softnic_table *table = &m->flow->pipeline->table[table_id];
394 		struct softnic_table_rule_action action;
395 
396 		if (!softnic_pipeline_table_meter_profile_find(table,
397 			meter_profile_id)) {
398 			struct rte_table_action_meter_profile profile;
399 
400 			memset(&profile, 0, sizeof(profile));
401 
402 			profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
403 			profile.trtcm.cir = mp_new->params.trtcm_rfc2698.cir;
404 			profile.trtcm.pir = mp_new->params.trtcm_rfc2698.pir;
405 			profile.trtcm.cbs = mp_new->params.trtcm_rfc2698.cbs;
406 			profile.trtcm.pbs = mp_new->params.trtcm_rfc2698.pbs;
407 
408 			/* Add meter profile to pipeline table */
409 			status = softnic_pipeline_table_mtr_profile_add(p,
410 					m->flow->pipeline->name,
411 					table_id,
412 					meter_profile_id,
413 					&profile);
414 			if (status)
415 				return -rte_mtr_error_set(error,
416 					EINVAL,
417 					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
418 					NULL,
419 					"Table meter profile add failed");
420 		}
421 
422 		/* Set meter action */
423 		memcpy(&action, &m->flow->action, sizeof(action));
424 
425 		action.mtr.mtr[0].meter_profile_id = meter_profile_id;
426 
427 		/* Re-add rule */
428 		status = softnic_pipeline_table_rule_add(p,
429 			m->flow->pipeline->name,
430 			table_id,
431 			&m->flow->match,
432 			&action,
433 			&m->flow->data);
434 		if (status)
435 			return -rte_mtr_error_set(error,
436 				EINVAL,
437 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
438 				NULL,
439 				"Pipeline table rule add failed");
440 
441 		/* Flow: update meter action */
442 		memcpy(&m->flow->action, &action, sizeof(m->flow->action));
443 	}
444 
445 	mp_old = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
446 
447 	/* Meter: Set meter profile */
448 	m->params.meter_profile_id = meter_profile_id;
449 
450 	/* Update dependencies*/
451 	mp_old->n_users--;
452 	mp_new->n_users++;
453 
454 	return 0;
455 }
456 
457 /* MTR object meter DSCP table update */
458 static int
pmd_mtr_meter_dscp_table_update(struct rte_eth_dev * dev,uint32_t mtr_id,enum rte_color * dscp_table,struct rte_mtr_error * error)459 pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev,
460 	uint32_t mtr_id,
461 	enum rte_color *dscp_table,
462 	struct rte_mtr_error *error)
463 {
464 	struct pmd_internals *p = dev->data->dev_private;
465 	struct rte_table_action_dscp_table dt;
466 	struct pipeline *pipeline;
467 	struct softnic_table *table;
468 	struct softnic_mtr *m;
469 	uint32_t table_id, i;
470 	int status;
471 
472 	/* MTR object id must be valid */
473 	m = softnic_mtr_find(p, mtr_id);
474 	if (m == NULL)
475 		return -rte_mtr_error_set(error,
476 			EEXIST,
477 			RTE_MTR_ERROR_TYPE_MTR_ID,
478 			NULL,
479 			"MTR object id not valid");
480 
481 	/* MTR object owner valid? */
482 	if (m->flow == NULL)
483 		return 0;
484 
485 	pipeline = m->flow->pipeline;
486 	table_id = m->flow->table_id;
487 	table = &pipeline->table[table_id];
488 
489 	memcpy(&dt, &table->dscp_table, sizeof(dt));
490 	for (i = 0; i < RTE_DIM(dt.entry); i++)
491 		dt.entry[i].color = (enum rte_color)dscp_table[i];
492 
493 	/* Update table */
494 	status = softnic_pipeline_table_dscp_table_update(p,
495 			pipeline->name,
496 			table_id,
497 			UINT64_MAX,
498 			&dt);
499 	if (status)
500 		return -rte_mtr_error_set(error,
501 			EINVAL,
502 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
503 			NULL,
504 			"Table action dscp table update failed");
505 
506 	return 0;
507 }
508 
509 /* MTR object policer action update */
510 static int
pmd_mtr_policer_actions_update(struct rte_eth_dev * dev,uint32_t mtr_id,uint32_t action_mask,enum rte_mtr_policer_action * actions,struct rte_mtr_error * error)511 pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
512 	uint32_t mtr_id,
513 	uint32_t action_mask,
514 	enum rte_mtr_policer_action *actions,
515 	struct rte_mtr_error *error)
516 {
517 	struct pmd_internals *p = dev->data->dev_private;
518 	struct softnic_mtr *m;
519 	uint32_t i;
520 	int status;
521 
522 	/* MTR object id must be valid */
523 	m = softnic_mtr_find(p, mtr_id);
524 	if (m == NULL)
525 		return -rte_mtr_error_set(error,
526 			EEXIST,
527 			RTE_MTR_ERROR_TYPE_MTR_ID,
528 			NULL,
529 			"MTR object id not valid");
530 
531 	/* Valid policer actions */
532 	if (actions == NULL)
533 		return -rte_mtr_error_set(error,
534 			EINVAL,
535 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
536 			NULL,
537 			"Invalid actions");
538 
539 	for (i = 0; i < RTE_COLORS; i++) {
540 		if (action_mask & (1 << i)) {
541 			if (actions[i] != MTR_POLICER_ACTION_COLOR_GREEN  &&
542 				actions[i] != MTR_POLICER_ACTION_COLOR_YELLOW &&
543 				actions[i] != MTR_POLICER_ACTION_COLOR_RED &&
544 				actions[i] != MTR_POLICER_ACTION_DROP) {
545 				return -rte_mtr_error_set(error,
546 					EINVAL,
547 					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
548 					NULL,
549 					" Invalid action value");
550 			}
551 		}
552 	}
553 
554 	/* MTR object owner valid? */
555 	if (m->flow) {
556 		struct pipeline *pipeline = m->flow->pipeline;
557 		struct softnic_table *table = &pipeline->table[m->flow->table_id];
558 		struct softnic_table_rule_action action;
559 
560 		memcpy(&action, &m->flow->action, sizeof(action));
561 
562 		/* Set action */
563 		for (i = 0; i < RTE_COLORS; i++)
564 			if (action_mask & (1 << i))
565 				action.mtr.mtr[0].policer[i] =
566 					softnic_table_action_policer(actions[i]);
567 
568 		/* Re-add the rule */
569 		status = softnic_pipeline_table_rule_add(p,
570 			pipeline->name,
571 			m->flow->table_id,
572 			&m->flow->match,
573 			&action,
574 			&m->flow->data);
575 		if (status)
576 			return -rte_mtr_error_set(error,
577 				EINVAL,
578 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
579 				NULL,
580 				"Pipeline table rule re-add failed");
581 
582 		/* Flow: Update meter action */
583 		memcpy(&m->flow->action, &action, sizeof(m->flow->action));
584 
585 		/* Reset the meter stats */
586 		rte_table_action_meter_read(table->a, m->flow->data,
587 			1, NULL, 1);
588 	}
589 
590 	/* Meter: Update policer actions */
591 	for (i = 0; i < RTE_COLORS; i++)
592 		if (action_mask & (1 << i))
593 			m->params.action[i] = actions[i];
594 
595 	return 0;
596 }
597 
598 #define MTR_STATS_PKTS_DEFAULT (RTE_MTR_STATS_N_PKTS_GREEN | \
599 				RTE_MTR_STATS_N_PKTS_YELLOW | \
600 				RTE_MTR_STATS_N_PKTS_RED | \
601 				RTE_MTR_STATS_N_PKTS_DROPPED)
602 
603 #define MTR_STATS_BYTES_DEFAULT (RTE_MTR_STATS_N_BYTES_GREEN | \
604 				RTE_MTR_STATS_N_BYTES_YELLOW | \
605 				RTE_MTR_STATS_N_BYTES_RED | \
606 				RTE_MTR_STATS_N_BYTES_DROPPED)
607 
608 /* MTR object stats read */
609 static void
mtr_stats_convert(struct softnic_mtr * m,struct rte_table_action_mtr_counters_tc * in,struct rte_mtr_stats * out,uint64_t * out_mask)610 mtr_stats_convert(struct softnic_mtr *m,
611 	struct rte_table_action_mtr_counters_tc *in,
612 	struct rte_mtr_stats *out,
613 	uint64_t *out_mask)
614 {
615 	memset(&out, 0, sizeof(out));
616 	*out_mask = 0;
617 
618 	if (in->n_packets_valid) {
619 		uint32_t i;
620 
621 		for (i = 0; i < RTE_COLORS; i++) {
622 			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
623 				out->n_pkts[RTE_COLOR_GREEN] += in->n_packets[i];
624 
625 			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
626 				out->n_pkts[RTE_COLOR_YELLOW] += in->n_packets[i];
627 
628 			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
629 				out->n_pkts[RTE_COLOR_RED] += in->n_packets[i];
630 
631 			if (m->params.action[i] == MTR_POLICER_ACTION_DROP)
632 				out->n_pkts_dropped += in->n_packets[i];
633 		}
634 
635 		*out_mask |= MTR_STATS_PKTS_DEFAULT;
636 	}
637 
638 	if (in->n_bytes_valid) {
639 		uint32_t i;
640 
641 		for (i = 0; i < RTE_COLORS; i++) {
642 			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
643 				out->n_bytes[RTE_COLOR_GREEN] += in->n_bytes[i];
644 
645 			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
646 				out->n_bytes[RTE_COLOR_YELLOW] += in->n_bytes[i];
647 
648 			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
649 				out->n_bytes[RTE_COLOR_RED] += in->n_bytes[i];
650 
651 			if (m->params.action[i] == MTR_POLICER_ACTION_DROP)
652 				out->n_bytes_dropped += in->n_bytes[i];
653 		}
654 
655 		*out_mask |= MTR_STATS_BYTES_DEFAULT;
656 	}
657 }
658 
659 /* MTR object stats read */
660 static int
pmd_mtr_stats_read(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_stats * stats,uint64_t * stats_mask,int clear,struct rte_mtr_error * error)661 pmd_mtr_stats_read(struct rte_eth_dev *dev,
662 	uint32_t mtr_id,
663 	struct rte_mtr_stats *stats,
664 	uint64_t *stats_mask,
665 	int clear,
666 	struct rte_mtr_error *error)
667 {
668 	struct pmd_internals *p = dev->data->dev_private;
669 	struct rte_table_action_mtr_counters counters;
670 	struct pipeline *pipeline;
671 	struct softnic_table *table;
672 	struct softnic_mtr *m;
673 	int status;
674 
675 	/* MTR object id must be valid */
676 	m = softnic_mtr_find(p, mtr_id);
677 	if (m == NULL)
678 		return -rte_mtr_error_set(error,
679 			EEXIST,
680 			RTE_MTR_ERROR_TYPE_MTR_ID,
681 			NULL,
682 			"MTR object id not valid");
683 
684 	/* MTR meter object owner valid? */
685 	if (m->flow == NULL) {
686 		if (stats != NULL)
687 			memset(stats, 0, sizeof(*stats));
688 
689 		if (stats_mask)
690 			*stats_mask = MTR_STATS_PKTS_DEFAULT |
691 				MTR_STATS_BYTES_DEFAULT;
692 
693 		return 0;
694 	}
695 
696 	pipeline = m->flow->pipeline;
697 	table = &pipeline->table[m->flow->table_id];
698 
699 	/* Meter stats read. */
700 	status = rte_table_action_meter_read(table->a,
701 		m->flow->data,
702 		1,
703 		&counters,
704 		clear);
705 	if (status)
706 		return -rte_mtr_error_set(error,
707 			EINVAL,
708 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
709 			NULL,
710 			"Meter stats read failed");
711 
712 	/* Stats format conversion. */
713 	if (stats || stats_mask) {
714 		struct rte_mtr_stats s;
715 		uint64_t s_mask = 0;
716 
717 		mtr_stats_convert(m,
718 			&counters.stats[0],
719 			&s,
720 			&s_mask);
721 
722 		if (stats)
723 			memcpy(stats, &s, sizeof(*stats));
724 
725 		if (stats_mask)
726 			*stats_mask = s_mask;
727 	}
728 
729 	return 0;
730 }
731 
732 const struct rte_mtr_ops pmd_mtr_ops = {
733 	.capabilities_get = NULL,
734 
735 	.meter_profile_add = pmd_mtr_meter_profile_add,
736 	.meter_profile_delete = pmd_mtr_meter_profile_delete,
737 
738 	.create = pmd_mtr_create,
739 	.destroy = pmd_mtr_destroy,
740 	.meter_enable = NULL,
741 	.meter_disable = NULL,
742 
743 	.meter_profile_update = pmd_mtr_meter_profile_update,
744 	.meter_dscp_table_update = pmd_mtr_meter_dscp_table_update,
745 	.policer_actions_update = pmd_mtr_policer_actions_update,
746 	.stats_update = NULL,
747 
748 	.stats_read = pmd_mtr_stats_read,
749 };
750