net/bnxt: support Thor WC TCAM
[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 meter policies list */
21         TAILQ_INIT(&p->mtr.meter_policies);
22
23         /* Initialize MTR objects list */
24         TAILQ_INIT(&p->mtr.mtrs);
25
26         return 0;
27 }
28
29 void
30 softnic_mtr_free(struct pmd_internals *p)
31 {
32         /* Remove MTR objects */
33         for ( ; ; ) {
34                 struct softnic_mtr *m;
35
36                 m = TAILQ_FIRST(&p->mtr.mtrs);
37                 if (m == NULL)
38                         break;
39
40                 TAILQ_REMOVE(&p->mtr.mtrs, m, node);
41                 free(m);
42         }
43
44         /* Remove meter profiles */
45         for ( ; ; ) {
46                 struct softnic_mtr_meter_profile *mp;
47
48                 mp = TAILQ_FIRST(&p->mtr.meter_profiles);
49                 if (mp == NULL)
50                         break;
51
52                 TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node);
53                 free(mp);
54         }
55 }
56
57 struct softnic_mtr_meter_profile *
58 softnic_mtr_meter_profile_find(struct pmd_internals *p,
59         uint32_t meter_profile_id)
60 {
61         struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles;
62         struct softnic_mtr_meter_profile *mp;
63
64         TAILQ_FOREACH(mp, mpl, node)
65                 if (meter_profile_id == mp->meter_profile_id)
66                         return mp;
67
68         return NULL;
69 }
70
71 static int
72 meter_profile_check(struct rte_eth_dev *dev,
73         uint32_t meter_profile_id,
74         struct rte_mtr_meter_profile *profile,
75         struct rte_mtr_error *error)
76 {
77         struct pmd_internals *p = dev->data->dev_private;
78         struct softnic_mtr_meter_profile *mp;
79
80         /* Meter profile ID must be valid. */
81         if (meter_profile_id == UINT32_MAX)
82                 return -rte_mtr_error_set(error,
83                         EINVAL,
84                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
85                         NULL,
86                         "Meter profile id not valid");
87
88         /* Meter profile must not exist. */
89         mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
90         if (mp)
91                 return -rte_mtr_error_set(error,
92                         EEXIST,
93                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
94                         NULL,
95                         "Meter prfile already exists");
96
97         /* Profile must not be NULL. */
98         if (profile == NULL)
99                 return -rte_mtr_error_set(error,
100                         EINVAL,
101                         RTE_MTR_ERROR_TYPE_METER_PROFILE,
102                         NULL,
103                         "profile null");
104
105         /* Traffic metering algorithm : TRTCM_RFC2698 */
106         if (profile->alg != RTE_MTR_TRTCM_RFC2698)
107                 return -rte_mtr_error_set(error,
108                         EINVAL,
109                         RTE_MTR_ERROR_TYPE_METER_PROFILE,
110                         NULL,
111                         "Metering alg not supported");
112
113         /* Not support packet mode, just support byte mode. */
114         if (profile->packet_mode)
115                 return -rte_mtr_error_set(error,
116                         EINVAL,
117                         RTE_MTR_ERROR_TYPE_METER_PROFILE_PACKET_MODE,
118                         NULL,
119                         "Meter packet mode not supported");
120
121         return 0;
122 }
123
124 /* MTR meter profile add */
125 static int
126 pmd_mtr_meter_profile_add(struct rte_eth_dev *dev,
127         uint32_t meter_profile_id,
128         struct rte_mtr_meter_profile *profile,
129         struct rte_mtr_error *error)
130 {
131         struct pmd_internals *p = dev->data->dev_private;
132         struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles;
133         struct softnic_mtr_meter_profile *mp;
134         int status;
135
136         /* Check input params */
137         status = meter_profile_check(dev, meter_profile_id, profile, error);
138         if (status)
139                 return status;
140
141         /* Memory allocation */
142         mp = calloc(1, sizeof(struct softnic_mtr_meter_profile));
143         if (mp == NULL)
144                 return -rte_mtr_error_set(error,
145                         ENOMEM,
146                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
147                         NULL,
148                         "Memory alloc failed");
149
150         /* Fill in */
151         mp->meter_profile_id = meter_profile_id;
152         memcpy(&mp->params, profile, sizeof(mp->params));
153
154         /* Add to list */
155         TAILQ_INSERT_TAIL(mpl, mp, node);
156
157         return 0;
158 }
159
160 /* MTR meter profile delete */
161 static int
162 pmd_mtr_meter_profile_delete(struct rte_eth_dev *dev,
163         uint32_t meter_profile_id,
164         struct rte_mtr_error *error)
165 {
166         struct pmd_internals *p = dev->data->dev_private;
167         struct softnic_mtr_meter_profile *mp;
168
169         /* Meter profile must exist */
170         mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
171         if (mp == NULL)
172                 return -rte_mtr_error_set(error,
173                         EINVAL,
174                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
175                         NULL,
176                         "Meter profile id invalid");
177
178         /* Check unused */
179         if (mp->n_users)
180                 return -rte_mtr_error_set(error,
181                         EBUSY,
182                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
183                         NULL,
184                         "Meter profile in use");
185
186         /* Remove from list */
187         TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node);
188         free(mp);
189
190         return 0;
191 }
192
193 struct softnic_mtr_meter_policy *
194 softnic_mtr_meter_policy_find(struct pmd_internals *p,
195         uint32_t meter_policy_id)
196 {
197         struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
198         struct softnic_mtr_meter_policy *mp;
199
200         TAILQ_FOREACH(mp, mpl, node)
201                 if (meter_policy_id == mp->meter_policy_id)
202                         return mp;
203
204         return NULL;
205 }
206
207 /* MTR meter policy add */
208 static int
209 pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
210         uint32_t meter_policy_id,
211         struct rte_mtr_meter_policy_params *policy,
212         struct rte_mtr_error *error)
213 {
214         struct pmd_internals *p = dev->data->dev_private;
215         struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
216         struct softnic_mtr_meter_policy *mp;
217         const struct rte_flow_action *act;
218         const struct rte_flow_action_meter_color *recolor;
219         uint32_t i;
220         bool valid_act_found;
221
222         if (policy == NULL)
223                 return -rte_mtr_error_set(error,
224                         EINVAL,
225                         RTE_MTR_ERROR_TYPE_METER_POLICY,
226                         NULL,
227                         "Null meter policy invalid");
228
229         /* Meter policy must not exist. */
230         mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
231         if (mp != NULL)
232                 return -rte_mtr_error_set(error,
233                         EINVAL,
234                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
235                         NULL,
236                         "Meter policy already exists");
237
238         for (i = 0; i < RTE_COLORS; i++) {
239                 if (policy->actions[i] == NULL)
240                         return -rte_mtr_error_set(error,
241                                 EINVAL,
242                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
243                                 NULL,
244                                 "Null action list");
245                 for (act = policy->actions[i], valid_act_found = false;
246                      act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
247                         if (act->type == RTE_FLOW_ACTION_TYPE_VOID)
248                                 continue;
249                         /*
250                          * Support one (and one only) of
251                          * METER_COLOR or DROP action.
252                          */
253                         if ((act->type != RTE_FLOW_ACTION_TYPE_METER_COLOR &&
254                                 act->type != RTE_FLOW_ACTION_TYPE_DROP) ||
255                                 valid_act_found)
256                                 return -rte_mtr_error_set(error,
257                                         EINVAL,
258                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
259                                         NULL,
260                                         "Action invalid");
261                         valid_act_found = true;
262                 }
263                 if (!valid_act_found)
264                         return -rte_mtr_error_set(error,
265                                 EINVAL,
266                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
267                                 NULL,
268                                 "No valid action found");
269         }
270
271         /* Memory allocation */
272         mp = calloc(1, sizeof(struct softnic_mtr_meter_policy));
273         if (mp == NULL)
274                 return -rte_mtr_error_set(error,
275                         ENOMEM,
276                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
277                         NULL,
278                         "Memory alloc failed");
279
280         /* Fill in */
281         mp->meter_policy_id = meter_policy_id;
282         for (i = 0; i < RTE_COLORS; i++) {
283                 mp->policer[i] = RTE_TABLE_ACTION_POLICER_DROP;
284                 act = policy->actions[i];
285                 if (!act)
286                         continue;
287                 if (act->type == RTE_FLOW_ACTION_TYPE_METER_COLOR) {
288                         recolor = act->conf;
289                         switch (recolor->color) {
290                         case RTE_COLOR_GREEN:
291                                 mp->policer[i] =
292                                 RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
293                                 break;
294                         case RTE_COLOR_YELLOW:
295                                 mp->policer[i] =
296                                 RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
297                                 break;
298                         case RTE_COLOR_RED:
299                                 mp->policer[i] =
300                                 RTE_TABLE_ACTION_POLICER_COLOR_RED;
301                                 break;
302                         default:
303                                 break;
304                         }
305                 }
306         }
307
308         /* Add to list */
309         TAILQ_INSERT_TAIL(mpl, mp, node);
310
311         return 0;
312 }
313
314 /* MTR meter policy delete */
315 static int
316 pmd_mtr_meter_policy_delete(struct rte_eth_dev *dev,
317         uint32_t meter_policy_id,
318         struct rte_mtr_error *error)
319 {
320         struct pmd_internals *p = dev->data->dev_private;
321         struct softnic_mtr_meter_policy *mp;
322
323         /* Meter policy must exist */
324         mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
325         if (mp == NULL)
326                 return -rte_mtr_error_set(error,
327                         EINVAL,
328                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
329                         NULL,
330                         "Meter policy id invalid");
331
332         /* Check unused */
333         if (mp->n_users)
334                 return -rte_mtr_error_set(error,
335                         EBUSY,
336                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
337                         NULL,
338                         "Meter policy in use");
339
340         /* Remove from list */
341         TAILQ_REMOVE(&p->mtr.meter_policies, mp, node);
342         free(mp);
343
344         return 0;
345 }
346
347 struct softnic_mtr *
348 softnic_mtr_find(struct pmd_internals *p, uint32_t mtr_id)
349 {
350         struct softnic_mtr_list *ml = &p->mtr.mtrs;
351         struct softnic_mtr *m;
352
353         TAILQ_FOREACH(m, ml, node)
354                 if (m->mtr_id == mtr_id)
355                         return m;
356
357         return NULL;
358 }
359
360
361 static int
362 mtr_check(struct pmd_internals *p,
363         uint32_t mtr_id,
364         struct rte_mtr_params *params,
365         int shared,
366         struct rte_mtr_error *error)
367 {
368         /* MTR id valid  */
369         if (softnic_mtr_find(p, mtr_id))
370                 return -rte_mtr_error_set(error,
371                         EEXIST,
372                         RTE_MTR_ERROR_TYPE_MTR_ID,
373                         NULL,
374                         "MTR object already exists");
375
376         /* MTR params must not be NULL */
377         if (params == NULL)
378                 return -rte_mtr_error_set(error,
379                         EINVAL,
380                         RTE_MTR_ERROR_TYPE_MTR_PARAMS,
381                         NULL,
382                         "MTR object params null");
383
384         /* Previous meter color not supported */
385         if (params->use_prev_mtr_color)
386                 return -rte_mtr_error_set(error,
387                         EINVAL,
388                         RTE_MTR_ERROR_TYPE_MTR_PARAMS,
389                         NULL,
390                         "Previous meter color not supported");
391
392         /* Shared MTR object not supported */
393         if (shared)
394                 return -rte_mtr_error_set(error,
395                         EINVAL,
396                         RTE_MTR_ERROR_TYPE_SHARED,
397                         NULL,
398                         "Shared MTR object not supported");
399
400         return 0;
401 }
402
403 /* MTR object create */
404 static int
405 pmd_mtr_create(struct rte_eth_dev *dev,
406         uint32_t mtr_id,
407         struct rte_mtr_params *params,
408         int shared,
409         struct rte_mtr_error *error)
410 {
411         struct pmd_internals *p = dev->data->dev_private;
412         struct softnic_mtr_list *ml = &p->mtr.mtrs;
413         struct softnic_mtr_meter_profile *mp;
414         struct softnic_mtr_meter_policy *policy;
415         struct softnic_mtr *m;
416         int status;
417
418         /* Check parameters */
419         status = mtr_check(p, mtr_id, params, shared, error);
420         if (status)
421                 return status;
422
423         /* Meter profile must exist */
424         mp = softnic_mtr_meter_profile_find(p, params->meter_profile_id);
425         if (mp == NULL)
426                 return -rte_mtr_error_set(error,
427                         EINVAL,
428                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
429                         NULL,
430                         "Meter profile id not valid");
431
432         /* Meter policy must exist */
433         policy = softnic_mtr_meter_policy_find(p, params->meter_policy_id);
434         if (policy == NULL) {
435                 return -rte_mtr_error_set(error,
436                                 EINVAL,
437                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
438                                 NULL,
439                                 "Meter policy id invalid");
440         }
441
442         /* Memory allocation */
443         m = calloc(1, sizeof(struct softnic_mtr));
444         if (m == NULL)
445                 return -rte_mtr_error_set(error,
446                         ENOMEM,
447                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
448                         NULL,
449                         "Memory alloc failed");
450
451         /* Fill in */
452         m->mtr_id = mtr_id;
453         memcpy(&m->params, params, sizeof(m->params));
454
455         /* Add to list */
456         TAILQ_INSERT_TAIL(ml, m, node);
457
458         /* Update dependencies */
459         mp->n_users++;
460         policy->n_users++;
461
462         return 0;
463 }
464
465 /* MTR object destroy */
466 static int
467 pmd_mtr_destroy(struct rte_eth_dev *dev,
468         uint32_t mtr_id,
469         struct rte_mtr_error *error)
470 {
471         struct pmd_internals *p = dev->data->dev_private;
472         struct softnic_mtr_list *ml = &p->mtr.mtrs;
473         struct softnic_mtr_meter_profile *mp;
474         struct softnic_mtr *m;
475         struct softnic_mtr_meter_policy *policy;
476
477         /* MTR object must exist */
478         m = softnic_mtr_find(p, mtr_id);
479         if (m == NULL)
480                 return -rte_mtr_error_set(error,
481                         EEXIST,
482                         RTE_MTR_ERROR_TYPE_MTR_ID,
483                         NULL,
484                         "MTR object id not valid");
485
486         /* MTR object must not have any owner */
487         if (m->flow != NULL)
488                 return -rte_mtr_error_set(error,
489                         EINVAL,
490                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
491                         NULL,
492                         "MTR object is being used");
493
494         /* Get meter profile */
495         mp = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
496         if (mp == NULL)
497                 return -rte_mtr_error_set(error,
498                         EINVAL,
499                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
500                         NULL,
501                         "MTR object meter profile invalid");
502
503         /* Meter policy must exist */
504         policy = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
505         if (policy == NULL)
506                 return -rte_mtr_error_set(error,
507                         EINVAL,
508                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
509                         NULL,
510                         "MTR object meter policy invalid");
511
512         /* Update dependencies */
513         mp->n_users--;
514         policy->n_users--;
515
516         /* Remove from list */
517         TAILQ_REMOVE(ml, m, node);
518         free(m);
519
520         return 0;
521 }
522
523 /* MTR object meter profile update */
524 static int
525 pmd_mtr_meter_profile_update(struct rte_eth_dev *dev,
526         uint32_t mtr_id,
527         uint32_t meter_profile_id,
528         struct rte_mtr_error *error)
529 {
530         struct pmd_internals *p = dev->data->dev_private;
531         struct softnic_mtr_meter_profile *mp_new, *mp_old;
532         struct softnic_mtr *m;
533         int status;
534
535         /* MTR object id must be valid */
536         m = softnic_mtr_find(p, mtr_id);
537         if (m == NULL)
538                 return -rte_mtr_error_set(error,
539                         EEXIST,
540                         RTE_MTR_ERROR_TYPE_MTR_ID,
541                         NULL,
542                         "MTR object id not valid");
543
544         /* Meter profile id must be valid */
545         mp_new = softnic_mtr_meter_profile_find(p, meter_profile_id);
546         if (mp_new == NULL)
547                 return -rte_mtr_error_set(error,
548                         EINVAL,
549                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
550                         NULL,
551                         "Meter profile not valid");
552
553         /* MTR object already set to meter profile id */
554         if (m->params.meter_profile_id == meter_profile_id)
555                 return 0;
556
557         /*  MTR object owner table update */
558         if (m->flow) {
559                 uint32_t table_id = m->flow->table_id;
560                 struct softnic_table *table = &m->flow->pipeline->table[table_id];
561                 struct softnic_table_rule_action action;
562
563                 if (!softnic_pipeline_table_meter_profile_find(table,
564                         meter_profile_id)) {
565                         struct rte_table_action_meter_profile profile;
566
567                         memset(&profile, 0, sizeof(profile));
568
569                         profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
570                         profile.trtcm.cir = mp_new->params.trtcm_rfc2698.cir;
571                         profile.trtcm.pir = mp_new->params.trtcm_rfc2698.pir;
572                         profile.trtcm.cbs = mp_new->params.trtcm_rfc2698.cbs;
573                         profile.trtcm.pbs = mp_new->params.trtcm_rfc2698.pbs;
574
575                         /* Add meter profile to pipeline table */
576                         status = softnic_pipeline_table_mtr_profile_add(p,
577                                         m->flow->pipeline->name,
578                                         table_id,
579                                         meter_profile_id,
580                                         &profile);
581                         if (status)
582                                 return -rte_mtr_error_set(error,
583                                         EINVAL,
584                                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
585                                         NULL,
586                                         "Table meter profile add failed");
587                 }
588
589                 /* Set meter action */
590                 memcpy(&action, &m->flow->action, sizeof(action));
591
592                 action.mtr.mtr[0].meter_profile_id = meter_profile_id;
593
594                 /* Re-add rule */
595                 status = softnic_pipeline_table_rule_add(p,
596                         m->flow->pipeline->name,
597                         table_id,
598                         &m->flow->match,
599                         &action,
600                         &m->flow->data);
601                 if (status)
602                         return -rte_mtr_error_set(error,
603                                 EINVAL,
604                                 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
605                                 NULL,
606                                 "Pipeline table rule add failed");
607
608                 /* Flow: update meter action */
609                 memcpy(&m->flow->action, &action, sizeof(m->flow->action));
610         }
611
612         mp_old = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
613
614         /* Meter: Set meter profile */
615         m->params.meter_profile_id = meter_profile_id;
616
617         /* Update dependencies*/
618         mp_old->n_users--;
619         mp_new->n_users++;
620
621         return 0;
622 }
623
624 /* MTR object meter DSCP table update */
625 static int
626 pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev,
627         uint32_t mtr_id,
628         enum rte_color *dscp_table,
629         struct rte_mtr_error *error)
630 {
631         struct pmd_internals *p = dev->data->dev_private;
632         struct rte_table_action_dscp_table dt;
633         struct pipeline *pipeline;
634         struct softnic_table *table;
635         struct softnic_mtr *m;
636         uint32_t table_id, i;
637         int status;
638
639         /* MTR object id must be valid */
640         m = softnic_mtr_find(p, mtr_id);
641         if (m == NULL)
642                 return -rte_mtr_error_set(error,
643                         EEXIST,
644                         RTE_MTR_ERROR_TYPE_MTR_ID,
645                         NULL,
646                         "MTR object id not valid");
647
648         /* MTR object owner valid? */
649         if (m->flow == NULL)
650                 return 0;
651
652         pipeline = m->flow->pipeline;
653         table_id = m->flow->table_id;
654         table = &pipeline->table[table_id];
655
656         memcpy(&dt, &table->dscp_table, sizeof(dt));
657         for (i = 0; i < RTE_DIM(dt.entry); i++)
658                 dt.entry[i].color = (enum rte_color)dscp_table[i];
659
660         /* Update table */
661         status = softnic_pipeline_table_dscp_table_update(p,
662                         pipeline->name,
663                         table_id,
664                         UINT64_MAX,
665                         &dt);
666         if (status)
667                 return -rte_mtr_error_set(error,
668                         EINVAL,
669                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
670                         NULL,
671                         "Table action dscp table update failed");
672
673         return 0;
674 }
675
676 /* MTR object policy update */
677 static int
678 pmd_mtr_meter_policy_update(struct rte_eth_dev *dev,
679         uint32_t mtr_id,
680         uint32_t meter_policy_id,
681         struct rte_mtr_error *error)
682 {
683         struct pmd_internals *p = dev->data->dev_private;
684         struct softnic_mtr *m;
685         uint32_t i;
686         int status;
687         struct softnic_mtr_meter_policy *mp_new, *mp_old;
688
689         /* MTR object id must be valid */
690         m = softnic_mtr_find(p, mtr_id);
691         if (m == NULL)
692                 return -rte_mtr_error_set(error,
693                         EEXIST,
694                         RTE_MTR_ERROR_TYPE_MTR_ID,
695                         NULL,
696                         "MTR object id not valid");
697
698         if (m->params.meter_policy_id == meter_policy_id)
699                 return 0;
700
701         /* Meter policy must exist */
702         mp_new = softnic_mtr_meter_policy_find(p, meter_policy_id);
703         if (mp_new == NULL)
704                 return -rte_mtr_error_set(error,
705                         EINVAL,
706                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
707                         NULL,
708                         "Meter policy id invalid");
709
710         /* MTR object owner valid? */
711         if (m->flow) {
712                 struct pipeline *pipeline = m->flow->pipeline;
713                 struct softnic_table *table = &pipeline->table[m->flow->table_id];
714                 struct softnic_table_rule_action action;
715
716                 memcpy(&action, &m->flow->action, sizeof(action));
717
718                 /* Set action */
719                 for (i = 0; i < RTE_COLORS; i++)
720                         action.mtr.mtr[0].policer[i] = mp_new->policer[i];
721
722                 /* Re-add the rule */
723                 status = softnic_pipeline_table_rule_add(p,
724                         pipeline->name,
725                         m->flow->table_id,
726                         &m->flow->match,
727                         &action,
728                         &m->flow->data);
729                 if (status)
730                         return -rte_mtr_error_set(error,
731                                 EINVAL,
732                                 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
733                                 NULL,
734                                 "Pipeline table rule re-add failed");
735
736                 /* Flow: Update meter action */
737                 memcpy(&m->flow->action, &action, sizeof(m->flow->action));
738
739                 /* Reset the meter stats */
740                 rte_table_action_meter_read(table->a, m->flow->data,
741                         1, NULL, 1);
742         }
743
744         mp_old = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
745         if (mp_old == NULL)
746                 return -rte_mtr_error_set(error,
747                         EINVAL,
748                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
749                         NULL,
750                         "Old meter policy id invalid");
751
752         /* Meter: Set meter profile */
753         m->params.meter_policy_id = meter_policy_id;
754
755         /* Update dependencies*/
756         mp_old->n_users--;
757         mp_new->n_users++;
758
759         return 0;
760 }
761
762 #define MTR_STATS_PKTS_DEFAULT (RTE_MTR_STATS_N_PKTS_GREEN | \
763                                 RTE_MTR_STATS_N_PKTS_YELLOW | \
764                                 RTE_MTR_STATS_N_PKTS_RED | \
765                                 RTE_MTR_STATS_N_PKTS_DROPPED)
766
767 #define MTR_STATS_BYTES_DEFAULT (RTE_MTR_STATS_N_BYTES_GREEN | \
768                                 RTE_MTR_STATS_N_BYTES_YELLOW | \
769                                 RTE_MTR_STATS_N_BYTES_RED | \
770                                 RTE_MTR_STATS_N_BYTES_DROPPED)
771
772 /* MTR object stats read */
773 static void
774 mtr_stats_convert(struct pmd_internals *p,
775         struct softnic_mtr *m,
776         struct rte_table_action_mtr_counters_tc *in,
777         struct rte_mtr_stats *out,
778         uint64_t *out_mask)
779 {
780         struct softnic_mtr_meter_policy *mp;
781
782         memset(&out, 0, sizeof(out));
783         *out_mask = 0;
784
785         /* Meter policy must exist */
786         mp = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
787         if (mp == NULL)
788                 return;
789
790         if (in->n_packets_valid) {
791                 uint32_t i;
792
793                 for (i = 0; i < RTE_COLORS; i++) {
794                         if (mp->policer[i] ==
795                                 RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
796                                 out->n_pkts[RTE_COLOR_GREEN] += in->n_packets[i];
797
798                         if (mp->policer[i] ==
799                                 RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
800                                 out->n_pkts[RTE_COLOR_YELLOW] += in->n_packets[i];
801
802                         if (mp->policer[i] ==
803                                 RTE_TABLE_ACTION_POLICER_COLOR_RED)
804                                 out->n_pkts[RTE_COLOR_RED] += in->n_packets[i];
805
806                         if (mp->policer[i] ==
807                                 RTE_TABLE_ACTION_POLICER_DROP)
808                                 out->n_pkts_dropped += in->n_packets[i];
809                 }
810
811                 *out_mask |= MTR_STATS_PKTS_DEFAULT;
812         }
813
814         if (in->n_bytes_valid) {
815                 uint32_t i;
816
817                 for (i = 0; i < RTE_COLORS; i++) {
818                         if (mp->policer[i] ==
819                                 RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
820                                 out->n_bytes[RTE_COLOR_GREEN] += in->n_bytes[i];
821
822                         if (mp->policer[i] ==
823                                 RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
824                                 out->n_bytes[RTE_COLOR_YELLOW] += in->n_bytes[i];
825
826                         if (mp->policer[i] ==
827                                 RTE_TABLE_ACTION_POLICER_COLOR_RED)
828                                 out->n_bytes[RTE_COLOR_RED] += in->n_bytes[i];
829
830                         if (mp->policer[i] ==
831                                 RTE_TABLE_ACTION_POLICER_DROP)
832                                 out->n_bytes_dropped += in->n_bytes[i];
833                 }
834
835                 *out_mask |= MTR_STATS_BYTES_DEFAULT;
836         }
837 }
838
839 /* MTR object stats read */
840 static int
841 pmd_mtr_stats_read(struct rte_eth_dev *dev,
842         uint32_t mtr_id,
843         struct rte_mtr_stats *stats,
844         uint64_t *stats_mask,
845         int clear,
846         struct rte_mtr_error *error)
847 {
848         struct pmd_internals *p = dev->data->dev_private;
849         struct rte_table_action_mtr_counters counters;
850         struct pipeline *pipeline;
851         struct softnic_table *table;
852         struct softnic_mtr *m;
853         int status;
854
855         /* MTR object id must be valid */
856         m = softnic_mtr_find(p, mtr_id);
857         if (m == NULL)
858                 return -rte_mtr_error_set(error,
859                         EEXIST,
860                         RTE_MTR_ERROR_TYPE_MTR_ID,
861                         NULL,
862                         "MTR object id not valid");
863
864         /* MTR meter object owner valid? */
865         if (m->flow == NULL) {
866                 if (stats != NULL)
867                         memset(stats, 0, sizeof(*stats));
868
869                 if (stats_mask)
870                         *stats_mask = MTR_STATS_PKTS_DEFAULT |
871                                 MTR_STATS_BYTES_DEFAULT;
872
873                 return 0;
874         }
875
876         pipeline = m->flow->pipeline;
877         table = &pipeline->table[m->flow->table_id];
878
879         /* Meter stats read. */
880         status = rte_table_action_meter_read(table->a,
881                 m->flow->data,
882                 1,
883                 &counters,
884                 clear);
885         if (status)
886                 return -rte_mtr_error_set(error,
887                         EINVAL,
888                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
889                         NULL,
890                         "Meter stats read failed");
891
892         /* Stats format conversion. */
893         if (stats || stats_mask) {
894                 struct rte_mtr_stats s;
895                 uint64_t s_mask = 0;
896
897                 mtr_stats_convert(p,
898                         m,
899                         &counters.stats[0],
900                         &s,
901                         &s_mask);
902
903                 if (stats)
904                         memcpy(stats, &s, sizeof(*stats));
905
906                 if (stats_mask)
907                         *stats_mask = s_mask;
908         }
909
910         return 0;
911 }
912
913 const struct rte_mtr_ops pmd_mtr_ops = {
914         .capabilities_get = NULL,
915
916         .meter_profile_add = pmd_mtr_meter_profile_add,
917         .meter_profile_delete = pmd_mtr_meter_profile_delete,
918
919         .meter_policy_add = pmd_mtr_meter_policy_add,
920         .meter_policy_delete = pmd_mtr_meter_policy_delete,
921
922         .create = pmd_mtr_create,
923         .destroy = pmd_mtr_destroy,
924         .meter_enable = NULL,
925         .meter_disable = NULL,
926
927         .meter_profile_update = pmd_mtr_meter_profile_update,
928         .meter_dscp_table_update = pmd_mtr_meter_dscp_table_update,
929         .meter_policy_update = pmd_mtr_meter_policy_update,
930         .stats_update = NULL,
931
932         .stats_read = pmd_mtr_stats_read,
933 };