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