pipeline: add statistics read 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_memcpy.h>
13 #include <rte_ether.h>
14 #include <rte_ip.h>
15 #include <rte_esp.h>
16 #include <rte_tcp.h>
17 #include <rte_udp.h>
18
19 #include "rte_table_action.h"
20
21 #define rte_htons rte_cpu_to_be_16
22 #define rte_htonl rte_cpu_to_be_32
23
24 #define rte_ntohs rte_be_to_cpu_16
25 #define rte_ntohl rte_be_to_cpu_32
26
27 /**
28  * RTE_TABLE_ACTION_FWD
29  */
30 #define fwd_data rte_pipeline_table_entry
31
32 static int
33 fwd_apply(struct fwd_data *data,
34         struct rte_table_action_fwd_params *p)
35 {
36         data->action = p->action;
37
38         if (p->action == RTE_PIPELINE_ACTION_PORT)
39                 data->port_id = p->id;
40
41         if (p->action == RTE_PIPELINE_ACTION_TABLE)
42                 data->table_id = p->id;
43
44         return 0;
45 }
46
47 /**
48  * RTE_TABLE_ACTION_MTR
49  */
50 static int
51 mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
52 {
53         if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
54                 ((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
55                 (mtr->n_bytes_enabled != 0))
56                 return -ENOTSUP;
57         return 0;
58 }
59
60 #define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color)        \
61         ((uint16_t)((((uint64_t)(queue)) & 0x3) |          \
62         ((((uint64_t)(tc)) & 0x3) << 2) |                  \
63         ((((uint64_t)(color)) & 0x3) << 4)))
64
65 #define MBUF_SCHED_COLOR(sched, color)                     \
66         (((sched) & (~0x30LLU)) | ((color) << 4))
67
68 struct mtr_trtcm_data {
69         struct rte_meter_trtcm trtcm;
70         uint64_t stats[e_RTE_METER_COLORS];
71 } __attribute__((__packed__));
72
73 #define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
74         (((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
75
76 static void
77 mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
78         uint32_t profile_id)
79 {
80         data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
81         data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
82 }
83
84 #define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
85         (((data)->stats[(color)] & 4LLU) >> 2)
86
87 #define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
88         ((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
89
90 static void
91 mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
92         enum rte_meter_color color,
93         enum rte_table_action_policer action)
94 {
95         if (action == RTE_TABLE_ACTION_POLICER_DROP) {
96                 data->stats[color] |= 4LLU;
97         } else {
98                 data->stats[color] &= ~7LLU;
99                 data->stats[color] |= color & 3LLU;
100         }
101 }
102
103 static uint64_t
104 mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
105         enum rte_meter_color color)
106 {
107         return data->stats[color] >> 8;
108 }
109
110 static void
111 mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
112         enum rte_meter_color color)
113 {
114         data->stats[color] &= 0xFFLU;
115 }
116
117 #define MTR_TRTCM_DATA_STATS_INC(data, color)              \
118         ((data)->stats[(color)] += (1LLU << 8))
119
120 static size_t
121 mtr_data_size(struct rte_table_action_mtr_config *mtr)
122 {
123         return mtr->n_tc * sizeof(struct mtr_trtcm_data);
124 }
125
126 struct dscp_table_entry_data {
127         enum rte_meter_color color;
128         uint16_t tc;
129         uint16_t queue_tc_color;
130 };
131
132 struct dscp_table_data {
133         struct dscp_table_entry_data entry[64];
134 };
135
136 struct meter_profile_data {
137         struct rte_meter_trtcm_profile profile;
138         uint32_t profile_id;
139         int valid;
140 };
141
142 static struct meter_profile_data *
143 meter_profile_data_find(struct meter_profile_data *mp,
144         uint32_t mp_size,
145         uint32_t profile_id)
146 {
147         uint32_t i;
148
149         for (i = 0; i < mp_size; i++) {
150                 struct meter_profile_data *mp_data = &mp[i];
151
152                 if (mp_data->valid && (mp_data->profile_id == profile_id))
153                         return mp_data;
154         }
155
156         return NULL;
157 }
158
159 static struct meter_profile_data *
160 meter_profile_data_find_unused(struct meter_profile_data *mp,
161         uint32_t mp_size)
162 {
163         uint32_t i;
164
165         for (i = 0; i < mp_size; i++) {
166                 struct meter_profile_data *mp_data = &mp[i];
167
168                 if (!mp_data->valid)
169                         return mp_data;
170         }
171
172         return NULL;
173 }
174
175 static int
176 mtr_apply_check(struct rte_table_action_mtr_params *p,
177         struct rte_table_action_mtr_config *cfg,
178         struct meter_profile_data *mp,
179         uint32_t mp_size)
180 {
181         uint32_t i;
182
183         if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
184                 return -EINVAL;
185
186         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
187                 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
188                 struct meter_profile_data *mp_data;
189
190                 if ((p->tc_mask & (1LLU << i)) == 0)
191                         continue;
192
193                 mp_data = meter_profile_data_find(mp,
194                         mp_size,
195                         p_tc->meter_profile_id);
196                 if (!mp_data)
197                         return -EINVAL;
198         }
199
200         return 0;
201 }
202
203 static int
204 mtr_apply(struct mtr_trtcm_data *data,
205         struct rte_table_action_mtr_params *p,
206         struct rte_table_action_mtr_config *cfg,
207         struct meter_profile_data *mp,
208         uint32_t mp_size)
209 {
210         uint32_t i;
211         int status;
212
213         /* Check input arguments */
214         status = mtr_apply_check(p, cfg, mp, mp_size);
215         if (status)
216                 return status;
217
218         /* Apply */
219         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
220                 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
221                 struct mtr_trtcm_data *data_tc = &data[i];
222                 struct meter_profile_data *mp_data;
223
224                 if ((p->tc_mask & (1LLU << i)) == 0)
225                         continue;
226
227                 /* Find profile */
228                 mp_data = meter_profile_data_find(mp,
229                         mp_size,
230                         p_tc->meter_profile_id);
231                 if (!mp_data)
232                         return -EINVAL;
233
234                 memset(data_tc, 0, sizeof(*data_tc));
235
236                 /* Meter object */
237                 status = rte_meter_trtcm_config(&data_tc->trtcm,
238                         &mp_data->profile);
239                 if (status)
240                         return status;
241
242                 /* Meter profile */
243                 mtr_trtcm_data_meter_profile_id_set(data_tc,
244                         mp_data - mp);
245
246                 /* Policer actions */
247                 mtr_trtcm_data_policer_action_set(data_tc,
248                         e_RTE_METER_GREEN,
249                         p_tc->policer[e_RTE_METER_GREEN]);
250
251                 mtr_trtcm_data_policer_action_set(data_tc,
252                         e_RTE_METER_YELLOW,
253                         p_tc->policer[e_RTE_METER_YELLOW]);
254
255                 mtr_trtcm_data_policer_action_set(data_tc,
256                         e_RTE_METER_RED,
257                         p_tc->policer[e_RTE_METER_RED]);
258         }
259
260         return 0;
261 }
262
263 static __rte_always_inline uint64_t
264 pkt_work_mtr(struct rte_mbuf *mbuf,
265         struct mtr_trtcm_data *data,
266         struct dscp_table_data *dscp_table,
267         struct meter_profile_data *mp,
268         uint64_t time,
269         uint32_t dscp,
270         uint16_t total_length)
271 {
272         uint64_t drop_mask, sched;
273         uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
274         struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
275         enum rte_meter_color color_in, color_meter, color_policer;
276         uint32_t tc, mp_id;
277
278         tc = dscp_entry->tc;
279         color_in = dscp_entry->color;
280         data += tc;
281         mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
282         sched = *sched_ptr;
283
284         /* Meter */
285         color_meter = rte_meter_trtcm_color_aware_check(
286                 &data->trtcm,
287                 &mp[mp_id].profile,
288                 time,
289                 total_length,
290                 color_in);
291
292         /* Stats */
293         MTR_TRTCM_DATA_STATS_INC(data, color_meter);
294
295         /* Police */
296         drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
297         color_policer =
298                 MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
299         *sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
300
301         return drop_mask;
302 }
303
304 /**
305  * RTE_TABLE_ACTION_TM
306  */
307 static int
308 tm_cfg_check(struct rte_table_action_tm_config *tm)
309 {
310         if ((tm->n_subports_per_port == 0) ||
311                 (rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
312                 (tm->n_subports_per_port > UINT16_MAX) ||
313                 (tm->n_pipes_per_subport == 0) ||
314                 (rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
315                 return -ENOTSUP;
316
317         return 0;
318 }
319
320 struct tm_data {
321         uint16_t queue_tc_color;
322         uint16_t subport;
323         uint32_t pipe;
324 } __attribute__((__packed__));
325
326 static int
327 tm_apply_check(struct rte_table_action_tm_params *p,
328         struct rte_table_action_tm_config *cfg)
329 {
330         if ((p->subport_id >= cfg->n_subports_per_port) ||
331                 (p->pipe_id >= cfg->n_pipes_per_subport))
332                 return -EINVAL;
333
334         return 0;
335 }
336
337 static int
338 tm_apply(struct tm_data *data,
339         struct rte_table_action_tm_params *p,
340         struct rte_table_action_tm_config *cfg)
341 {
342         int status;
343
344         /* Check input arguments */
345         status = tm_apply_check(p, cfg);
346         if (status)
347                 return status;
348
349         /* Apply */
350         data->queue_tc_color = 0;
351         data->subport = (uint16_t) p->subport_id;
352         data->pipe = p->pipe_id;
353
354         return 0;
355 }
356
357 static __rte_always_inline void
358 pkt_work_tm(struct rte_mbuf *mbuf,
359         struct tm_data *data,
360         struct dscp_table_data *dscp_table,
361         uint32_t dscp)
362 {
363         struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
364         struct tm_data *sched_ptr = (struct tm_data *) &mbuf->hash.sched;
365         struct tm_data sched;
366
367         sched = *data;
368         sched.queue_tc_color = dscp_entry->queue_tc_color;
369         *sched_ptr = sched;
370 }
371
372 /**
373  * RTE_TABLE_ACTION_ENCAP
374  */
375 static int
376 encap_valid(enum rte_table_action_encap_type encap)
377 {
378         switch (encap) {
379         case RTE_TABLE_ACTION_ENCAP_ETHER:
380         case RTE_TABLE_ACTION_ENCAP_VLAN:
381         case RTE_TABLE_ACTION_ENCAP_QINQ:
382         case RTE_TABLE_ACTION_ENCAP_MPLS:
383         case RTE_TABLE_ACTION_ENCAP_PPPOE:
384                 return 1;
385         default:
386                 return 0;
387         }
388 }
389
390 static int
391 encap_cfg_check(struct rte_table_action_encap_config *encap)
392 {
393         if ((encap->encap_mask == 0) ||
394                 (__builtin_popcountll(encap->encap_mask) != 1))
395                 return -ENOTSUP;
396
397         return 0;
398 }
399
400 struct encap_ether_data {
401         struct ether_hdr ether;
402 } __attribute__((__packed__));
403
404 #define VLAN(pcp, dei, vid)                                \
405         ((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
406         ((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
407         (((uint64_t)(vid)) & 0xFFFLLU))                    \
408
409 struct encap_vlan_data {
410         struct ether_hdr ether;
411         struct vlan_hdr vlan;
412 } __attribute__((__packed__));
413
414 struct encap_qinq_data {
415         struct ether_hdr ether;
416         struct vlan_hdr svlan;
417         struct vlan_hdr cvlan;
418 } __attribute__((__packed__));
419
420 #define ETHER_TYPE_MPLS_UNICAST                            0x8847
421
422 #define ETHER_TYPE_MPLS_MULTICAST                          0x8848
423
424 #define MPLS(label, tc, s, ttl)                            \
425         ((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
426         ((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
427         ((((uint64_t)(s)) & 0x1LLU) << 8) |                \
428         (((uint64_t)(ttl)) & 0xFFLLU)))
429
430 struct encap_mpls_data {
431         struct ether_hdr ether;
432         uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
433         uint32_t mpls_count;
434 } __attribute__((__packed__));
435
436 #define ETHER_TYPE_PPPOE_SESSION                           0x8864
437
438 #define PPP_PROTOCOL_IP                                    0x0021
439
440 struct pppoe_ppp_hdr {
441         uint16_t ver_type_code;
442         uint16_t session_id;
443         uint16_t length;
444         uint16_t protocol;
445 } __attribute__((__packed__));
446
447 struct encap_pppoe_data {
448         struct ether_hdr ether;
449         struct pppoe_ppp_hdr pppoe_ppp;
450 } __attribute__((__packed__));
451
452 static size_t
453 encap_data_size(struct rte_table_action_encap_config *encap)
454 {
455         switch (encap->encap_mask) {
456         case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
457                 return sizeof(struct encap_ether_data);
458
459         case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
460                 return sizeof(struct encap_vlan_data);
461
462         case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
463                 return sizeof(struct encap_qinq_data);
464
465         case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
466                 return sizeof(struct encap_mpls_data);
467
468         case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
469                 return sizeof(struct encap_pppoe_data);
470
471         default:
472                 return 0;
473         }
474 }
475
476 static int
477 encap_apply_check(struct rte_table_action_encap_params *p,
478         struct rte_table_action_encap_config *cfg)
479 {
480         if ((encap_valid(p->type) == 0) ||
481                 ((cfg->encap_mask & (1LLU << p->type)) == 0))
482                 return -EINVAL;
483
484         switch (p->type) {
485         case RTE_TABLE_ACTION_ENCAP_ETHER:
486                 return 0;
487
488         case RTE_TABLE_ACTION_ENCAP_VLAN:
489                 return 0;
490
491         case RTE_TABLE_ACTION_ENCAP_QINQ:
492                 return 0;
493
494         case RTE_TABLE_ACTION_ENCAP_MPLS:
495                 if ((p->mpls.mpls_count == 0) ||
496                         (p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
497                         return -EINVAL;
498
499                 return 0;
500
501         case RTE_TABLE_ACTION_ENCAP_PPPOE:
502                 return 0;
503
504         default:
505                 return -EINVAL;
506         }
507 }
508
509 static int
510 encap_ether_apply(void *data,
511         struct rte_table_action_encap_params *p,
512         struct rte_table_action_common_config *common_cfg)
513 {
514         struct encap_ether_data *d = data;
515         uint16_t ethertype = (common_cfg->ip_version) ?
516                 ETHER_TYPE_IPv4 :
517                 ETHER_TYPE_IPv6;
518
519         /* Ethernet */
520         ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
521         ether_addr_copy(&p->ether.ether.sa, &d->ether.s_addr);
522         d->ether.ether_type = rte_htons(ethertype);
523
524         return 0;
525 }
526
527 static int
528 encap_vlan_apply(void *data,
529         struct rte_table_action_encap_params *p,
530         struct rte_table_action_common_config *common_cfg)
531 {
532         struct encap_vlan_data *d = data;
533         uint16_t ethertype = (common_cfg->ip_version) ?
534                 ETHER_TYPE_IPv4 :
535                 ETHER_TYPE_IPv6;
536
537         /* Ethernet */
538         ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
539         ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
540         d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
541
542         /* VLAN */
543         d->vlan.vlan_tci = rte_htons(VLAN(p->vlan.vlan.pcp,
544                 p->vlan.vlan.dei,
545                 p->vlan.vlan.vid));
546         d->vlan.eth_proto = rte_htons(ethertype);
547
548         return 0;
549 }
550
551 static int
552 encap_qinq_apply(void *data,
553         struct rte_table_action_encap_params *p,
554         struct rte_table_action_common_config *common_cfg)
555 {
556         struct encap_qinq_data *d = data;
557         uint16_t ethertype = (common_cfg->ip_version) ?
558                 ETHER_TYPE_IPv4 :
559                 ETHER_TYPE_IPv6;
560
561         /* Ethernet */
562         ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
563         ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
564         d->ether.ether_type = rte_htons(ETHER_TYPE_QINQ);
565
566         /* SVLAN */
567         d->svlan.vlan_tci = rte_htons(VLAN(p->qinq.svlan.pcp,
568                 p->qinq.svlan.dei,
569                 p->qinq.svlan.vid));
570         d->svlan.eth_proto = rte_htons(ETHER_TYPE_VLAN);
571
572         /* CVLAN */
573         d->cvlan.vlan_tci = rte_htons(VLAN(p->qinq.cvlan.pcp,
574                 p->qinq.cvlan.dei,
575                 p->qinq.cvlan.vid));
576         d->cvlan.eth_proto = rte_htons(ethertype);
577
578         return 0;
579 }
580
581 static int
582 encap_mpls_apply(void *data,
583         struct rte_table_action_encap_params *p)
584 {
585         struct encap_mpls_data *d = data;
586         uint16_t ethertype = (p->mpls.unicast) ?
587                 ETHER_TYPE_MPLS_UNICAST :
588                 ETHER_TYPE_MPLS_MULTICAST;
589         uint32_t i;
590
591         /* Ethernet */
592         ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
593         ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
594         d->ether.ether_type = rte_htons(ethertype);
595
596         /* MPLS */
597         for (i = 0; i < p->mpls.mpls_count - 1; i++)
598                 d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
599                         p->mpls.mpls[i].tc,
600                         0,
601                         p->mpls.mpls[i].ttl));
602
603         d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
604                 p->mpls.mpls[i].tc,
605                 1,
606                 p->mpls.mpls[i].ttl));
607
608         d->mpls_count = p->mpls.mpls_count;
609         return 0;
610 }
611
612 static int
613 encap_pppoe_apply(void *data,
614         struct rte_table_action_encap_params *p)
615 {
616         struct encap_pppoe_data *d = data;
617
618         /* Ethernet */
619         ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
620         ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
621         d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
622
623         /* PPPoE and PPP*/
624         d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
625         d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
626         d->pppoe_ppp.length = 0; /* not pre-computed */
627         d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
628
629         return 0;
630 }
631
632 static int
633 encap_apply(void *data,
634         struct rte_table_action_encap_params *p,
635         struct rte_table_action_encap_config *cfg,
636         struct rte_table_action_common_config *common_cfg)
637 {
638         int status;
639
640         /* Check input arguments */
641         status = encap_apply_check(p, cfg);
642         if (status)
643                 return status;
644
645         switch (p->type) {
646         case RTE_TABLE_ACTION_ENCAP_ETHER:
647                 return encap_ether_apply(data, p, common_cfg);
648
649         case RTE_TABLE_ACTION_ENCAP_VLAN:
650                 return encap_vlan_apply(data, p, common_cfg);
651
652         case RTE_TABLE_ACTION_ENCAP_QINQ:
653                 return encap_qinq_apply(data, p, common_cfg);
654
655         case RTE_TABLE_ACTION_ENCAP_MPLS:
656                 return encap_mpls_apply(data, p);
657
658         case RTE_TABLE_ACTION_ENCAP_PPPOE:
659                 return encap_pppoe_apply(data, p);
660
661         default:
662                 return -EINVAL;
663         }
664 }
665
666 static __rte_always_inline void *
667 encap(void *dst, const void *src, size_t n)
668 {
669         dst = ((uint8_t *) dst) - n;
670         return rte_memcpy(dst, src, n);
671 }
672
673 static __rte_always_inline void
674 pkt_work_encap(struct rte_mbuf *mbuf,
675         void *data,
676         struct rte_table_action_encap_config *cfg,
677         void *ip,
678         uint16_t total_length,
679         uint32_t ip_offset)
680 {
681         switch (cfg->encap_mask) {
682         case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
683                 encap(ip, data, sizeof(struct encap_ether_data));
684                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
685                         sizeof(struct encap_ether_data));
686                 mbuf->pkt_len = mbuf->data_len = total_length +
687                         sizeof(struct encap_ether_data);
688                 break;
689
690         case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
691                 encap(ip, data, sizeof(struct encap_vlan_data));
692                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
693                         sizeof(struct encap_vlan_data));
694                 mbuf->pkt_len = mbuf->data_len = total_length +
695                         sizeof(struct encap_vlan_data);
696                 break;
697
698         case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
699                 encap(ip, data, sizeof(struct encap_qinq_data));
700                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
701                         sizeof(struct encap_qinq_data));
702                 mbuf->pkt_len = mbuf->data_len = total_length +
703                         sizeof(struct encap_qinq_data);
704                 break;
705
706         case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
707         {
708                 struct encap_mpls_data *mpls = data;
709                 size_t size = sizeof(struct ether_hdr) +
710                         mpls->mpls_count * 4;
711
712                 encap(ip, data, size);
713                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
714                 mbuf->pkt_len = mbuf->data_len = total_length + size;
715                 break;
716         }
717
718         case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
719         {
720                 struct encap_pppoe_data *pppoe =
721                         encap(ip, data, sizeof(struct encap_pppoe_data));
722                 pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
723                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
724                         sizeof(struct encap_pppoe_data));
725                 mbuf->pkt_len = mbuf->data_len = total_length +
726                         sizeof(struct encap_pppoe_data);
727                 break;
728         }
729
730         default:
731                 break;
732         }
733 }
734
735 /**
736  * RTE_TABLE_ACTION_NAT
737  */
738 static int
739 nat_cfg_check(struct rte_table_action_nat_config *nat)
740 {
741         if ((nat->proto != 0x06) &&
742                 (nat->proto != 0x11))
743                 return -ENOTSUP;
744
745         return 0;
746 }
747
748 struct nat_ipv4_data {
749         uint32_t addr;
750         uint16_t port;
751 } __attribute__((__packed__));
752
753 struct nat_ipv6_data {
754         uint8_t addr[16];
755         uint16_t port;
756 } __attribute__((__packed__));
757
758 static size_t
759 nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
760         struct rte_table_action_common_config *common)
761 {
762         int ip_version = common->ip_version;
763
764         return (ip_version) ?
765                 sizeof(struct nat_ipv4_data) :
766                 sizeof(struct nat_ipv6_data);
767 }
768
769 static int
770 nat_apply_check(struct rte_table_action_nat_params *p,
771         struct rte_table_action_common_config *cfg)
772 {
773         if ((p->ip_version && (cfg->ip_version == 0)) ||
774                 ((p->ip_version == 0) && cfg->ip_version))
775                 return -EINVAL;
776
777         return 0;
778 }
779
780 static int
781 nat_apply(void *data,
782         struct rte_table_action_nat_params *p,
783         struct rte_table_action_common_config *cfg)
784 {
785         int status;
786
787         /* Check input arguments */
788         status = nat_apply_check(p, cfg);
789         if (status)
790                 return status;
791
792         /* Apply */
793         if (p->ip_version) {
794                 struct nat_ipv4_data *d = data;
795
796                 d->addr = rte_htonl(p->addr.ipv4);
797                 d->port = rte_htons(p->port);
798         } else {
799                 struct nat_ipv6_data *d = data;
800
801                 memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
802                 d->port = rte_htons(p->port);
803         }
804
805         return 0;
806 }
807
808 static __rte_always_inline uint16_t
809 nat_ipv4_checksum_update(uint16_t cksum0,
810         uint32_t ip0,
811         uint32_t ip1)
812 {
813         int32_t cksum1;
814
815         cksum1 = cksum0;
816         cksum1 = ~cksum1 & 0xFFFF;
817
818         /* Subtract ip0 (one's complement logic) */
819         cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF);
820         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
821         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
822
823         /* Add ip1 (one's complement logic) */
824         cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF);
825         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
826         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
827
828         return (uint16_t)(~cksum1);
829 }
830
831 static __rte_always_inline uint16_t
832 nat_ipv4_tcp_udp_checksum_update(uint16_t cksum0,
833         uint32_t ip0,
834         uint32_t ip1,
835         uint16_t port0,
836         uint16_t port1)
837 {
838         int32_t cksum1;
839
840         cksum1 = cksum0;
841         cksum1 = ~cksum1 & 0xFFFF;
842
843         /* Subtract ip0 and port 0 (one's complement logic) */
844         cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF) + port0;
845         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
846         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
847
848         /* Add ip1 and port1 (one's complement logic) */
849         cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF) + port1;
850         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
851         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
852
853         return (uint16_t)(~cksum1);
854 }
855
856 static __rte_always_inline uint16_t
857 nat_ipv6_tcp_udp_checksum_update(uint16_t cksum0,
858         uint16_t *ip0,
859         uint16_t *ip1,
860         uint16_t port0,
861         uint16_t port1)
862 {
863         int32_t cksum1;
864
865         cksum1 = cksum0;
866         cksum1 = ~cksum1 & 0xFFFF;
867
868         /* Subtract ip0 and port 0 (one's complement logic) */
869         cksum1 -= ip0[0] + ip0[1] + ip0[2] + ip0[3] +
870                 ip0[4] + ip0[5] + ip0[6] + ip0[7] + port0;
871         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
872         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
873
874         /* Add ip1 and port1 (one's complement logic) */
875         cksum1 += ip1[0] + ip1[1] + ip1[2] + ip1[3] +
876                 ip1[4] + ip1[5] + ip1[6] + ip1[7] + port1;
877         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
878         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
879
880         return (uint16_t)(~cksum1);
881 }
882
883 static __rte_always_inline void
884 pkt_ipv4_work_nat(struct ipv4_hdr *ip,
885         struct nat_ipv4_data *data,
886         struct rte_table_action_nat_config *cfg)
887 {
888         if (cfg->source_nat) {
889                 if (cfg->proto == 0x6) {
890                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
891                         uint16_t ip_cksum, tcp_cksum;
892
893                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
894                                 ip->src_addr,
895                                 data->addr);
896
897                         tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
898                                 ip->src_addr,
899                                 data->addr,
900                                 tcp->src_port,
901                                 data->port);
902
903                         ip->src_addr = data->addr;
904                         ip->hdr_checksum = ip_cksum;
905                         tcp->src_port = data->port;
906                         tcp->cksum = tcp_cksum;
907                 } else {
908                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
909                         uint16_t ip_cksum, udp_cksum;
910
911                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
912                                 ip->src_addr,
913                                 data->addr);
914
915                         udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
916                                 ip->src_addr,
917                                 data->addr,
918                                 udp->src_port,
919                                 data->port);
920
921                         ip->src_addr = data->addr;
922                         ip->hdr_checksum = ip_cksum;
923                         udp->src_port = data->port;
924                         if (udp->dgram_cksum)
925                                 udp->dgram_cksum = udp_cksum;
926                 }
927         } else {
928                 if (cfg->proto == 0x6) {
929                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
930                         uint16_t ip_cksum, tcp_cksum;
931
932                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
933                                 ip->dst_addr,
934                                 data->addr);
935
936                         tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
937                                 ip->dst_addr,
938                                 data->addr,
939                                 tcp->dst_port,
940                                 data->port);
941
942                         ip->dst_addr = data->addr;
943                         ip->hdr_checksum = ip_cksum;
944                         tcp->dst_port = data->port;
945                         tcp->cksum = tcp_cksum;
946                 } else {
947                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
948                         uint16_t ip_cksum, udp_cksum;
949
950                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
951                                 ip->dst_addr,
952                                 data->addr);
953
954                         udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
955                                 ip->dst_addr,
956                                 data->addr,
957                                 udp->dst_port,
958                                 data->port);
959
960                         ip->dst_addr = data->addr;
961                         ip->hdr_checksum = ip_cksum;
962                         udp->dst_port = data->port;
963                         if (udp->dgram_cksum)
964                                 udp->dgram_cksum = udp_cksum;
965                 }
966         }
967 }
968
969 static __rte_always_inline void
970 pkt_ipv6_work_nat(struct ipv6_hdr *ip,
971         struct nat_ipv6_data *data,
972         struct rte_table_action_nat_config *cfg)
973 {
974         if (cfg->source_nat) {
975                 if (cfg->proto == 0x6) {
976                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
977                         uint16_t tcp_cksum;
978
979                         tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
980                                 (uint16_t *)ip->src_addr,
981                                 (uint16_t *)data->addr,
982                                 tcp->src_port,
983                                 data->port);
984
985                         rte_memcpy(ip->src_addr, data->addr, 16);
986                         tcp->src_port = data->port;
987                         tcp->cksum = tcp_cksum;
988                 } else {
989                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
990                         uint16_t udp_cksum;
991
992                         udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
993                                 (uint16_t *)ip->src_addr,
994                                 (uint16_t *)data->addr,
995                                 udp->src_port,
996                                 data->port);
997
998                         rte_memcpy(ip->src_addr, data->addr, 16);
999                         udp->src_port = data->port;
1000                         udp->dgram_cksum = udp_cksum;
1001                 }
1002         } else {
1003                 if (cfg->proto == 0x6) {
1004                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1005                         uint16_t tcp_cksum;
1006
1007                         tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
1008                                 (uint16_t *)ip->dst_addr,
1009                                 (uint16_t *)data->addr,
1010                                 tcp->dst_port,
1011                                 data->port);
1012
1013                         rte_memcpy(ip->dst_addr, data->addr, 16);
1014                         tcp->dst_port = data->port;
1015                         tcp->cksum = tcp_cksum;
1016                 } else {
1017                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1018                         uint16_t udp_cksum;
1019
1020                         udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
1021                                 (uint16_t *)ip->dst_addr,
1022                                 (uint16_t *)data->addr,
1023                                 udp->dst_port,
1024                                 data->port);
1025
1026                         rte_memcpy(ip->dst_addr, data->addr, 16);
1027                         udp->dst_port = data->port;
1028                         udp->dgram_cksum = udp_cksum;
1029                 }
1030         }
1031 }
1032
1033 /**
1034  * RTE_TABLE_ACTION_TTL
1035  */
1036 static int
1037 ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
1038 {
1039         if (ttl->drop == 0)
1040                 return -ENOTSUP;
1041
1042         return 0;
1043 }
1044
1045 struct ttl_data {
1046         uint32_t n_packets;
1047 } __attribute__((__packed__));
1048
1049 #define TTL_INIT(data, decrement)                         \
1050         ((data)->n_packets = (decrement) ? 1 : 0)
1051
1052 #define TTL_DEC_GET(data)                                  \
1053         ((uint8_t)((data)->n_packets & 1))
1054
1055 #define TTL_STATS_RESET(data)                             \
1056         ((data)->n_packets = ((data)->n_packets & 1))
1057
1058 #define TTL_STATS_READ(data)                               \
1059         ((data)->n_packets >> 1)
1060
1061 #define TTL_STATS_ADD(data, value)                        \
1062         ((data)->n_packets =                                  \
1063                 (((((data)->n_packets >> 1) + (value)) << 1) |    \
1064                 ((data)->n_packets & 1)))
1065
1066 static int
1067 ttl_apply(void *data,
1068         struct rte_table_action_ttl_params *p)
1069 {
1070         struct ttl_data *d = data;
1071
1072         TTL_INIT(d, p->decrement);
1073
1074         return 0;
1075 }
1076
1077 static __rte_always_inline uint64_t
1078 pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
1079         struct ttl_data *data)
1080 {
1081         uint32_t drop;
1082         uint16_t cksum = ip->hdr_checksum;
1083         uint8_t ttl = ip->time_to_live;
1084         uint8_t ttl_diff = TTL_DEC_GET(data);
1085
1086         cksum += ttl_diff;
1087         ttl -= ttl_diff;
1088
1089         ip->hdr_checksum = cksum;
1090         ip->time_to_live = ttl;
1091
1092         drop = (ttl == 0) ? 1 : 0;
1093         TTL_STATS_ADD(data, drop);
1094
1095         return drop;
1096 }
1097
1098 static __rte_always_inline uint64_t
1099 pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
1100         struct ttl_data *data)
1101 {
1102         uint32_t drop;
1103         uint8_t ttl = ip->hop_limits;
1104         uint8_t ttl_diff = TTL_DEC_GET(data);
1105
1106         ttl -= ttl_diff;
1107
1108         ip->hop_limits = ttl;
1109
1110         drop = (ttl == 0) ? 1 : 0;
1111         TTL_STATS_ADD(data, drop);
1112
1113         return drop;
1114 }
1115
1116 /**
1117  * RTE_TABLE_ACTION_STATS
1118  */
1119 static int
1120 stats_cfg_check(struct rte_table_action_stats_config *stats)
1121 {
1122         if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
1123                 return -EINVAL;
1124
1125         return 0;
1126 }
1127
1128 struct stats_data {
1129         uint64_t n_packets;
1130         uint64_t n_bytes;
1131 } __attribute__((__packed__));
1132
1133 static int
1134 stats_apply(struct stats_data *data,
1135         struct rte_table_action_stats_params *p)
1136 {
1137         data->n_packets = p->n_packets;
1138         data->n_bytes = p->n_bytes;
1139
1140         return 0;
1141 }
1142
1143 static __rte_always_inline void
1144 pkt_work_stats(struct stats_data *data,
1145         uint16_t total_length)
1146 {
1147         data->n_packets++;
1148         data->n_bytes += total_length;
1149 }
1150
1151 /**
1152  * Action profile
1153  */
1154 static int
1155 action_valid(enum rte_table_action_type action)
1156 {
1157         switch (action) {
1158         case RTE_TABLE_ACTION_FWD:
1159         case RTE_TABLE_ACTION_MTR:
1160         case RTE_TABLE_ACTION_TM:
1161         case RTE_TABLE_ACTION_ENCAP:
1162         case RTE_TABLE_ACTION_NAT:
1163         case RTE_TABLE_ACTION_TTL:
1164         case RTE_TABLE_ACTION_STATS:
1165                 return 1;
1166         default:
1167                 return 0;
1168         }
1169 }
1170
1171
1172 #define RTE_TABLE_ACTION_MAX                      64
1173
1174 struct ap_config {
1175         uint64_t action_mask;
1176         struct rte_table_action_common_config common;
1177         struct rte_table_action_mtr_config mtr;
1178         struct rte_table_action_tm_config tm;
1179         struct rte_table_action_encap_config encap;
1180         struct rte_table_action_nat_config nat;
1181         struct rte_table_action_ttl_config ttl;
1182         struct rte_table_action_stats_config stats;
1183 };
1184
1185 static size_t
1186 action_cfg_size(enum rte_table_action_type action)
1187 {
1188         switch (action) {
1189         case RTE_TABLE_ACTION_MTR:
1190                 return sizeof(struct rte_table_action_mtr_config);
1191         case RTE_TABLE_ACTION_TM:
1192                 return sizeof(struct rte_table_action_tm_config);
1193         case RTE_TABLE_ACTION_ENCAP:
1194                 return sizeof(struct rte_table_action_encap_config);
1195         case RTE_TABLE_ACTION_NAT:
1196                 return sizeof(struct rte_table_action_nat_config);
1197         case RTE_TABLE_ACTION_TTL:
1198                 return sizeof(struct rte_table_action_ttl_config);
1199         case RTE_TABLE_ACTION_STATS:
1200                 return sizeof(struct rte_table_action_stats_config);
1201         default:
1202                 return 0;
1203         }
1204 }
1205
1206 static void*
1207 action_cfg_get(struct ap_config *ap_config,
1208         enum rte_table_action_type type)
1209 {
1210         switch (type) {
1211         case RTE_TABLE_ACTION_MTR:
1212                 return &ap_config->mtr;
1213
1214         case RTE_TABLE_ACTION_TM:
1215                 return &ap_config->tm;
1216
1217         case RTE_TABLE_ACTION_ENCAP:
1218                 return &ap_config->encap;
1219
1220         case RTE_TABLE_ACTION_NAT:
1221                 return &ap_config->nat;
1222
1223         case RTE_TABLE_ACTION_TTL:
1224                 return &ap_config->ttl;
1225
1226         case RTE_TABLE_ACTION_STATS:
1227                 return &ap_config->stats;
1228
1229         default:
1230                 return NULL;
1231         }
1232 }
1233
1234 static void
1235 action_cfg_set(struct ap_config *ap_config,
1236         enum rte_table_action_type type,
1237         void *action_cfg)
1238 {
1239         void *dst = action_cfg_get(ap_config, type);
1240
1241         if (dst)
1242                 memcpy(dst, action_cfg, action_cfg_size(type));
1243
1244         ap_config->action_mask |= 1LLU << type;
1245 }
1246
1247 struct ap_data {
1248         size_t offset[RTE_TABLE_ACTION_MAX];
1249         size_t total_size;
1250 };
1251
1252 static size_t
1253 action_data_size(enum rte_table_action_type action,
1254         struct ap_config *ap_config)
1255 {
1256         switch (action) {
1257         case RTE_TABLE_ACTION_FWD:
1258                 return sizeof(struct fwd_data);
1259
1260         case RTE_TABLE_ACTION_MTR:
1261                 return mtr_data_size(&ap_config->mtr);
1262
1263         case RTE_TABLE_ACTION_TM:
1264                 return sizeof(struct tm_data);
1265
1266         case RTE_TABLE_ACTION_ENCAP:
1267                 return encap_data_size(&ap_config->encap);
1268
1269         case RTE_TABLE_ACTION_NAT:
1270                 return nat_data_size(&ap_config->nat,
1271                         &ap_config->common);
1272
1273         case RTE_TABLE_ACTION_TTL:
1274                 return sizeof(struct ttl_data);
1275
1276         case RTE_TABLE_ACTION_STATS:
1277                 return sizeof(struct stats_data);
1278
1279         default:
1280                 return 0;
1281         }
1282 }
1283
1284
1285 static void
1286 action_data_offset_set(struct ap_data *ap_data,
1287         struct ap_config *ap_config)
1288 {
1289         uint64_t action_mask = ap_config->action_mask;
1290         size_t offset;
1291         uint32_t action;
1292
1293         memset(ap_data->offset, 0, sizeof(ap_data->offset));
1294
1295         offset = 0;
1296         for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
1297                 if (action_mask & (1LLU << action)) {
1298                         ap_data->offset[action] = offset;
1299                         offset += action_data_size((enum rte_table_action_type)action,
1300                                 ap_config);
1301                 }
1302
1303         ap_data->total_size = offset;
1304 }
1305
1306 struct rte_table_action_profile {
1307         struct ap_config cfg;
1308         struct ap_data data;
1309         int frozen;
1310 };
1311
1312 struct rte_table_action_profile *
1313 rte_table_action_profile_create(struct rte_table_action_common_config *common)
1314 {
1315         struct rte_table_action_profile *ap;
1316
1317         /* Check input arguments */
1318         if (common == NULL)
1319                 return NULL;
1320
1321         /* Memory allocation */
1322         ap = calloc(1, sizeof(struct rte_table_action_profile));
1323         if (ap == NULL)
1324                 return NULL;
1325
1326         /* Initialization */
1327         memcpy(&ap->cfg.common, common, sizeof(*common));
1328
1329         return ap;
1330 }
1331
1332
1333 int
1334 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
1335         enum rte_table_action_type type,
1336         void *action_config)
1337 {
1338         int status;
1339
1340         /* Check input arguments */
1341         if ((profile == NULL) ||
1342                 profile->frozen ||
1343                 (action_valid(type) == 0) ||
1344                 (profile->cfg.action_mask & (1LLU << type)) ||
1345                 ((action_cfg_size(type) == 0) && action_config) ||
1346                 (action_cfg_size(type) && (action_config == NULL)))
1347                 return -EINVAL;
1348
1349         switch (type) {
1350         case RTE_TABLE_ACTION_MTR:
1351                 status = mtr_cfg_check(action_config);
1352                 break;
1353
1354         case RTE_TABLE_ACTION_TM:
1355                 status = tm_cfg_check(action_config);
1356                 break;
1357
1358         case RTE_TABLE_ACTION_ENCAP:
1359                 status = encap_cfg_check(action_config);
1360                 break;
1361
1362         case RTE_TABLE_ACTION_NAT:
1363                 status = nat_cfg_check(action_config);
1364                 break;
1365
1366         case RTE_TABLE_ACTION_TTL:
1367                 status = ttl_cfg_check(action_config);
1368                 break;
1369
1370         case RTE_TABLE_ACTION_STATS:
1371                 status = stats_cfg_check(action_config);
1372                 break;
1373
1374         default:
1375                 status = 0;
1376                 break;
1377         }
1378
1379         if (status)
1380                 return status;
1381
1382         /* Action enable */
1383         action_cfg_set(&profile->cfg, type, action_config);
1384
1385         return 0;
1386 }
1387
1388 int
1389 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
1390 {
1391         if (profile->frozen)
1392                 return -EBUSY;
1393
1394         profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1395         action_data_offset_set(&profile->data, &profile->cfg);
1396         profile->frozen = 1;
1397
1398         return 0;
1399 }
1400
1401 int
1402 rte_table_action_profile_free(struct rte_table_action_profile *profile)
1403 {
1404         if (profile == NULL)
1405                 return 0;
1406
1407         free(profile);
1408         return 0;
1409 }
1410
1411 /**
1412  * Action
1413  */
1414 #define METER_PROFILES_MAX                                 32
1415
1416 struct rte_table_action {
1417         struct ap_config cfg;
1418         struct ap_data data;
1419         struct dscp_table_data dscp_table;
1420         struct meter_profile_data mp[METER_PROFILES_MAX];
1421 };
1422
1423 struct rte_table_action *
1424 rte_table_action_create(struct rte_table_action_profile *profile,
1425         uint32_t socket_id)
1426 {
1427         struct rte_table_action *action;
1428
1429         /* Check input arguments */
1430         if ((profile == NULL) ||
1431                 (profile->frozen == 0))
1432                 return NULL;
1433
1434         /* Memory allocation */
1435         action = rte_zmalloc_socket(NULL,
1436                 sizeof(struct rte_table_action),
1437                 RTE_CACHE_LINE_SIZE,
1438                 socket_id);
1439         if (action == NULL)
1440                 return NULL;
1441
1442         /* Initialization */
1443         memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
1444         memcpy(&action->data, &profile->data, sizeof(profile->data));
1445
1446         return action;
1447 }
1448
1449 static __rte_always_inline void *
1450 action_data_get(void *data,
1451         struct rte_table_action *action,
1452         enum rte_table_action_type type)
1453 {
1454         size_t offset = action->data.offset[type];
1455         uint8_t *data_bytes = data;
1456
1457         return &data_bytes[offset];
1458 }
1459
1460 int
1461 rte_table_action_apply(struct rte_table_action *action,
1462         void *data,
1463         enum rte_table_action_type type,
1464         void *action_params)
1465 {
1466         void *action_data;
1467
1468         /* Check input arguments */
1469         if ((action == NULL) ||
1470                 (data == NULL) ||
1471                 (action_valid(type) == 0) ||
1472                 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
1473                 (action_params == NULL))
1474                 return -EINVAL;
1475
1476         /* Data update */
1477         action_data = action_data_get(data, action, type);
1478
1479         switch (type) {
1480         case RTE_TABLE_ACTION_FWD:
1481                 return fwd_apply(action_data,
1482                         action_params);
1483
1484         case RTE_TABLE_ACTION_MTR:
1485                 return mtr_apply(action_data,
1486                         action_params,
1487                         &action->cfg.mtr,
1488                         action->mp,
1489                         RTE_DIM(action->mp));
1490
1491         case RTE_TABLE_ACTION_TM:
1492                 return tm_apply(action_data,
1493                         action_params,
1494                         &action->cfg.tm);
1495
1496         case RTE_TABLE_ACTION_ENCAP:
1497                 return encap_apply(action_data,
1498                         action_params,
1499                         &action->cfg.encap,
1500                         &action->cfg.common);
1501
1502         case RTE_TABLE_ACTION_NAT:
1503                 return nat_apply(action_data,
1504                         action_params,
1505                         &action->cfg.common);
1506
1507         case RTE_TABLE_ACTION_TTL:
1508                 return ttl_apply(action_data,
1509                         action_params);
1510
1511         case RTE_TABLE_ACTION_STATS:
1512                 return stats_apply(action_data,
1513                         action_params);
1514
1515         default:
1516                 return -EINVAL;
1517         }
1518 }
1519
1520 int
1521 rte_table_action_dscp_table_update(struct rte_table_action *action,
1522         uint64_t dscp_mask,
1523         struct rte_table_action_dscp_table *table)
1524 {
1525         uint32_t i;
1526
1527         /* Check input arguments */
1528         if ((action == NULL) ||
1529                 ((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
1530                 (1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
1531                 (dscp_mask == 0) ||
1532                 (table == NULL))
1533                 return -EINVAL;
1534
1535         for (i = 0; i < RTE_DIM(table->entry); i++) {
1536                 struct dscp_table_entry_data *data =
1537                         &action->dscp_table.entry[i];
1538                 struct rte_table_action_dscp_table_entry *entry =
1539                         &table->entry[i];
1540                 uint16_t queue_tc_color =
1541                         MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
1542                                 entry->tc_id,
1543                                 entry->color);
1544
1545                 if ((dscp_mask & (1LLU << i)) == 0)
1546                         continue;
1547
1548                 data->color = entry->color;
1549                 data->tc = entry->tc_id;
1550                 data->queue_tc_color = queue_tc_color;
1551         }
1552
1553         return 0;
1554 }
1555
1556 int
1557 rte_table_action_meter_profile_add(struct rte_table_action *action,
1558         uint32_t meter_profile_id,
1559         struct rte_table_action_meter_profile *profile)
1560 {
1561         struct meter_profile_data *mp_data;
1562         uint32_t status;
1563
1564         /* Check input arguments */
1565         if ((action == NULL) ||
1566                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
1567                 (profile == NULL))
1568                 return -EINVAL;
1569
1570         if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
1571                 return -ENOTSUP;
1572
1573         mp_data = meter_profile_data_find(action->mp,
1574                 RTE_DIM(action->mp),
1575                 meter_profile_id);
1576         if (mp_data)
1577                 return -EEXIST;
1578
1579         mp_data = meter_profile_data_find_unused(action->mp,
1580                 RTE_DIM(action->mp));
1581         if (!mp_data)
1582                 return -ENOSPC;
1583
1584         /* Install new profile */
1585         status = rte_meter_trtcm_profile_config(&mp_data->profile,
1586                 &profile->trtcm);
1587         if (status)
1588                 return status;
1589
1590         mp_data->profile_id = meter_profile_id;
1591         mp_data->valid = 1;
1592
1593         return 0;
1594 }
1595
1596 int
1597 rte_table_action_meter_profile_delete(struct rte_table_action *action,
1598         uint32_t meter_profile_id)
1599 {
1600         struct meter_profile_data *mp_data;
1601
1602         /* Check input arguments */
1603         if ((action == NULL) ||
1604                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
1605                 return -EINVAL;
1606
1607         mp_data = meter_profile_data_find(action->mp,
1608                 RTE_DIM(action->mp),
1609                 meter_profile_id);
1610         if (!mp_data)
1611                 return 0;
1612
1613         /* Uninstall profile */
1614         mp_data->valid = 0;
1615
1616         return 0;
1617 }
1618
1619 int
1620 rte_table_action_meter_read(struct rte_table_action *action,
1621         void *data,
1622         uint32_t tc_mask,
1623         struct rte_table_action_mtr_counters *stats,
1624         int clear)
1625 {
1626         struct mtr_trtcm_data *mtr_data;
1627         uint32_t i;
1628
1629         /* Check input arguments */
1630         if ((action == NULL) ||
1631                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
1632                 (data == NULL) ||
1633                 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
1634                 return -EINVAL;
1635
1636         mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
1637
1638         /* Read */
1639         if (stats) {
1640                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
1641                         struct rte_table_action_mtr_counters_tc *dst =
1642                                 &stats->stats[i];
1643                         struct mtr_trtcm_data *src = &mtr_data[i];
1644
1645                         if ((tc_mask & (1 << i)) == 0)
1646                                 continue;
1647
1648                         dst->n_packets[e_RTE_METER_GREEN] =
1649                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
1650
1651                         dst->n_packets[e_RTE_METER_YELLOW] =
1652                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
1653
1654                         dst->n_packets[e_RTE_METER_RED] =
1655                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
1656
1657                         dst->n_packets_valid = 1;
1658                         dst->n_bytes_valid = 0;
1659                 }
1660
1661                 stats->tc_mask = tc_mask;
1662         }
1663
1664         /* Clear */
1665         if (clear)
1666                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
1667                         struct mtr_trtcm_data *src = &mtr_data[i];
1668
1669                         if ((tc_mask & (1 << i)) == 0)
1670                                 continue;
1671
1672                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
1673                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
1674                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
1675                 }
1676
1677
1678         return 0;
1679 }
1680
1681 int
1682 rte_table_action_ttl_read(struct rte_table_action *action,
1683         void *data,
1684         struct rte_table_action_ttl_counters *stats,
1685         int clear)
1686 {
1687         struct ttl_data *ttl_data;
1688
1689         /* Check input arguments */
1690         if ((action == NULL) ||
1691                 ((action->cfg.action_mask &
1692                 (1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
1693                 (data == NULL))
1694                 return -EINVAL;
1695
1696         ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
1697
1698         /* Read */
1699         if (stats)
1700                 stats->n_packets = TTL_STATS_READ(ttl_data);
1701
1702         /* Clear */
1703         if (clear)
1704                 TTL_STATS_RESET(ttl_data);
1705
1706         return 0;
1707 }
1708
1709 int
1710 rte_table_action_stats_read(struct rte_table_action *action,
1711         void *data,
1712         struct rte_table_action_stats_counters *stats,
1713         int clear)
1714 {
1715         struct stats_data *stats_data;
1716
1717         /* Check input arguments */
1718         if ((action == NULL) ||
1719                 ((action->cfg.action_mask &
1720                 (1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
1721                 (data == NULL))
1722                 return -EINVAL;
1723
1724         stats_data = action_data_get(data, action,
1725                 RTE_TABLE_ACTION_STATS);
1726
1727         /* Read */
1728         if (stats) {
1729                 stats->n_packets = stats_data->n_packets;
1730                 stats->n_bytes = stats_data->n_bytes;
1731                 stats->n_packets_valid = 1;
1732                 stats->n_bytes_valid = 1;
1733         }
1734
1735         /* Clear */
1736         if (clear) {
1737                 stats_data->n_packets = 0;
1738                 stats_data->n_bytes = 0;
1739         }
1740
1741         return 0;
1742 }
1743
1744 static __rte_always_inline uint64_t
1745 pkt_work(struct rte_mbuf *mbuf,
1746         struct rte_pipeline_table_entry *table_entry,
1747         uint64_t time,
1748         struct rte_table_action *action,
1749         struct ap_config *cfg)
1750 {
1751         uint64_t drop_mask = 0;
1752
1753         uint32_t ip_offset = action->cfg.common.ip_offset;
1754         void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
1755
1756         uint32_t dscp;
1757         uint16_t total_length;
1758
1759         if (cfg->common.ip_version) {
1760                 struct ipv4_hdr *hdr = ip;
1761
1762                 dscp = hdr->type_of_service >> 2;
1763                 total_length = rte_ntohs(hdr->total_length);
1764         } else {
1765                 struct ipv6_hdr *hdr = ip;
1766
1767                 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
1768                 total_length =
1769                         rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
1770         }
1771
1772         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1773                 void *data =
1774                         action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
1775
1776                 drop_mask |= pkt_work_mtr(mbuf,
1777                         data,
1778                         &action->dscp_table,
1779                         action->mp,
1780                         time,
1781                         dscp,
1782                         total_length);
1783         }
1784
1785         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1786                 void *data =
1787                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
1788
1789                 pkt_work_tm(mbuf,
1790                         data,
1791                         &action->dscp_table,
1792                         dscp);
1793         }
1794
1795         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1796                 void *data =
1797                         action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
1798
1799                 pkt_work_encap(mbuf,
1800                         data,
1801                         &cfg->encap,
1802                         ip,
1803                         total_length,
1804                         ip_offset);
1805         }
1806
1807         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1808                 void *data =
1809                         action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
1810
1811                 if (cfg->common.ip_version)
1812                         pkt_ipv4_work_nat(ip, data, &cfg->nat);
1813                 else
1814                         pkt_ipv6_work_nat(ip, data, &cfg->nat);
1815         }
1816
1817         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
1818                 void *data =
1819                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
1820
1821                 if (cfg->common.ip_version)
1822                         drop_mask |= pkt_ipv4_work_ttl(ip, data);
1823                 else
1824                         drop_mask |= pkt_ipv6_work_ttl(ip, data);
1825         }
1826
1827         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
1828                 void *data =
1829                         action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
1830
1831                 pkt_work_stats(data, total_length);
1832         }
1833
1834         return drop_mask;
1835 }
1836
1837 static __rte_always_inline uint64_t
1838 pkt4_work(struct rte_mbuf **mbufs,
1839         struct rte_pipeline_table_entry **table_entries,
1840         uint64_t time,
1841         struct rte_table_action *action,
1842         struct ap_config *cfg)
1843 {
1844         uint64_t drop_mask0 = 0;
1845         uint64_t drop_mask1 = 0;
1846         uint64_t drop_mask2 = 0;
1847         uint64_t drop_mask3 = 0;
1848
1849         struct rte_mbuf *mbuf0 = mbufs[0];
1850         struct rte_mbuf *mbuf1 = mbufs[1];
1851         struct rte_mbuf *mbuf2 = mbufs[2];
1852         struct rte_mbuf *mbuf3 = mbufs[3];
1853
1854         struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
1855         struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
1856         struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
1857         struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
1858
1859         uint32_t ip_offset = action->cfg.common.ip_offset;
1860         void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
1861         void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
1862         void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
1863         void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
1864
1865         uint32_t dscp0, dscp1, dscp2, dscp3;
1866         uint16_t total_length0, total_length1, total_length2, total_length3;
1867
1868         if (cfg->common.ip_version) {
1869                 struct ipv4_hdr *hdr0 = ip0;
1870                 struct ipv4_hdr *hdr1 = ip1;
1871                 struct ipv4_hdr *hdr2 = ip2;
1872                 struct ipv4_hdr *hdr3 = ip3;
1873
1874                 dscp0 = hdr0->type_of_service >> 2;
1875                 dscp1 = hdr1->type_of_service >> 2;
1876                 dscp2 = hdr2->type_of_service >> 2;
1877                 dscp3 = hdr3->type_of_service >> 2;
1878
1879                 total_length0 = rte_ntohs(hdr0->total_length);
1880                 total_length1 = rte_ntohs(hdr1->total_length);
1881                 total_length2 = rte_ntohs(hdr2->total_length);
1882                 total_length3 = rte_ntohs(hdr3->total_length);
1883         } else {
1884                 struct ipv6_hdr *hdr0 = ip0;
1885                 struct ipv6_hdr *hdr1 = ip1;
1886                 struct ipv6_hdr *hdr2 = ip2;
1887                 struct ipv6_hdr *hdr3 = ip3;
1888
1889                 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
1890                 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
1891                 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
1892                 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
1893
1894                 total_length0 =
1895                         rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
1896                 total_length1 =
1897                         rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
1898                 total_length2 =
1899                         rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
1900                 total_length3 =
1901                         rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
1902         }
1903
1904         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1905                 void *data0 =
1906                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
1907                 void *data1 =
1908                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
1909                 void *data2 =
1910                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
1911                 void *data3 =
1912                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
1913
1914                 drop_mask0 |= pkt_work_mtr(mbuf0,
1915                         data0,
1916                         &action->dscp_table,
1917                         action->mp,
1918                         time,
1919                         dscp0,
1920                         total_length0);
1921
1922                 drop_mask1 |= pkt_work_mtr(mbuf1,
1923                         data1,
1924                         &action->dscp_table,
1925                         action->mp,
1926                         time,
1927                         dscp1,
1928                         total_length1);
1929
1930                 drop_mask2 |= pkt_work_mtr(mbuf2,
1931                         data2,
1932                         &action->dscp_table,
1933                         action->mp,
1934                         time,
1935                         dscp2,
1936                         total_length2);
1937
1938                 drop_mask3 |= pkt_work_mtr(mbuf3,
1939                         data3,
1940                         &action->dscp_table,
1941                         action->mp,
1942                         time,
1943                         dscp3,
1944                         total_length3);
1945         }
1946
1947         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1948                 void *data0 =
1949                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
1950                 void *data1 =
1951                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
1952                 void *data2 =
1953                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
1954                 void *data3 =
1955                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
1956
1957                 pkt_work_tm(mbuf0,
1958                         data0,
1959                         &action->dscp_table,
1960                         dscp0);
1961
1962                 pkt_work_tm(mbuf1,
1963                         data1,
1964                         &action->dscp_table,
1965                         dscp1);
1966
1967                 pkt_work_tm(mbuf2,
1968                         data2,
1969                         &action->dscp_table,
1970                         dscp2);
1971
1972                 pkt_work_tm(mbuf3,
1973                         data3,
1974                         &action->dscp_table,
1975                         dscp3);
1976         }
1977
1978         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1979                 void *data0 =
1980                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
1981                 void *data1 =
1982                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
1983                 void *data2 =
1984                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
1985                 void *data3 =
1986                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
1987
1988                 pkt_work_encap(mbuf0,
1989                         data0,
1990                         &cfg->encap,
1991                         ip0,
1992                         total_length0,
1993                         ip_offset);
1994
1995                 pkt_work_encap(mbuf1,
1996                         data1,
1997                         &cfg->encap,
1998                         ip1,
1999                         total_length1,
2000                         ip_offset);
2001
2002                 pkt_work_encap(mbuf2,
2003                         data2,
2004                         &cfg->encap,
2005                         ip2,
2006                         total_length2,
2007                         ip_offset);
2008
2009                 pkt_work_encap(mbuf3,
2010                         data3,
2011                         &cfg->encap,
2012                         ip3,
2013                         total_length3,
2014                         ip_offset);
2015         }
2016
2017         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2018                 void *data0 =
2019                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
2020                 void *data1 =
2021                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
2022                 void *data2 =
2023                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
2024                 void *data3 =
2025                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
2026
2027                 if (cfg->common.ip_version) {
2028                         pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
2029                         pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
2030                         pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
2031                         pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
2032                 } else {
2033                         pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
2034                         pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
2035                         pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
2036                         pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
2037                 }
2038         }
2039
2040         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2041                 void *data0 =
2042                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
2043                 void *data1 =
2044                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
2045                 void *data2 =
2046                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
2047                 void *data3 =
2048                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
2049
2050                 if (cfg->common.ip_version) {
2051                         drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
2052                         drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
2053                         drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
2054                         drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
2055                 } else {
2056                         drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
2057                         drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
2058                         drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
2059                         drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
2060                 }
2061         }
2062
2063         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2064                 void *data0 =
2065                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
2066                 void *data1 =
2067                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
2068                 void *data2 =
2069                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
2070                 void *data3 =
2071                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
2072
2073                 pkt_work_stats(data0, total_length0);
2074                 pkt_work_stats(data1, total_length1);
2075                 pkt_work_stats(data2, total_length2);
2076                 pkt_work_stats(data3, total_length3);
2077         }
2078
2079         return drop_mask0 |
2080                 (drop_mask1 << 1) |
2081                 (drop_mask2 << 2) |
2082                 (drop_mask3 << 3);
2083 }
2084
2085 static __rte_always_inline int
2086 ah(struct rte_pipeline *p,
2087         struct rte_mbuf **pkts,
2088         uint64_t pkts_mask,
2089         struct rte_pipeline_table_entry **entries,
2090         struct rte_table_action *action,
2091         struct ap_config *cfg)
2092 {
2093         uint64_t pkts_drop_mask = 0;
2094         uint64_t time = 0;
2095
2096         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
2097                 time = rte_rdtsc();
2098
2099         if ((pkts_mask & (pkts_mask + 1)) == 0) {
2100                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
2101                 uint32_t i;
2102
2103                 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2104                         uint64_t drop_mask;
2105
2106                         drop_mask = pkt4_work(&pkts[i],
2107                                 &entries[i],
2108                                 time,
2109                                 action,
2110                                 cfg);
2111
2112                         pkts_drop_mask |= drop_mask << i;
2113                 }
2114
2115                 for ( ; i < n_pkts; i++) {
2116                         uint64_t drop_mask;
2117
2118                         drop_mask = pkt_work(pkts[i],
2119                                 entries[i],
2120                                 time,
2121                                 action,
2122                                 cfg);
2123
2124                         pkts_drop_mask |= drop_mask << i;
2125                 }
2126         } else
2127                 for ( ; pkts_mask; ) {
2128                         uint32_t pos = __builtin_ctzll(pkts_mask);
2129                         uint64_t pkt_mask = 1LLU << pos;
2130                         uint64_t drop_mask;
2131
2132                         drop_mask = pkt_work(pkts[pos],
2133                                 entries[pos],
2134                                 time,
2135                                 action,
2136                                 cfg);
2137
2138                         pkts_mask &= ~pkt_mask;
2139                         pkts_drop_mask |= drop_mask << pos;
2140                 }
2141
2142         rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2143
2144         return 0;
2145 }
2146
2147 static int
2148 ah_default(struct rte_pipeline *p,
2149         struct rte_mbuf **pkts,
2150         uint64_t pkts_mask,
2151         struct rte_pipeline_table_entry **entries,
2152         void *arg)
2153 {
2154         struct rte_table_action *action = arg;
2155
2156         return ah(p,
2157                 pkts,
2158                 pkts_mask,
2159                 entries,
2160                 action,
2161                 &action->cfg);
2162 }
2163
2164 static rte_pipeline_table_action_handler_hit
2165 ah_selector(struct rte_table_action *action)
2166 {
2167         if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
2168                 return NULL;
2169
2170         return ah_default;
2171 }
2172
2173 int
2174 rte_table_action_table_params_get(struct rte_table_action *action,
2175         struct rte_pipeline_table_params *params)
2176 {
2177         rte_pipeline_table_action_handler_hit f_action_hit;
2178         uint32_t total_size;
2179
2180         /* Check input arguments */
2181         if ((action == NULL) ||
2182                 (params == NULL))
2183                 return -EINVAL;
2184
2185         f_action_hit = ah_selector(action);
2186         total_size = rte_align32pow2(action->data.total_size);
2187
2188         /* Fill in params */
2189         params->f_action_hit = f_action_hit;
2190         params->f_action_miss = NULL;
2191         params->arg_ah = (f_action_hit) ? action : NULL;
2192         params->action_data_size = total_size -
2193                 sizeof(struct rte_pipeline_table_entry);
2194
2195         return 0;
2196 }
2197
2198 int
2199 rte_table_action_free(struct rte_table_action *action)
2200 {
2201         if (action == NULL)
2202                 return 0;
2203
2204         rte_free(action);
2205
2206         return 0;
2207 }