pipeline: add traffic manager action
[dpdk.git] / lib / librte_pipeline / rte_table_action.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <rte_common.h>
9 #include <rte_byteorder.h>
10 #include <rte_cycles.h>
11 #include <rte_malloc.h>
12 #include <rte_ip.h>
13
14
15 #include "rte_table_action.h"
16
17 #define rte_htons rte_cpu_to_be_16
18 #define rte_htonl rte_cpu_to_be_32
19
20 #define rte_ntohs rte_be_to_cpu_16
21 #define rte_ntohl rte_be_to_cpu_32
22
23 /**
24  * RTE_TABLE_ACTION_FWD
25  */
26 #define fwd_data rte_pipeline_table_entry
27
28 static int
29 fwd_apply(struct fwd_data *data,
30         struct rte_table_action_fwd_params *p)
31 {
32         data->action = p->action;
33
34         if (p->action == RTE_PIPELINE_ACTION_PORT)
35                 data->port_id = p->id;
36
37         if (p->action == RTE_PIPELINE_ACTION_TABLE)
38                 data->table_id = p->id;
39
40         return 0;
41 }
42
43 /**
44  * RTE_TABLE_ACTION_MTR
45  */
46 static int
47 mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
48 {
49         if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
50                 ((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
51                 (mtr->n_bytes_enabled != 0))
52                 return -ENOTSUP;
53         return 0;
54 }
55
56 #define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color)        \
57         ((uint16_t)((((uint64_t)(queue)) & 0x3) |          \
58         ((((uint64_t)(tc)) & 0x3) << 2) |                  \
59         ((((uint64_t)(color)) & 0x3) << 4)))
60
61 #define MBUF_SCHED_COLOR(sched, color)                     \
62         (((sched) & (~0x30LLU)) | ((color) << 4))
63
64 struct mtr_trtcm_data {
65         struct rte_meter_trtcm trtcm;
66         uint64_t stats[e_RTE_METER_COLORS];
67 } __attribute__((__packed__));
68
69 #define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
70         (((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
71
72 static void
73 mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
74         uint32_t profile_id)
75 {
76         data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
77         data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
78 }
79
80 #define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
81         (((data)->stats[(color)] & 4LLU) >> 2)
82
83 #define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
84         ((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
85
86 static void
87 mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
88         enum rte_meter_color color,
89         enum rte_table_action_policer action)
90 {
91         if (action == RTE_TABLE_ACTION_POLICER_DROP) {
92                 data->stats[color] |= 4LLU;
93         } else {
94                 data->stats[color] &= ~7LLU;
95                 data->stats[color] |= color & 3LLU;
96         }
97 }
98
99 static uint64_t
100 mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
101         enum rte_meter_color color)
102 {
103         return data->stats[color] >> 8;
104 }
105
106 static void
107 mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
108         enum rte_meter_color color)
109 {
110         data->stats[color] &= 0xFFLU;
111 }
112
113 #define MTR_TRTCM_DATA_STATS_INC(data, color)              \
114         ((data)->stats[(color)] += (1LLU << 8))
115
116 static size_t
117 mtr_data_size(struct rte_table_action_mtr_config *mtr)
118 {
119         return mtr->n_tc * sizeof(struct mtr_trtcm_data);
120 }
121
122 struct dscp_table_entry_data {
123         enum rte_meter_color color;
124         uint16_t tc;
125         uint16_t queue_tc_color;
126 };
127
128 struct dscp_table_data {
129         struct dscp_table_entry_data entry[64];
130 };
131
132 struct meter_profile_data {
133         struct rte_meter_trtcm_profile profile;
134         uint32_t profile_id;
135         int valid;
136 };
137
138 static struct meter_profile_data *
139 meter_profile_data_find(struct meter_profile_data *mp,
140         uint32_t mp_size,
141         uint32_t profile_id)
142 {
143         uint32_t i;
144
145         for (i = 0; i < mp_size; i++) {
146                 struct meter_profile_data *mp_data = &mp[i];
147
148                 if (mp_data->valid && (mp_data->profile_id == profile_id))
149                         return mp_data;
150         }
151
152         return NULL;
153 }
154
155 static struct meter_profile_data *
156 meter_profile_data_find_unused(struct meter_profile_data *mp,
157         uint32_t mp_size)
158 {
159         uint32_t i;
160
161         for (i = 0; i < mp_size; i++) {
162                 struct meter_profile_data *mp_data = &mp[i];
163
164                 if (!mp_data->valid)
165                         return mp_data;
166         }
167
168         return NULL;
169 }
170
171 static int
172 mtr_apply_check(struct rte_table_action_mtr_params *p,
173         struct rte_table_action_mtr_config *cfg,
174         struct meter_profile_data *mp,
175         uint32_t mp_size)
176 {
177         uint32_t i;
178
179         if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
180                 return -EINVAL;
181
182         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
183                 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
184                 struct meter_profile_data *mp_data;
185
186                 if ((p->tc_mask & (1LLU << i)) == 0)
187                         continue;
188
189                 mp_data = meter_profile_data_find(mp,
190                         mp_size,
191                         p_tc->meter_profile_id);
192                 if (!mp_data)
193                         return -EINVAL;
194         }
195
196         return 0;
197 }
198
199 static int
200 mtr_apply(struct mtr_trtcm_data *data,
201         struct rte_table_action_mtr_params *p,
202         struct rte_table_action_mtr_config *cfg,
203         struct meter_profile_data *mp,
204         uint32_t mp_size)
205 {
206         uint32_t i;
207         int status;
208
209         /* Check input arguments */
210         status = mtr_apply_check(p, cfg, mp, mp_size);
211         if (status)
212                 return status;
213
214         /* Apply */
215         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
216                 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
217                 struct mtr_trtcm_data *data_tc = &data[i];
218                 struct meter_profile_data *mp_data;
219
220                 if ((p->tc_mask & (1LLU << i)) == 0)
221                         continue;
222
223                 /* Find profile */
224                 mp_data = meter_profile_data_find(mp,
225                         mp_size,
226                         p_tc->meter_profile_id);
227                 if (!mp_data)
228                         return -EINVAL;
229
230                 memset(data_tc, 0, sizeof(*data_tc));
231
232                 /* Meter object */
233                 status = rte_meter_trtcm_config(&data_tc->trtcm,
234                         &mp_data->profile);
235                 if (status)
236                         return status;
237
238                 /* Meter profile */
239                 mtr_trtcm_data_meter_profile_id_set(data_tc,
240                         mp_data - mp);
241
242                 /* Policer actions */
243                 mtr_trtcm_data_policer_action_set(data_tc,
244                         e_RTE_METER_GREEN,
245                         p_tc->policer[e_RTE_METER_GREEN]);
246
247                 mtr_trtcm_data_policer_action_set(data_tc,
248                         e_RTE_METER_YELLOW,
249                         p_tc->policer[e_RTE_METER_YELLOW]);
250
251                 mtr_trtcm_data_policer_action_set(data_tc,
252                         e_RTE_METER_RED,
253                         p_tc->policer[e_RTE_METER_RED]);
254         }
255
256         return 0;
257 }
258
259 static __rte_always_inline uint64_t
260 pkt_work_mtr(struct rte_mbuf *mbuf,
261         struct mtr_trtcm_data *data,
262         struct dscp_table_data *dscp_table,
263         struct meter_profile_data *mp,
264         uint64_t time,
265         uint32_t dscp,
266         uint16_t total_length)
267 {
268         uint64_t drop_mask, sched;
269         uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
270         struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
271         enum rte_meter_color color_in, color_meter, color_policer;
272         uint32_t tc, mp_id;
273
274         tc = dscp_entry->tc;
275         color_in = dscp_entry->color;
276         data += tc;
277         mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
278         sched = *sched_ptr;
279
280         /* Meter */
281         color_meter = rte_meter_trtcm_color_aware_check(
282                 &data->trtcm,
283                 &mp[mp_id].profile,
284                 time,
285                 total_length,
286                 color_in);
287
288         /* Stats */
289         MTR_TRTCM_DATA_STATS_INC(data, color_meter);
290
291         /* Police */
292         drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
293         color_policer =
294                 MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
295         *sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
296
297         return drop_mask;
298 }
299
300 /**
301  * RTE_TABLE_ACTION_TM
302  */
303 static int
304 tm_cfg_check(struct rte_table_action_tm_config *tm)
305 {
306         if ((tm->n_subports_per_port == 0) ||
307                 (rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
308                 (tm->n_subports_per_port > UINT16_MAX) ||
309                 (tm->n_pipes_per_subport == 0) ||
310                 (rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
311                 return -ENOTSUP;
312
313         return 0;
314 }
315
316 struct tm_data {
317         uint16_t queue_tc_color;
318         uint16_t subport;
319         uint32_t pipe;
320 } __attribute__((__packed__));
321
322 static int
323 tm_apply_check(struct rte_table_action_tm_params *p,
324         struct rte_table_action_tm_config *cfg)
325 {
326         if ((p->subport_id >= cfg->n_subports_per_port) ||
327                 (p->pipe_id >= cfg->n_pipes_per_subport))
328                 return -EINVAL;
329
330         return 0;
331 }
332
333 static int
334 tm_apply(struct tm_data *data,
335         struct rte_table_action_tm_params *p,
336         struct rte_table_action_tm_config *cfg)
337 {
338         int status;
339
340         /* Check input arguments */
341         status = tm_apply_check(p, cfg);
342         if (status)
343                 return status;
344
345         /* Apply */
346         data->queue_tc_color = 0;
347         data->subport = (uint16_t) p->subport_id;
348         data->pipe = p->pipe_id;
349
350         return 0;
351 }
352
353 static __rte_always_inline void
354 pkt_work_tm(struct rte_mbuf *mbuf,
355         struct tm_data *data,
356         struct dscp_table_data *dscp_table,
357         uint32_t dscp)
358 {
359         struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
360         struct tm_data *sched_ptr = (struct tm_data *) &mbuf->hash.sched;
361         struct tm_data sched;
362
363         sched = *data;
364         sched.queue_tc_color = dscp_entry->queue_tc_color;
365         *sched_ptr = sched;
366 }
367
368 /**
369  * Action profile
370  */
371 static int
372 action_valid(enum rte_table_action_type action)
373 {
374         switch (action) {
375         case RTE_TABLE_ACTION_FWD:
376         case RTE_TABLE_ACTION_MTR:
377         case RTE_TABLE_ACTION_TM:
378                 return 1;
379         default:
380                 return 0;
381         }
382 }
383
384
385 #define RTE_TABLE_ACTION_MAX                      64
386
387 struct ap_config {
388         uint64_t action_mask;
389         struct rte_table_action_common_config common;
390         struct rte_table_action_mtr_config mtr;
391         struct rte_table_action_tm_config tm;
392 };
393
394 static size_t
395 action_cfg_size(enum rte_table_action_type action)
396 {
397         switch (action) {
398         case RTE_TABLE_ACTION_MTR:
399                 return sizeof(struct rte_table_action_mtr_config);
400         case RTE_TABLE_ACTION_TM:
401                 return sizeof(struct rte_table_action_tm_config);
402         default:
403                 return 0;
404         }
405 }
406
407 static void*
408 action_cfg_get(struct ap_config *ap_config,
409         enum rte_table_action_type type)
410 {
411         switch (type) {
412         case RTE_TABLE_ACTION_MTR:
413                 return &ap_config->mtr;
414
415         case RTE_TABLE_ACTION_TM:
416                 return &ap_config->tm;
417
418         default:
419                 return NULL;
420         }
421 }
422
423 static void
424 action_cfg_set(struct ap_config *ap_config,
425         enum rte_table_action_type type,
426         void *action_cfg)
427 {
428         void *dst = action_cfg_get(ap_config, type);
429
430         if (dst)
431                 memcpy(dst, action_cfg, action_cfg_size(type));
432
433         ap_config->action_mask |= 1LLU << type;
434 }
435
436 struct ap_data {
437         size_t offset[RTE_TABLE_ACTION_MAX];
438         size_t total_size;
439 };
440
441 static size_t
442 action_data_size(enum rte_table_action_type action,
443         struct ap_config *ap_config)
444 {
445         switch (action) {
446         case RTE_TABLE_ACTION_FWD:
447                 return sizeof(struct fwd_data);
448
449         case RTE_TABLE_ACTION_MTR:
450                 return mtr_data_size(&ap_config->mtr);
451
452         case RTE_TABLE_ACTION_TM:
453                 return sizeof(struct tm_data);
454
455         default:
456                 return 0;
457         }
458 }
459
460
461 static void
462 action_data_offset_set(struct ap_data *ap_data,
463         struct ap_config *ap_config)
464 {
465         uint64_t action_mask = ap_config->action_mask;
466         size_t offset;
467         uint32_t action;
468
469         memset(ap_data->offset, 0, sizeof(ap_data->offset));
470
471         offset = 0;
472         for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
473                 if (action_mask & (1LLU << action)) {
474                         ap_data->offset[action] = offset;
475                         offset += action_data_size((enum rte_table_action_type)action,
476                                 ap_config);
477                 }
478
479         ap_data->total_size = offset;
480 }
481
482 struct rte_table_action_profile {
483         struct ap_config cfg;
484         struct ap_data data;
485         int frozen;
486 };
487
488 struct rte_table_action_profile *
489 rte_table_action_profile_create(struct rte_table_action_common_config *common)
490 {
491         struct rte_table_action_profile *ap;
492
493         /* Check input arguments */
494         if (common == NULL)
495                 return NULL;
496
497         /* Memory allocation */
498         ap = calloc(1, sizeof(struct rte_table_action_profile));
499         if (ap == NULL)
500                 return NULL;
501
502         /* Initialization */
503         memcpy(&ap->cfg.common, common, sizeof(*common));
504
505         return ap;
506 }
507
508
509 int
510 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
511         enum rte_table_action_type type,
512         void *action_config)
513 {
514         int status;
515
516         /* Check input arguments */
517         if ((profile == NULL) ||
518                 profile->frozen ||
519                 (action_valid(type) == 0) ||
520                 (profile->cfg.action_mask & (1LLU << type)) ||
521                 ((action_cfg_size(type) == 0) && action_config) ||
522                 (action_cfg_size(type) && (action_config == NULL)))
523                 return -EINVAL;
524
525         switch (type) {
526         case RTE_TABLE_ACTION_MTR:
527                 status = mtr_cfg_check(action_config);
528                 break;
529
530         case RTE_TABLE_ACTION_TM:
531                 status = tm_cfg_check(action_config);
532                 break;
533
534         default:
535                 status = 0;
536                 break;
537         }
538
539         if (status)
540                 return status;
541
542         /* Action enable */
543         action_cfg_set(&profile->cfg, type, action_config);
544
545         return 0;
546 }
547
548 int
549 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
550 {
551         if (profile->frozen)
552                 return -EBUSY;
553
554         profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
555         action_data_offset_set(&profile->data, &profile->cfg);
556         profile->frozen = 1;
557
558         return 0;
559 }
560
561 int
562 rte_table_action_profile_free(struct rte_table_action_profile *profile)
563 {
564         if (profile == NULL)
565                 return 0;
566
567         free(profile);
568         return 0;
569 }
570
571 /**
572  * Action
573  */
574 #define METER_PROFILES_MAX                                 32
575
576 struct rte_table_action {
577         struct ap_config cfg;
578         struct ap_data data;
579         struct dscp_table_data dscp_table;
580         struct meter_profile_data mp[METER_PROFILES_MAX];
581 };
582
583 struct rte_table_action *
584 rte_table_action_create(struct rte_table_action_profile *profile,
585         uint32_t socket_id)
586 {
587         struct rte_table_action *action;
588
589         /* Check input arguments */
590         if ((profile == NULL) ||
591                 (profile->frozen == 0))
592                 return NULL;
593
594         /* Memory allocation */
595         action = rte_zmalloc_socket(NULL,
596                 sizeof(struct rte_table_action),
597                 RTE_CACHE_LINE_SIZE,
598                 socket_id);
599         if (action == NULL)
600                 return NULL;
601
602         /* Initialization */
603         memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
604         memcpy(&action->data, &profile->data, sizeof(profile->data));
605
606         return action;
607 }
608
609 static __rte_always_inline void *
610 action_data_get(void *data,
611         struct rte_table_action *action,
612         enum rte_table_action_type type)
613 {
614         size_t offset = action->data.offset[type];
615         uint8_t *data_bytes = data;
616
617         return &data_bytes[offset];
618 }
619
620 int
621 rte_table_action_apply(struct rte_table_action *action,
622         void *data,
623         enum rte_table_action_type type,
624         void *action_params)
625 {
626         void *action_data;
627
628         /* Check input arguments */
629         if ((action == NULL) ||
630                 (data == NULL) ||
631                 (action_valid(type) == 0) ||
632                 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
633                 (action_params == NULL))
634                 return -EINVAL;
635
636         /* Data update */
637         action_data = action_data_get(data, action, type);
638
639         switch (type) {
640         case RTE_TABLE_ACTION_FWD:
641                 return fwd_apply(action_data,
642                         action_params);
643
644         case RTE_TABLE_ACTION_MTR:
645                 return mtr_apply(action_data,
646                         action_params,
647                         &action->cfg.mtr,
648                         action->mp,
649                         RTE_DIM(action->mp));
650
651         case RTE_TABLE_ACTION_TM:
652                 return tm_apply(action_data,
653                         action_params,
654                         &action->cfg.tm);
655
656         default:
657                 return -EINVAL;
658         }
659 }
660
661 int
662 rte_table_action_dscp_table_update(struct rte_table_action *action,
663         uint64_t dscp_mask,
664         struct rte_table_action_dscp_table *table)
665 {
666         uint32_t i;
667
668         /* Check input arguments */
669         if ((action == NULL) ||
670                 ((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
671                 (1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
672                 (dscp_mask == 0) ||
673                 (table == NULL))
674                 return -EINVAL;
675
676         for (i = 0; i < RTE_DIM(table->entry); i++) {
677                 struct dscp_table_entry_data *data =
678                         &action->dscp_table.entry[i];
679                 struct rte_table_action_dscp_table_entry *entry =
680                         &table->entry[i];
681                 uint16_t queue_tc_color =
682                         MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
683                                 entry->tc_id,
684                                 entry->color);
685
686                 if ((dscp_mask & (1LLU << i)) == 0)
687                         continue;
688
689                 data->color = entry->color;
690                 data->tc = entry->tc_id;
691                 data->queue_tc_color = queue_tc_color;
692         }
693
694         return 0;
695 }
696
697 int
698 rte_table_action_meter_profile_add(struct rte_table_action *action,
699         uint32_t meter_profile_id,
700         struct rte_table_action_meter_profile *profile)
701 {
702         struct meter_profile_data *mp_data;
703         uint32_t status;
704
705         /* Check input arguments */
706         if ((action == NULL) ||
707                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
708                 (profile == NULL))
709                 return -EINVAL;
710
711         if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
712                 return -ENOTSUP;
713
714         mp_data = meter_profile_data_find(action->mp,
715                 RTE_DIM(action->mp),
716                 meter_profile_id);
717         if (mp_data)
718                 return -EEXIST;
719
720         mp_data = meter_profile_data_find_unused(action->mp,
721                 RTE_DIM(action->mp));
722         if (!mp_data)
723                 return -ENOSPC;
724
725         /* Install new profile */
726         status = rte_meter_trtcm_profile_config(&mp_data->profile,
727                 &profile->trtcm);
728         if (status)
729                 return status;
730
731         mp_data->profile_id = meter_profile_id;
732         mp_data->valid = 1;
733
734         return 0;
735 }
736
737 int
738 rte_table_action_meter_profile_delete(struct rte_table_action *action,
739         uint32_t meter_profile_id)
740 {
741         struct meter_profile_data *mp_data;
742
743         /* Check input arguments */
744         if ((action == NULL) ||
745                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
746                 return -EINVAL;
747
748         mp_data = meter_profile_data_find(action->mp,
749                 RTE_DIM(action->mp),
750                 meter_profile_id);
751         if (!mp_data)
752                 return 0;
753
754         /* Uninstall profile */
755         mp_data->valid = 0;
756
757         return 0;
758 }
759
760 int
761 rte_table_action_meter_read(struct rte_table_action *action,
762         void *data,
763         uint32_t tc_mask,
764         struct rte_table_action_mtr_counters *stats,
765         int clear)
766 {
767         struct mtr_trtcm_data *mtr_data;
768         uint32_t i;
769
770         /* Check input arguments */
771         if ((action == NULL) ||
772                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
773                 (data == NULL) ||
774                 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
775                 return -EINVAL;
776
777         mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
778
779         /* Read */
780         if (stats) {
781                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
782                         struct rte_table_action_mtr_counters_tc *dst =
783                                 &stats->stats[i];
784                         struct mtr_trtcm_data *src = &mtr_data[i];
785
786                         if ((tc_mask & (1 << i)) == 0)
787                                 continue;
788
789                         dst->n_packets[e_RTE_METER_GREEN] =
790                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
791
792                         dst->n_packets[e_RTE_METER_YELLOW] =
793                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
794
795                         dst->n_packets[e_RTE_METER_RED] =
796                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
797
798                         dst->n_packets_valid = 1;
799                         dst->n_bytes_valid = 0;
800                 }
801
802                 stats->tc_mask = tc_mask;
803         }
804
805         /* Clear */
806         if (clear)
807                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
808                         struct mtr_trtcm_data *src = &mtr_data[i];
809
810                         if ((tc_mask & (1 << i)) == 0)
811                                 continue;
812
813                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
814                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
815                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
816                 }
817
818
819         return 0;
820 }
821
822 static __rte_always_inline uint64_t
823 pkt_work(struct rte_mbuf *mbuf,
824         struct rte_pipeline_table_entry *table_entry,
825         uint64_t time,
826         struct rte_table_action *action,
827         struct ap_config *cfg)
828 {
829         uint64_t drop_mask = 0;
830
831         uint32_t ip_offset = action->cfg.common.ip_offset;
832         void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
833
834         uint32_t dscp;
835         uint16_t total_length;
836
837         if (cfg->common.ip_version) {
838                 struct ipv4_hdr *hdr = ip;
839
840                 dscp = hdr->type_of_service >> 2;
841                 total_length = rte_ntohs(hdr->total_length);
842         } else {
843                 struct ipv6_hdr *hdr = ip;
844
845                 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
846                 total_length =
847                         rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
848         }
849
850         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
851                 void *data =
852                         action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
853
854                 drop_mask |= pkt_work_mtr(mbuf,
855                         data,
856                         &action->dscp_table,
857                         action->mp,
858                         time,
859                         dscp,
860                         total_length);
861         }
862
863         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
864                 void *data =
865                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
866
867                 pkt_work_tm(mbuf,
868                         data,
869                         &action->dscp_table,
870                         dscp);
871         }
872
873         return drop_mask;
874 }
875
876 static __rte_always_inline uint64_t
877 pkt4_work(struct rte_mbuf **mbufs,
878         struct rte_pipeline_table_entry **table_entries,
879         uint64_t time,
880         struct rte_table_action *action,
881         struct ap_config *cfg)
882 {
883         uint64_t drop_mask0 = 0;
884         uint64_t drop_mask1 = 0;
885         uint64_t drop_mask2 = 0;
886         uint64_t drop_mask3 = 0;
887
888         struct rte_mbuf *mbuf0 = mbufs[0];
889         struct rte_mbuf *mbuf1 = mbufs[1];
890         struct rte_mbuf *mbuf2 = mbufs[2];
891         struct rte_mbuf *mbuf3 = mbufs[3];
892
893         struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
894         struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
895         struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
896         struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
897
898         uint32_t ip_offset = action->cfg.common.ip_offset;
899         void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
900         void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
901         void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
902         void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
903
904         uint32_t dscp0, dscp1, dscp2, dscp3;
905         uint16_t total_length0, total_length1, total_length2, total_length3;
906
907         if (cfg->common.ip_version) {
908                 struct ipv4_hdr *hdr0 = ip0;
909                 struct ipv4_hdr *hdr1 = ip1;
910                 struct ipv4_hdr *hdr2 = ip2;
911                 struct ipv4_hdr *hdr3 = ip3;
912
913                 dscp0 = hdr0->type_of_service >> 2;
914                 dscp1 = hdr1->type_of_service >> 2;
915                 dscp2 = hdr2->type_of_service >> 2;
916                 dscp3 = hdr3->type_of_service >> 2;
917
918                 total_length0 = rte_ntohs(hdr0->total_length);
919                 total_length1 = rte_ntohs(hdr1->total_length);
920                 total_length2 = rte_ntohs(hdr2->total_length);
921                 total_length3 = rte_ntohs(hdr3->total_length);
922         } else {
923                 struct ipv6_hdr *hdr0 = ip0;
924                 struct ipv6_hdr *hdr1 = ip1;
925                 struct ipv6_hdr *hdr2 = ip2;
926                 struct ipv6_hdr *hdr3 = ip3;
927
928                 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
929                 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
930                 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
931                 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
932
933                 total_length0 =
934                         rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
935                 total_length1 =
936                         rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
937                 total_length2 =
938                         rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
939                 total_length3 =
940                         rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
941         }
942
943         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
944                 void *data0 =
945                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
946                 void *data1 =
947                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
948                 void *data2 =
949                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
950                 void *data3 =
951                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
952
953                 drop_mask0 |= pkt_work_mtr(mbuf0,
954                         data0,
955                         &action->dscp_table,
956                         action->mp,
957                         time,
958                         dscp0,
959                         total_length0);
960
961                 drop_mask1 |= pkt_work_mtr(mbuf1,
962                         data1,
963                         &action->dscp_table,
964                         action->mp,
965                         time,
966                         dscp1,
967                         total_length1);
968
969                 drop_mask2 |= pkt_work_mtr(mbuf2,
970                         data2,
971                         &action->dscp_table,
972                         action->mp,
973                         time,
974                         dscp2,
975                         total_length2);
976
977                 drop_mask3 |= pkt_work_mtr(mbuf3,
978                         data3,
979                         &action->dscp_table,
980                         action->mp,
981                         time,
982                         dscp3,
983                         total_length3);
984         }
985
986         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
987                 void *data0 =
988                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
989                 void *data1 =
990                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
991                 void *data2 =
992                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
993                 void *data3 =
994                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
995
996                 pkt_work_tm(mbuf0,
997                         data0,
998                         &action->dscp_table,
999                         dscp0);
1000
1001                 pkt_work_tm(mbuf1,
1002                         data1,
1003                         &action->dscp_table,
1004                         dscp1);
1005
1006                 pkt_work_tm(mbuf2,
1007                         data2,
1008                         &action->dscp_table,
1009                         dscp2);
1010
1011                 pkt_work_tm(mbuf3,
1012                         data3,
1013                         &action->dscp_table,
1014                         dscp3);
1015         }
1016
1017         return drop_mask0 |
1018                 (drop_mask1 << 1) |
1019                 (drop_mask2 << 2) |
1020                 (drop_mask3 << 3);
1021 }
1022
1023 static __rte_always_inline int
1024 ah(struct rte_pipeline *p,
1025         struct rte_mbuf **pkts,
1026         uint64_t pkts_mask,
1027         struct rte_pipeline_table_entry **entries,
1028         struct rte_table_action *action,
1029         struct ap_config *cfg)
1030 {
1031         uint64_t pkts_drop_mask = 0;
1032         uint64_t time = 0;
1033
1034         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
1035                 time = rte_rdtsc();
1036
1037         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1038                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1039                 uint32_t i;
1040
1041                 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
1042                         uint64_t drop_mask;
1043
1044                         drop_mask = pkt4_work(&pkts[i],
1045                                 &entries[i],
1046                                 time,
1047                                 action,
1048                                 cfg);
1049
1050                         pkts_drop_mask |= drop_mask << i;
1051                 }
1052
1053                 for ( ; i < n_pkts; i++) {
1054                         uint64_t drop_mask;
1055
1056                         drop_mask = pkt_work(pkts[i],
1057                                 entries[i],
1058                                 time,
1059                                 action,
1060                                 cfg);
1061
1062                         pkts_drop_mask |= drop_mask << i;
1063                 }
1064         } else
1065                 for ( ; pkts_mask; ) {
1066                         uint32_t pos = __builtin_ctzll(pkts_mask);
1067                         uint64_t pkt_mask = 1LLU << pos;
1068                         uint64_t drop_mask;
1069
1070                         drop_mask = pkt_work(pkts[pos],
1071                                 entries[pos],
1072                                 time,
1073                                 action,
1074                                 cfg);
1075
1076                         pkts_mask &= ~pkt_mask;
1077                         pkts_drop_mask |= drop_mask << pos;
1078                 }
1079
1080         rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
1081
1082         return 0;
1083 }
1084
1085 static int
1086 ah_default(struct rte_pipeline *p,
1087         struct rte_mbuf **pkts,
1088         uint64_t pkts_mask,
1089         struct rte_pipeline_table_entry **entries,
1090         void *arg)
1091 {
1092         struct rte_table_action *action = arg;
1093
1094         return ah(p,
1095                 pkts,
1096                 pkts_mask,
1097                 entries,
1098                 action,
1099                 &action->cfg);
1100 }
1101
1102 static rte_pipeline_table_action_handler_hit
1103 ah_selector(struct rte_table_action *action)
1104 {
1105         if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
1106                 return NULL;
1107
1108         return ah_default;
1109 }
1110
1111 int
1112 rte_table_action_table_params_get(struct rte_table_action *action,
1113         struct rte_pipeline_table_params *params)
1114 {
1115         rte_pipeline_table_action_handler_hit f_action_hit;
1116         uint32_t total_size;
1117
1118         /* Check input arguments */
1119         if ((action == NULL) ||
1120                 (params == NULL))
1121                 return -EINVAL;
1122
1123         f_action_hit = ah_selector(action);
1124         total_size = rte_align32pow2(action->data.total_size);
1125
1126         /* Fill in params */
1127         params->f_action_hit = f_action_hit;
1128         params->f_action_miss = NULL;
1129         params->arg_ah = (f_action_hit) ? action : NULL;
1130         params->action_data_size = total_size -
1131                 sizeof(struct rte_pipeline_table_entry);
1132
1133         return 0;
1134 }
1135
1136 int
1137 rte_table_action_free(struct rte_table_action *action)
1138 {
1139         if (action == NULL)
1140                 return 0;
1141
1142         rte_free(action);
1143
1144         return 0;
1145 }