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