pipeline: add traffic metering 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 /**
302  * Action profile
303  */
304 static int
305 action_valid(enum rte_table_action_type action)
306 {
307         switch (action) {
308         case RTE_TABLE_ACTION_FWD:
309         case RTE_TABLE_ACTION_MTR:
310                 return 1;
311         default:
312                 return 0;
313         }
314 }
315
316
317 #define RTE_TABLE_ACTION_MAX                      64
318
319 struct ap_config {
320         uint64_t action_mask;
321         struct rte_table_action_common_config common;
322         struct rte_table_action_mtr_config mtr;
323 };
324
325 static size_t
326 action_cfg_size(enum rte_table_action_type action)
327 {
328         switch (action) {
329         case RTE_TABLE_ACTION_MTR:
330                 return sizeof(struct rte_table_action_mtr_config);
331         default:
332                 return 0;
333         }
334 }
335
336 static void*
337 action_cfg_get(struct ap_config *ap_config,
338         enum rte_table_action_type type)
339 {
340         switch (type) {
341         case RTE_TABLE_ACTION_MTR:
342                 return &ap_config->mtr;
343
344         default:
345                 return NULL;
346         }
347 }
348
349 static void
350 action_cfg_set(struct ap_config *ap_config,
351         enum rte_table_action_type type,
352         void *action_cfg)
353 {
354         void *dst = action_cfg_get(ap_config, type);
355
356         if (dst)
357                 memcpy(dst, action_cfg, action_cfg_size(type));
358
359         ap_config->action_mask |= 1LLU << type;
360 }
361
362 struct ap_data {
363         size_t offset[RTE_TABLE_ACTION_MAX];
364         size_t total_size;
365 };
366
367 static size_t
368 action_data_size(enum rte_table_action_type action,
369         struct ap_config *ap_config)
370 {
371         switch (action) {
372         case RTE_TABLE_ACTION_FWD:
373                 return sizeof(struct fwd_data);
374
375         case RTE_TABLE_ACTION_MTR:
376                 return mtr_data_size(&ap_config->mtr);
377
378         default:
379                 return 0;
380         }
381 }
382
383
384 static void
385 action_data_offset_set(struct ap_data *ap_data,
386         struct ap_config *ap_config)
387 {
388         uint64_t action_mask = ap_config->action_mask;
389         size_t offset;
390         uint32_t action;
391
392         memset(ap_data->offset, 0, sizeof(ap_data->offset));
393
394         offset = 0;
395         for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
396                 if (action_mask & (1LLU << action)) {
397                         ap_data->offset[action] = offset;
398                         offset += action_data_size((enum rte_table_action_type)action,
399                                 ap_config);
400                 }
401
402         ap_data->total_size = offset;
403 }
404
405 struct rte_table_action_profile {
406         struct ap_config cfg;
407         struct ap_data data;
408         int frozen;
409 };
410
411 struct rte_table_action_profile *
412 rte_table_action_profile_create(struct rte_table_action_common_config *common)
413 {
414         struct rte_table_action_profile *ap;
415
416         /* Check input arguments */
417         if (common == NULL)
418                 return NULL;
419
420         /* Memory allocation */
421         ap = calloc(1, sizeof(struct rte_table_action_profile));
422         if (ap == NULL)
423                 return NULL;
424
425         /* Initialization */
426         memcpy(&ap->cfg.common, common, sizeof(*common));
427
428         return ap;
429 }
430
431
432 int
433 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
434         enum rte_table_action_type type,
435         void *action_config)
436 {
437         int status;
438
439         /* Check input arguments */
440         if ((profile == NULL) ||
441                 profile->frozen ||
442                 (action_valid(type) == 0) ||
443                 (profile->cfg.action_mask & (1LLU << type)) ||
444                 ((action_cfg_size(type) == 0) && action_config) ||
445                 (action_cfg_size(type) && (action_config == NULL)))
446                 return -EINVAL;
447
448         switch (type) {
449         case RTE_TABLE_ACTION_MTR:
450                 status = mtr_cfg_check(action_config);
451                 break;
452
453         default:
454                 status = 0;
455                 break;
456         }
457
458         if (status)
459                 return status;
460
461         /* Action enable */
462         action_cfg_set(&profile->cfg, type, action_config);
463
464         return 0;
465 }
466
467 int
468 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
469 {
470         if (profile->frozen)
471                 return -EBUSY;
472
473         profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
474         action_data_offset_set(&profile->data, &profile->cfg);
475         profile->frozen = 1;
476
477         return 0;
478 }
479
480 int
481 rte_table_action_profile_free(struct rte_table_action_profile *profile)
482 {
483         if (profile == NULL)
484                 return 0;
485
486         free(profile);
487         return 0;
488 }
489
490 /**
491  * Action
492  */
493 #define METER_PROFILES_MAX                                 32
494
495 struct rte_table_action {
496         struct ap_config cfg;
497         struct ap_data data;
498         struct dscp_table_data dscp_table;
499         struct meter_profile_data mp[METER_PROFILES_MAX];
500 };
501
502 struct rte_table_action *
503 rte_table_action_create(struct rte_table_action_profile *profile,
504         uint32_t socket_id)
505 {
506         struct rte_table_action *action;
507
508         /* Check input arguments */
509         if ((profile == NULL) ||
510                 (profile->frozen == 0))
511                 return NULL;
512
513         /* Memory allocation */
514         action = rte_zmalloc_socket(NULL,
515                 sizeof(struct rte_table_action),
516                 RTE_CACHE_LINE_SIZE,
517                 socket_id);
518         if (action == NULL)
519                 return NULL;
520
521         /* Initialization */
522         memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
523         memcpy(&action->data, &profile->data, sizeof(profile->data));
524
525         return action;
526 }
527
528 static __rte_always_inline void *
529 action_data_get(void *data,
530         struct rte_table_action *action,
531         enum rte_table_action_type type)
532 {
533         size_t offset = action->data.offset[type];
534         uint8_t *data_bytes = data;
535
536         return &data_bytes[offset];
537 }
538
539 int
540 rte_table_action_apply(struct rte_table_action *action,
541         void *data,
542         enum rte_table_action_type type,
543         void *action_params)
544 {
545         void *action_data;
546
547         /* Check input arguments */
548         if ((action == NULL) ||
549                 (data == NULL) ||
550                 (action_valid(type) == 0) ||
551                 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
552                 (action_params == NULL))
553                 return -EINVAL;
554
555         /* Data update */
556         action_data = action_data_get(data, action, type);
557
558         switch (type) {
559         case RTE_TABLE_ACTION_FWD:
560                 return fwd_apply(action_data,
561                         action_params);
562
563         case RTE_TABLE_ACTION_MTR:
564                 return mtr_apply(action_data,
565                         action_params,
566                         &action->cfg.mtr,
567                         action->mp,
568                         RTE_DIM(action->mp));
569
570         default:
571                 return -EINVAL;
572         }
573 }
574
575 int
576 rte_table_action_dscp_table_update(struct rte_table_action *action,
577         uint64_t dscp_mask,
578         struct rte_table_action_dscp_table *table)
579 {
580         uint32_t i;
581
582         /* Check input arguments */
583         if ((action == NULL) ||
584                 (action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
585                 (dscp_mask == 0) ||
586                 (table == NULL))
587                 return -EINVAL;
588
589         for (i = 0; i < RTE_DIM(table->entry); i++) {
590                 struct dscp_table_entry_data *data =
591                         &action->dscp_table.entry[i];
592                 struct rte_table_action_dscp_table_entry *entry =
593                         &table->entry[i];
594                 uint16_t queue_tc_color =
595                         MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
596                                 entry->tc_id,
597                                 entry->color);
598
599                 if ((dscp_mask & (1LLU << i)) == 0)
600                         continue;
601
602                 data->color = entry->color;
603                 data->tc = entry->tc_id;
604                 data->queue_tc_color = queue_tc_color;
605         }
606
607         return 0;
608 }
609
610 int
611 rte_table_action_meter_profile_add(struct rte_table_action *action,
612         uint32_t meter_profile_id,
613         struct rte_table_action_meter_profile *profile)
614 {
615         struct meter_profile_data *mp_data;
616         uint32_t status;
617
618         /* Check input arguments */
619         if ((action == NULL) ||
620                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
621                 (profile == NULL))
622                 return -EINVAL;
623
624         if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
625                 return -ENOTSUP;
626
627         mp_data = meter_profile_data_find(action->mp,
628                 RTE_DIM(action->mp),
629                 meter_profile_id);
630         if (mp_data)
631                 return -EEXIST;
632
633         mp_data = meter_profile_data_find_unused(action->mp,
634                 RTE_DIM(action->mp));
635         if (!mp_data)
636                 return -ENOSPC;
637
638         /* Install new profile */
639         status = rte_meter_trtcm_profile_config(&mp_data->profile,
640                 &profile->trtcm);
641         if (status)
642                 return status;
643
644         mp_data->profile_id = meter_profile_id;
645         mp_data->valid = 1;
646
647         return 0;
648 }
649
650 int
651 rte_table_action_meter_profile_delete(struct rte_table_action *action,
652         uint32_t meter_profile_id)
653 {
654         struct meter_profile_data *mp_data;
655
656         /* Check input arguments */
657         if ((action == NULL) ||
658                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
659                 return -EINVAL;
660
661         mp_data = meter_profile_data_find(action->mp,
662                 RTE_DIM(action->mp),
663                 meter_profile_id);
664         if (!mp_data)
665                 return 0;
666
667         /* Uninstall profile */
668         mp_data->valid = 0;
669
670         return 0;
671 }
672
673 int
674 rte_table_action_meter_read(struct rte_table_action *action,
675         void *data,
676         uint32_t tc_mask,
677         struct rte_table_action_mtr_counters *stats,
678         int clear)
679 {
680         struct mtr_trtcm_data *mtr_data;
681         uint32_t i;
682
683         /* Check input arguments */
684         if ((action == NULL) ||
685                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
686                 (data == NULL) ||
687                 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
688                 return -EINVAL;
689
690         mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
691
692         /* Read */
693         if (stats) {
694                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
695                         struct rte_table_action_mtr_counters_tc *dst =
696                                 &stats->stats[i];
697                         struct mtr_trtcm_data *src = &mtr_data[i];
698
699                         if ((tc_mask & (1 << i)) == 0)
700                                 continue;
701
702                         dst->n_packets[e_RTE_METER_GREEN] =
703                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
704
705                         dst->n_packets[e_RTE_METER_YELLOW] =
706                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
707
708                         dst->n_packets[e_RTE_METER_RED] =
709                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
710
711                         dst->n_packets_valid = 1;
712                         dst->n_bytes_valid = 0;
713                 }
714
715                 stats->tc_mask = tc_mask;
716         }
717
718         /* Clear */
719         if (clear)
720                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
721                         struct mtr_trtcm_data *src = &mtr_data[i];
722
723                         if ((tc_mask & (1 << i)) == 0)
724                                 continue;
725
726                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
727                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
728                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
729                 }
730
731
732         return 0;
733 }
734
735 static __rte_always_inline uint64_t
736 pkt_work(struct rte_mbuf *mbuf,
737         struct rte_pipeline_table_entry *table_entry,
738         uint64_t time,
739         struct rte_table_action *action,
740         struct ap_config *cfg)
741 {
742         uint64_t drop_mask = 0;
743
744         uint32_t ip_offset = action->cfg.common.ip_offset;
745         void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
746
747         uint32_t dscp;
748         uint16_t total_length;
749
750         if (cfg->common.ip_version) {
751                 struct ipv4_hdr *hdr = ip;
752
753                 dscp = hdr->type_of_service >> 2;
754                 total_length = rte_ntohs(hdr->total_length);
755         } else {
756                 struct ipv6_hdr *hdr = ip;
757
758                 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
759                 total_length =
760                         rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
761         }
762
763         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
764                 void *data =
765                         action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
766
767                 drop_mask |= pkt_work_mtr(mbuf,
768                         data,
769                         &action->dscp_table,
770                         action->mp,
771                         time,
772                         dscp,
773                         total_length);
774         }
775
776         return drop_mask;
777 }
778
779 static __rte_always_inline uint64_t
780 pkt4_work(struct rte_mbuf **mbufs,
781         struct rte_pipeline_table_entry **table_entries,
782         uint64_t time,
783         struct rte_table_action *action,
784         struct ap_config *cfg)
785 {
786         uint64_t drop_mask0 = 0;
787         uint64_t drop_mask1 = 0;
788         uint64_t drop_mask2 = 0;
789         uint64_t drop_mask3 = 0;
790
791         struct rte_mbuf *mbuf0 = mbufs[0];
792         struct rte_mbuf *mbuf1 = mbufs[1];
793         struct rte_mbuf *mbuf2 = mbufs[2];
794         struct rte_mbuf *mbuf3 = mbufs[3];
795
796         struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
797         struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
798         struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
799         struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
800
801         uint32_t ip_offset = action->cfg.common.ip_offset;
802         void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
803         void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
804         void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
805         void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
806
807         uint32_t dscp0, dscp1, dscp2, dscp3;
808         uint16_t total_length0, total_length1, total_length2, total_length3;
809
810         if (cfg->common.ip_version) {
811                 struct ipv4_hdr *hdr0 = ip0;
812                 struct ipv4_hdr *hdr1 = ip1;
813                 struct ipv4_hdr *hdr2 = ip2;
814                 struct ipv4_hdr *hdr3 = ip3;
815
816                 dscp0 = hdr0->type_of_service >> 2;
817                 dscp1 = hdr1->type_of_service >> 2;
818                 dscp2 = hdr2->type_of_service >> 2;
819                 dscp3 = hdr3->type_of_service >> 2;
820
821                 total_length0 = rte_ntohs(hdr0->total_length);
822                 total_length1 = rte_ntohs(hdr1->total_length);
823                 total_length2 = rte_ntohs(hdr2->total_length);
824                 total_length3 = rte_ntohs(hdr3->total_length);
825         } else {
826                 struct ipv6_hdr *hdr0 = ip0;
827                 struct ipv6_hdr *hdr1 = ip1;
828                 struct ipv6_hdr *hdr2 = ip2;
829                 struct ipv6_hdr *hdr3 = ip3;
830
831                 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
832                 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
833                 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
834                 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
835
836                 total_length0 =
837                         rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
838                 total_length1 =
839                         rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
840                 total_length2 =
841                         rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
842                 total_length3 =
843                         rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
844         }
845
846         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
847                 void *data0 =
848                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
849                 void *data1 =
850                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
851                 void *data2 =
852                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
853                 void *data3 =
854                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
855
856                 drop_mask0 |= pkt_work_mtr(mbuf0,
857                         data0,
858                         &action->dscp_table,
859                         action->mp,
860                         time,
861                         dscp0,
862                         total_length0);
863
864                 drop_mask1 |= pkt_work_mtr(mbuf1,
865                         data1,
866                         &action->dscp_table,
867                         action->mp,
868                         time,
869                         dscp1,
870                         total_length1);
871
872                 drop_mask2 |= pkt_work_mtr(mbuf2,
873                         data2,
874                         &action->dscp_table,
875                         action->mp,
876                         time,
877                         dscp2,
878                         total_length2);
879
880                 drop_mask3 |= pkt_work_mtr(mbuf3,
881                         data3,
882                         &action->dscp_table,
883                         action->mp,
884                         time,
885                         dscp3,
886                         total_length3);
887         }
888
889         return drop_mask0 |
890                 (drop_mask1 << 1) |
891                 (drop_mask2 << 2) |
892                 (drop_mask3 << 3);
893 }
894
895 static __rte_always_inline int
896 ah(struct rte_pipeline *p,
897         struct rte_mbuf **pkts,
898         uint64_t pkts_mask,
899         struct rte_pipeline_table_entry **entries,
900         struct rte_table_action *action,
901         struct ap_config *cfg)
902 {
903         uint64_t pkts_drop_mask = 0;
904         uint64_t time = 0;
905
906         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
907                 time = rte_rdtsc();
908
909         if ((pkts_mask & (pkts_mask + 1)) == 0) {
910                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
911                 uint32_t i;
912
913                 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
914                         uint64_t drop_mask;
915
916                         drop_mask = pkt4_work(&pkts[i],
917                                 &entries[i],
918                                 time,
919                                 action,
920                                 cfg);
921
922                         pkts_drop_mask |= drop_mask << i;
923                 }
924
925                 for ( ; i < n_pkts; i++) {
926                         uint64_t drop_mask;
927
928                         drop_mask = pkt_work(pkts[i],
929                                 entries[i],
930                                 time,
931                                 action,
932                                 cfg);
933
934                         pkts_drop_mask |= drop_mask << i;
935                 }
936         } else
937                 for ( ; pkts_mask; ) {
938                         uint32_t pos = __builtin_ctzll(pkts_mask);
939                         uint64_t pkt_mask = 1LLU << pos;
940                         uint64_t drop_mask;
941
942                         drop_mask = pkt_work(pkts[pos],
943                                 entries[pos],
944                                 time,
945                                 action,
946                                 cfg);
947
948                         pkts_mask &= ~pkt_mask;
949                         pkts_drop_mask |= drop_mask << pos;
950                 }
951
952         rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
953
954         return 0;
955 }
956
957 static int
958 ah_default(struct rte_pipeline *p,
959         struct rte_mbuf **pkts,
960         uint64_t pkts_mask,
961         struct rte_pipeline_table_entry **entries,
962         void *arg)
963 {
964         struct rte_table_action *action = arg;
965
966         return ah(p,
967                 pkts,
968                 pkts_mask,
969                 entries,
970                 action,
971                 &action->cfg);
972 }
973
974 static rte_pipeline_table_action_handler_hit
975 ah_selector(struct rte_table_action *action)
976 {
977         if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
978                 return NULL;
979
980         return ah_default;
981 }
982
983 int
984 rte_table_action_table_params_get(struct rte_table_action *action,
985         struct rte_pipeline_table_params *params)
986 {
987         rte_pipeline_table_action_handler_hit f_action_hit;
988         uint32_t total_size;
989
990         /* Check input arguments */
991         if ((action == NULL) ||
992                 (params == NULL))
993                 return -EINVAL;
994
995         f_action_hit = ah_selector(action);
996         total_size = rte_align32pow2(action->data.total_size);
997
998         /* Fill in params */
999         params->f_action_hit = f_action_hit;
1000         params->f_action_miss = NULL;
1001         params->arg_ah = (f_action_hit) ? action : NULL;
1002         params->action_data_size = total_size -
1003                 sizeof(struct rte_pipeline_table_entry);
1004
1005         return 0;
1006 }
1007
1008 int
1009 rte_table_action_free(struct rte_table_action *action)
1010 {
1011         if (action == NULL)
1012                 return 0;
1013
1014         rte_free(action);
1015
1016         return 0;
1017 }