New upstream version 18.11-rc2
[deb_dpdk.git] / drivers / net / softnic / rte_eth_softnic_meter.c
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
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
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 *
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
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
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
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
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 *
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
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
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
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
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
459 pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev,
460         uint32_t mtr_id,
461         enum rte_mtr_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_meter_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
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_MTR_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_MTR_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_MTR_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
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_MTR_COLORS; i++) {
622                         if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
623                                 out->n_pkts[RTE_MTR_GREEN] += in->n_packets[i];
624
625                         if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
626                                 out->n_pkts[RTE_MTR_YELLOW] += in->n_packets[i];
627
628                         if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
629                                 out->n_pkts[RTE_MTR_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_MTR_COLORS; i++) {
642                         if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
643                                 out->n_bytes[RTE_MTR_GREEN] += in->n_bytes[i];
644
645                         if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
646                                 out->n_bytes[RTE_MTR_YELLOW] += in->n_bytes[i];
647
648                         if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
649                                 out->n_bytes[RTE_MTR_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
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 };