1a32c71d72c60ddef652fef97d40ffa302094542
[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  * RTE_TABLE_ACTION_TIME
1153  */
1154 struct time_data {
1155         uint64_t time;
1156 } __attribute__((__packed__));
1157
1158 static int
1159 time_apply(struct time_data *data,
1160         struct rte_table_action_time_params *p)
1161 {
1162         data->time = p->time;
1163         return 0;
1164 }
1165
1166 static __rte_always_inline void
1167 pkt_work_time(struct time_data *data,
1168         uint64_t time)
1169 {
1170         data->time = time;
1171 }
1172
1173 /**
1174  * Action profile
1175  */
1176 static int
1177 action_valid(enum rte_table_action_type action)
1178 {
1179         switch (action) {
1180         case RTE_TABLE_ACTION_FWD:
1181         case RTE_TABLE_ACTION_MTR:
1182         case RTE_TABLE_ACTION_TM:
1183         case RTE_TABLE_ACTION_ENCAP:
1184         case RTE_TABLE_ACTION_NAT:
1185         case RTE_TABLE_ACTION_TTL:
1186         case RTE_TABLE_ACTION_STATS:
1187         case RTE_TABLE_ACTION_TIME:
1188                 return 1;
1189         default:
1190                 return 0;
1191         }
1192 }
1193
1194
1195 #define RTE_TABLE_ACTION_MAX                      64
1196
1197 struct ap_config {
1198         uint64_t action_mask;
1199         struct rte_table_action_common_config common;
1200         struct rte_table_action_mtr_config mtr;
1201         struct rte_table_action_tm_config tm;
1202         struct rte_table_action_encap_config encap;
1203         struct rte_table_action_nat_config nat;
1204         struct rte_table_action_ttl_config ttl;
1205         struct rte_table_action_stats_config stats;
1206 };
1207
1208 static size_t
1209 action_cfg_size(enum rte_table_action_type action)
1210 {
1211         switch (action) {
1212         case RTE_TABLE_ACTION_MTR:
1213                 return sizeof(struct rte_table_action_mtr_config);
1214         case RTE_TABLE_ACTION_TM:
1215                 return sizeof(struct rte_table_action_tm_config);
1216         case RTE_TABLE_ACTION_ENCAP:
1217                 return sizeof(struct rte_table_action_encap_config);
1218         case RTE_TABLE_ACTION_NAT:
1219                 return sizeof(struct rte_table_action_nat_config);
1220         case RTE_TABLE_ACTION_TTL:
1221                 return sizeof(struct rte_table_action_ttl_config);
1222         case RTE_TABLE_ACTION_STATS:
1223                 return sizeof(struct rte_table_action_stats_config);
1224         default:
1225                 return 0;
1226         }
1227 }
1228
1229 static void*
1230 action_cfg_get(struct ap_config *ap_config,
1231         enum rte_table_action_type type)
1232 {
1233         switch (type) {
1234         case RTE_TABLE_ACTION_MTR:
1235                 return &ap_config->mtr;
1236
1237         case RTE_TABLE_ACTION_TM:
1238                 return &ap_config->tm;
1239
1240         case RTE_TABLE_ACTION_ENCAP:
1241                 return &ap_config->encap;
1242
1243         case RTE_TABLE_ACTION_NAT:
1244                 return &ap_config->nat;
1245
1246         case RTE_TABLE_ACTION_TTL:
1247                 return &ap_config->ttl;
1248
1249         case RTE_TABLE_ACTION_STATS:
1250                 return &ap_config->stats;
1251
1252         default:
1253                 return NULL;
1254         }
1255 }
1256
1257 static void
1258 action_cfg_set(struct ap_config *ap_config,
1259         enum rte_table_action_type type,
1260         void *action_cfg)
1261 {
1262         void *dst = action_cfg_get(ap_config, type);
1263
1264         if (dst)
1265                 memcpy(dst, action_cfg, action_cfg_size(type));
1266
1267         ap_config->action_mask |= 1LLU << type;
1268 }
1269
1270 struct ap_data {
1271         size_t offset[RTE_TABLE_ACTION_MAX];
1272         size_t total_size;
1273 };
1274
1275 static size_t
1276 action_data_size(enum rte_table_action_type action,
1277         struct ap_config *ap_config)
1278 {
1279         switch (action) {
1280         case RTE_TABLE_ACTION_FWD:
1281                 return sizeof(struct fwd_data);
1282
1283         case RTE_TABLE_ACTION_MTR:
1284                 return mtr_data_size(&ap_config->mtr);
1285
1286         case RTE_TABLE_ACTION_TM:
1287                 return sizeof(struct tm_data);
1288
1289         case RTE_TABLE_ACTION_ENCAP:
1290                 return encap_data_size(&ap_config->encap);
1291
1292         case RTE_TABLE_ACTION_NAT:
1293                 return nat_data_size(&ap_config->nat,
1294                         &ap_config->common);
1295
1296         case RTE_TABLE_ACTION_TTL:
1297                 return sizeof(struct ttl_data);
1298
1299         case RTE_TABLE_ACTION_STATS:
1300                 return sizeof(struct stats_data);
1301
1302         case RTE_TABLE_ACTION_TIME:
1303                 return sizeof(struct time_data);
1304
1305         default:
1306                 return 0;
1307         }
1308 }
1309
1310
1311 static void
1312 action_data_offset_set(struct ap_data *ap_data,
1313         struct ap_config *ap_config)
1314 {
1315         uint64_t action_mask = ap_config->action_mask;
1316         size_t offset;
1317         uint32_t action;
1318
1319         memset(ap_data->offset, 0, sizeof(ap_data->offset));
1320
1321         offset = 0;
1322         for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
1323                 if (action_mask & (1LLU << action)) {
1324                         ap_data->offset[action] = offset;
1325                         offset += action_data_size((enum rte_table_action_type)action,
1326                                 ap_config);
1327                 }
1328
1329         ap_data->total_size = offset;
1330 }
1331
1332 struct rte_table_action_profile {
1333         struct ap_config cfg;
1334         struct ap_data data;
1335         int frozen;
1336 };
1337
1338 struct rte_table_action_profile *
1339 rte_table_action_profile_create(struct rte_table_action_common_config *common)
1340 {
1341         struct rte_table_action_profile *ap;
1342
1343         /* Check input arguments */
1344         if (common == NULL)
1345                 return NULL;
1346
1347         /* Memory allocation */
1348         ap = calloc(1, sizeof(struct rte_table_action_profile));
1349         if (ap == NULL)
1350                 return NULL;
1351
1352         /* Initialization */
1353         memcpy(&ap->cfg.common, common, sizeof(*common));
1354
1355         return ap;
1356 }
1357
1358
1359 int
1360 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
1361         enum rte_table_action_type type,
1362         void *action_config)
1363 {
1364         int status;
1365
1366         /* Check input arguments */
1367         if ((profile == NULL) ||
1368                 profile->frozen ||
1369                 (action_valid(type) == 0) ||
1370                 (profile->cfg.action_mask & (1LLU << type)) ||
1371                 ((action_cfg_size(type) == 0) && action_config) ||
1372                 (action_cfg_size(type) && (action_config == NULL)))
1373                 return -EINVAL;
1374
1375         switch (type) {
1376         case RTE_TABLE_ACTION_MTR:
1377                 status = mtr_cfg_check(action_config);
1378                 break;
1379
1380         case RTE_TABLE_ACTION_TM:
1381                 status = tm_cfg_check(action_config);
1382                 break;
1383
1384         case RTE_TABLE_ACTION_ENCAP:
1385                 status = encap_cfg_check(action_config);
1386                 break;
1387
1388         case RTE_TABLE_ACTION_NAT:
1389                 status = nat_cfg_check(action_config);
1390                 break;
1391
1392         case RTE_TABLE_ACTION_TTL:
1393                 status = ttl_cfg_check(action_config);
1394                 break;
1395
1396         case RTE_TABLE_ACTION_STATS:
1397                 status = stats_cfg_check(action_config);
1398                 break;
1399
1400         default:
1401                 status = 0;
1402                 break;
1403         }
1404
1405         if (status)
1406                 return status;
1407
1408         /* Action enable */
1409         action_cfg_set(&profile->cfg, type, action_config);
1410
1411         return 0;
1412 }
1413
1414 int
1415 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
1416 {
1417         if (profile->frozen)
1418                 return -EBUSY;
1419
1420         profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1421         action_data_offset_set(&profile->data, &profile->cfg);
1422         profile->frozen = 1;
1423
1424         return 0;
1425 }
1426
1427 int
1428 rte_table_action_profile_free(struct rte_table_action_profile *profile)
1429 {
1430         if (profile == NULL)
1431                 return 0;
1432
1433         free(profile);
1434         return 0;
1435 }
1436
1437 /**
1438  * Action
1439  */
1440 #define METER_PROFILES_MAX                                 32
1441
1442 struct rte_table_action {
1443         struct ap_config cfg;
1444         struct ap_data data;
1445         struct dscp_table_data dscp_table;
1446         struct meter_profile_data mp[METER_PROFILES_MAX];
1447 };
1448
1449 struct rte_table_action *
1450 rte_table_action_create(struct rte_table_action_profile *profile,
1451         uint32_t socket_id)
1452 {
1453         struct rte_table_action *action;
1454
1455         /* Check input arguments */
1456         if ((profile == NULL) ||
1457                 (profile->frozen == 0))
1458                 return NULL;
1459
1460         /* Memory allocation */
1461         action = rte_zmalloc_socket(NULL,
1462                 sizeof(struct rte_table_action),
1463                 RTE_CACHE_LINE_SIZE,
1464                 socket_id);
1465         if (action == NULL)
1466                 return NULL;
1467
1468         /* Initialization */
1469         memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
1470         memcpy(&action->data, &profile->data, sizeof(profile->data));
1471
1472         return action;
1473 }
1474
1475 static __rte_always_inline void *
1476 action_data_get(void *data,
1477         struct rte_table_action *action,
1478         enum rte_table_action_type type)
1479 {
1480         size_t offset = action->data.offset[type];
1481         uint8_t *data_bytes = data;
1482
1483         return &data_bytes[offset];
1484 }
1485
1486 int
1487 rte_table_action_apply(struct rte_table_action *action,
1488         void *data,
1489         enum rte_table_action_type type,
1490         void *action_params)
1491 {
1492         void *action_data;
1493
1494         /* Check input arguments */
1495         if ((action == NULL) ||
1496                 (data == NULL) ||
1497                 (action_valid(type) == 0) ||
1498                 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
1499                 (action_params == NULL))
1500                 return -EINVAL;
1501
1502         /* Data update */
1503         action_data = action_data_get(data, action, type);
1504
1505         switch (type) {
1506         case RTE_TABLE_ACTION_FWD:
1507                 return fwd_apply(action_data,
1508                         action_params);
1509
1510         case RTE_TABLE_ACTION_MTR:
1511                 return mtr_apply(action_data,
1512                         action_params,
1513                         &action->cfg.mtr,
1514                         action->mp,
1515                         RTE_DIM(action->mp));
1516
1517         case RTE_TABLE_ACTION_TM:
1518                 return tm_apply(action_data,
1519                         action_params,
1520                         &action->cfg.tm);
1521
1522         case RTE_TABLE_ACTION_ENCAP:
1523                 return encap_apply(action_data,
1524                         action_params,
1525                         &action->cfg.encap,
1526                         &action->cfg.common);
1527
1528         case RTE_TABLE_ACTION_NAT:
1529                 return nat_apply(action_data,
1530                         action_params,
1531                         &action->cfg.common);
1532
1533         case RTE_TABLE_ACTION_TTL:
1534                 return ttl_apply(action_data,
1535                         action_params);
1536
1537         case RTE_TABLE_ACTION_STATS:
1538                 return stats_apply(action_data,
1539                         action_params);
1540
1541         case RTE_TABLE_ACTION_TIME:
1542                 return time_apply(action_data,
1543                         action_params);
1544
1545         default:
1546                 return -EINVAL;
1547         }
1548 }
1549
1550 int
1551 rte_table_action_dscp_table_update(struct rte_table_action *action,
1552         uint64_t dscp_mask,
1553         struct rte_table_action_dscp_table *table)
1554 {
1555         uint32_t i;
1556
1557         /* Check input arguments */
1558         if ((action == NULL) ||
1559                 ((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
1560                 (1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
1561                 (dscp_mask == 0) ||
1562                 (table == NULL))
1563                 return -EINVAL;
1564
1565         for (i = 0; i < RTE_DIM(table->entry); i++) {
1566                 struct dscp_table_entry_data *data =
1567                         &action->dscp_table.entry[i];
1568                 struct rte_table_action_dscp_table_entry *entry =
1569                         &table->entry[i];
1570                 uint16_t queue_tc_color =
1571                         MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
1572                                 entry->tc_id,
1573                                 entry->color);
1574
1575                 if ((dscp_mask & (1LLU << i)) == 0)
1576                         continue;
1577
1578                 data->color = entry->color;
1579                 data->tc = entry->tc_id;
1580                 data->queue_tc_color = queue_tc_color;
1581         }
1582
1583         return 0;
1584 }
1585
1586 int
1587 rte_table_action_meter_profile_add(struct rte_table_action *action,
1588         uint32_t meter_profile_id,
1589         struct rte_table_action_meter_profile *profile)
1590 {
1591         struct meter_profile_data *mp_data;
1592         uint32_t status;
1593
1594         /* Check input arguments */
1595         if ((action == NULL) ||
1596                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
1597                 (profile == NULL))
1598                 return -EINVAL;
1599
1600         if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
1601                 return -ENOTSUP;
1602
1603         mp_data = meter_profile_data_find(action->mp,
1604                 RTE_DIM(action->mp),
1605                 meter_profile_id);
1606         if (mp_data)
1607                 return -EEXIST;
1608
1609         mp_data = meter_profile_data_find_unused(action->mp,
1610                 RTE_DIM(action->mp));
1611         if (!mp_data)
1612                 return -ENOSPC;
1613
1614         /* Install new profile */
1615         status = rte_meter_trtcm_profile_config(&mp_data->profile,
1616                 &profile->trtcm);
1617         if (status)
1618                 return status;
1619
1620         mp_data->profile_id = meter_profile_id;
1621         mp_data->valid = 1;
1622
1623         return 0;
1624 }
1625
1626 int
1627 rte_table_action_meter_profile_delete(struct rte_table_action *action,
1628         uint32_t meter_profile_id)
1629 {
1630         struct meter_profile_data *mp_data;
1631
1632         /* Check input arguments */
1633         if ((action == NULL) ||
1634                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
1635                 return -EINVAL;
1636
1637         mp_data = meter_profile_data_find(action->mp,
1638                 RTE_DIM(action->mp),
1639                 meter_profile_id);
1640         if (!mp_data)
1641                 return 0;
1642
1643         /* Uninstall profile */
1644         mp_data->valid = 0;
1645
1646         return 0;
1647 }
1648
1649 int
1650 rte_table_action_meter_read(struct rte_table_action *action,
1651         void *data,
1652         uint32_t tc_mask,
1653         struct rte_table_action_mtr_counters *stats,
1654         int clear)
1655 {
1656         struct mtr_trtcm_data *mtr_data;
1657         uint32_t i;
1658
1659         /* Check input arguments */
1660         if ((action == NULL) ||
1661                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
1662                 (data == NULL) ||
1663                 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
1664                 return -EINVAL;
1665
1666         mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
1667
1668         /* Read */
1669         if (stats) {
1670                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
1671                         struct rte_table_action_mtr_counters_tc *dst =
1672                                 &stats->stats[i];
1673                         struct mtr_trtcm_data *src = &mtr_data[i];
1674
1675                         if ((tc_mask & (1 << i)) == 0)
1676                                 continue;
1677
1678                         dst->n_packets[e_RTE_METER_GREEN] =
1679                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
1680
1681                         dst->n_packets[e_RTE_METER_YELLOW] =
1682                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
1683
1684                         dst->n_packets[e_RTE_METER_RED] =
1685                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
1686
1687                         dst->n_packets_valid = 1;
1688                         dst->n_bytes_valid = 0;
1689                 }
1690
1691                 stats->tc_mask = tc_mask;
1692         }
1693
1694         /* Clear */
1695         if (clear)
1696                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
1697                         struct mtr_trtcm_data *src = &mtr_data[i];
1698
1699                         if ((tc_mask & (1 << i)) == 0)
1700                                 continue;
1701
1702                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
1703                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
1704                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
1705                 }
1706
1707
1708         return 0;
1709 }
1710
1711 int
1712 rte_table_action_ttl_read(struct rte_table_action *action,
1713         void *data,
1714         struct rte_table_action_ttl_counters *stats,
1715         int clear)
1716 {
1717         struct ttl_data *ttl_data;
1718
1719         /* Check input arguments */
1720         if ((action == NULL) ||
1721                 ((action->cfg.action_mask &
1722                 (1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
1723                 (data == NULL))
1724                 return -EINVAL;
1725
1726         ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
1727
1728         /* Read */
1729         if (stats)
1730                 stats->n_packets = TTL_STATS_READ(ttl_data);
1731
1732         /* Clear */
1733         if (clear)
1734                 TTL_STATS_RESET(ttl_data);
1735
1736         return 0;
1737 }
1738
1739 int
1740 rte_table_action_stats_read(struct rte_table_action *action,
1741         void *data,
1742         struct rte_table_action_stats_counters *stats,
1743         int clear)
1744 {
1745         struct stats_data *stats_data;
1746
1747         /* Check input arguments */
1748         if ((action == NULL) ||
1749                 ((action->cfg.action_mask &
1750                 (1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
1751                 (data == NULL))
1752                 return -EINVAL;
1753
1754         stats_data = action_data_get(data, action,
1755                 RTE_TABLE_ACTION_STATS);
1756
1757         /* Read */
1758         if (stats) {
1759                 stats->n_packets = stats_data->n_packets;
1760                 stats->n_bytes = stats_data->n_bytes;
1761                 stats->n_packets_valid = 1;
1762                 stats->n_bytes_valid = 1;
1763         }
1764
1765         /* Clear */
1766         if (clear) {
1767                 stats_data->n_packets = 0;
1768                 stats_data->n_bytes = 0;
1769         }
1770
1771         return 0;
1772 }
1773
1774 int
1775 rte_table_action_time_read(struct rte_table_action *action,
1776         void *data,
1777         uint64_t *timestamp)
1778 {
1779         struct time_data *time_data;
1780
1781         /* Check input arguments */
1782         if ((action == NULL) ||
1783                 ((action->cfg.action_mask &
1784                 (1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
1785                 (data == NULL) ||
1786                 (timestamp == NULL))
1787                 return -EINVAL;
1788
1789         time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
1790
1791         /* Read */
1792         *timestamp = time_data->time;
1793
1794         return 0;
1795 }
1796
1797 static __rte_always_inline uint64_t
1798 pkt_work(struct rte_mbuf *mbuf,
1799         struct rte_pipeline_table_entry *table_entry,
1800         uint64_t time,
1801         struct rte_table_action *action,
1802         struct ap_config *cfg)
1803 {
1804         uint64_t drop_mask = 0;
1805
1806         uint32_t ip_offset = action->cfg.common.ip_offset;
1807         void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
1808
1809         uint32_t dscp;
1810         uint16_t total_length;
1811
1812         if (cfg->common.ip_version) {
1813                 struct ipv4_hdr *hdr = ip;
1814
1815                 dscp = hdr->type_of_service >> 2;
1816                 total_length = rte_ntohs(hdr->total_length);
1817         } else {
1818                 struct ipv6_hdr *hdr = ip;
1819
1820                 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
1821                 total_length =
1822                         rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
1823         }
1824
1825         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1826                 void *data =
1827                         action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
1828
1829                 drop_mask |= pkt_work_mtr(mbuf,
1830                         data,
1831                         &action->dscp_table,
1832                         action->mp,
1833                         time,
1834                         dscp,
1835                         total_length);
1836         }
1837
1838         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1839                 void *data =
1840                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
1841
1842                 pkt_work_tm(mbuf,
1843                         data,
1844                         &action->dscp_table,
1845                         dscp);
1846         }
1847
1848         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1849                 void *data =
1850                         action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
1851
1852                 pkt_work_encap(mbuf,
1853                         data,
1854                         &cfg->encap,
1855                         ip,
1856                         total_length,
1857                         ip_offset);
1858         }
1859
1860         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1861                 void *data =
1862                         action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
1863
1864                 if (cfg->common.ip_version)
1865                         pkt_ipv4_work_nat(ip, data, &cfg->nat);
1866                 else
1867                         pkt_ipv6_work_nat(ip, data, &cfg->nat);
1868         }
1869
1870         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
1871                 void *data =
1872                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
1873
1874                 if (cfg->common.ip_version)
1875                         drop_mask |= pkt_ipv4_work_ttl(ip, data);
1876                 else
1877                         drop_mask |= pkt_ipv6_work_ttl(ip, data);
1878         }
1879
1880         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
1881                 void *data =
1882                         action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
1883
1884                 pkt_work_stats(data, total_length);
1885         }
1886
1887         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
1888                 void *data =
1889                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
1890
1891                 pkt_work_time(data, time);
1892         }
1893
1894         return drop_mask;
1895 }
1896
1897 static __rte_always_inline uint64_t
1898 pkt4_work(struct rte_mbuf **mbufs,
1899         struct rte_pipeline_table_entry **table_entries,
1900         uint64_t time,
1901         struct rte_table_action *action,
1902         struct ap_config *cfg)
1903 {
1904         uint64_t drop_mask0 = 0;
1905         uint64_t drop_mask1 = 0;
1906         uint64_t drop_mask2 = 0;
1907         uint64_t drop_mask3 = 0;
1908
1909         struct rte_mbuf *mbuf0 = mbufs[0];
1910         struct rte_mbuf *mbuf1 = mbufs[1];
1911         struct rte_mbuf *mbuf2 = mbufs[2];
1912         struct rte_mbuf *mbuf3 = mbufs[3];
1913
1914         struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
1915         struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
1916         struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
1917         struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
1918
1919         uint32_t ip_offset = action->cfg.common.ip_offset;
1920         void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
1921         void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
1922         void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
1923         void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
1924
1925         uint32_t dscp0, dscp1, dscp2, dscp3;
1926         uint16_t total_length0, total_length1, total_length2, total_length3;
1927
1928         if (cfg->common.ip_version) {
1929                 struct ipv4_hdr *hdr0 = ip0;
1930                 struct ipv4_hdr *hdr1 = ip1;
1931                 struct ipv4_hdr *hdr2 = ip2;
1932                 struct ipv4_hdr *hdr3 = ip3;
1933
1934                 dscp0 = hdr0->type_of_service >> 2;
1935                 dscp1 = hdr1->type_of_service >> 2;
1936                 dscp2 = hdr2->type_of_service >> 2;
1937                 dscp3 = hdr3->type_of_service >> 2;
1938
1939                 total_length0 = rte_ntohs(hdr0->total_length);
1940                 total_length1 = rte_ntohs(hdr1->total_length);
1941                 total_length2 = rte_ntohs(hdr2->total_length);
1942                 total_length3 = rte_ntohs(hdr3->total_length);
1943         } else {
1944                 struct ipv6_hdr *hdr0 = ip0;
1945                 struct ipv6_hdr *hdr1 = ip1;
1946                 struct ipv6_hdr *hdr2 = ip2;
1947                 struct ipv6_hdr *hdr3 = ip3;
1948
1949                 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
1950                 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
1951                 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
1952                 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
1953
1954                 total_length0 =
1955                         rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
1956                 total_length1 =
1957                         rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
1958                 total_length2 =
1959                         rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
1960                 total_length3 =
1961                         rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
1962         }
1963
1964         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1965                 void *data0 =
1966                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
1967                 void *data1 =
1968                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
1969                 void *data2 =
1970                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
1971                 void *data3 =
1972                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
1973
1974                 drop_mask0 |= pkt_work_mtr(mbuf0,
1975                         data0,
1976                         &action->dscp_table,
1977                         action->mp,
1978                         time,
1979                         dscp0,
1980                         total_length0);
1981
1982                 drop_mask1 |= pkt_work_mtr(mbuf1,
1983                         data1,
1984                         &action->dscp_table,
1985                         action->mp,
1986                         time,
1987                         dscp1,
1988                         total_length1);
1989
1990                 drop_mask2 |= pkt_work_mtr(mbuf2,
1991                         data2,
1992                         &action->dscp_table,
1993                         action->mp,
1994                         time,
1995                         dscp2,
1996                         total_length2);
1997
1998                 drop_mask3 |= pkt_work_mtr(mbuf3,
1999                         data3,
2000                         &action->dscp_table,
2001                         action->mp,
2002                         time,
2003                         dscp3,
2004                         total_length3);
2005         }
2006
2007         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2008                 void *data0 =
2009                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
2010                 void *data1 =
2011                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
2012                 void *data2 =
2013                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
2014                 void *data3 =
2015                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
2016
2017                 pkt_work_tm(mbuf0,
2018                         data0,
2019                         &action->dscp_table,
2020                         dscp0);
2021
2022                 pkt_work_tm(mbuf1,
2023                         data1,
2024                         &action->dscp_table,
2025                         dscp1);
2026
2027                 pkt_work_tm(mbuf2,
2028                         data2,
2029                         &action->dscp_table,
2030                         dscp2);
2031
2032                 pkt_work_tm(mbuf3,
2033                         data3,
2034                         &action->dscp_table,
2035                         dscp3);
2036         }
2037
2038         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2039                 void *data0 =
2040                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
2041                 void *data1 =
2042                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
2043                 void *data2 =
2044                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
2045                 void *data3 =
2046                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
2047
2048                 pkt_work_encap(mbuf0,
2049                         data0,
2050                         &cfg->encap,
2051                         ip0,
2052                         total_length0,
2053                         ip_offset);
2054
2055                 pkt_work_encap(mbuf1,
2056                         data1,
2057                         &cfg->encap,
2058                         ip1,
2059                         total_length1,
2060                         ip_offset);
2061
2062                 pkt_work_encap(mbuf2,
2063                         data2,
2064                         &cfg->encap,
2065                         ip2,
2066                         total_length2,
2067                         ip_offset);
2068
2069                 pkt_work_encap(mbuf3,
2070                         data3,
2071                         &cfg->encap,
2072                         ip3,
2073                         total_length3,
2074                         ip_offset);
2075         }
2076
2077         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2078                 void *data0 =
2079                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
2080                 void *data1 =
2081                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
2082                 void *data2 =
2083                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
2084                 void *data3 =
2085                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
2086
2087                 if (cfg->common.ip_version) {
2088                         pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
2089                         pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
2090                         pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
2091                         pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
2092                 } else {
2093                         pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
2094                         pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
2095                         pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
2096                         pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
2097                 }
2098         }
2099
2100         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2101                 void *data0 =
2102                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
2103                 void *data1 =
2104                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
2105                 void *data2 =
2106                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
2107                 void *data3 =
2108                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
2109
2110                 if (cfg->common.ip_version) {
2111                         drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
2112                         drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
2113                         drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
2114                         drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
2115                 } else {
2116                         drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
2117                         drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
2118                         drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
2119                         drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
2120                 }
2121         }
2122
2123         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2124                 void *data0 =
2125                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
2126                 void *data1 =
2127                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
2128                 void *data2 =
2129                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
2130                 void *data3 =
2131                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
2132
2133                 pkt_work_stats(data0, total_length0);
2134                 pkt_work_stats(data1, total_length1);
2135                 pkt_work_stats(data2, total_length2);
2136                 pkt_work_stats(data3, total_length3);
2137         }
2138
2139         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2140                 void *data0 =
2141                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
2142                 void *data1 =
2143                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
2144                 void *data2 =
2145                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
2146                 void *data3 =
2147                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
2148
2149                 pkt_work_time(data0, time);
2150                 pkt_work_time(data1, time);
2151                 pkt_work_time(data2, time);
2152                 pkt_work_time(data3, time);
2153         }
2154
2155         return drop_mask0 |
2156                 (drop_mask1 << 1) |
2157                 (drop_mask2 << 2) |
2158                 (drop_mask3 << 3);
2159 }
2160
2161 static __rte_always_inline int
2162 ah(struct rte_pipeline *p,
2163         struct rte_mbuf **pkts,
2164         uint64_t pkts_mask,
2165         struct rte_pipeline_table_entry **entries,
2166         struct rte_table_action *action,
2167         struct ap_config *cfg)
2168 {
2169         uint64_t pkts_drop_mask = 0;
2170         uint64_t time = 0;
2171
2172         if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
2173                 (1LLU << RTE_TABLE_ACTION_TIME)))
2174                 time = rte_rdtsc();
2175
2176         if ((pkts_mask & (pkts_mask + 1)) == 0) {
2177                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
2178                 uint32_t i;
2179
2180                 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2181                         uint64_t drop_mask;
2182
2183                         drop_mask = pkt4_work(&pkts[i],
2184                                 &entries[i],
2185                                 time,
2186                                 action,
2187                                 cfg);
2188
2189                         pkts_drop_mask |= drop_mask << i;
2190                 }
2191
2192                 for ( ; i < n_pkts; i++) {
2193                         uint64_t drop_mask;
2194
2195                         drop_mask = pkt_work(pkts[i],
2196                                 entries[i],
2197                                 time,
2198                                 action,
2199                                 cfg);
2200
2201                         pkts_drop_mask |= drop_mask << i;
2202                 }
2203         } else
2204                 for ( ; pkts_mask; ) {
2205                         uint32_t pos = __builtin_ctzll(pkts_mask);
2206                         uint64_t pkt_mask = 1LLU << pos;
2207                         uint64_t drop_mask;
2208
2209                         drop_mask = pkt_work(pkts[pos],
2210                                 entries[pos],
2211                                 time,
2212                                 action,
2213                                 cfg);
2214
2215                         pkts_mask &= ~pkt_mask;
2216                         pkts_drop_mask |= drop_mask << pos;
2217                 }
2218
2219         rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2220
2221         return 0;
2222 }
2223
2224 static int
2225 ah_default(struct rte_pipeline *p,
2226         struct rte_mbuf **pkts,
2227         uint64_t pkts_mask,
2228         struct rte_pipeline_table_entry **entries,
2229         void *arg)
2230 {
2231         struct rte_table_action *action = arg;
2232
2233         return ah(p,
2234                 pkts,
2235                 pkts_mask,
2236                 entries,
2237                 action,
2238                 &action->cfg);
2239 }
2240
2241 static rte_pipeline_table_action_handler_hit
2242 ah_selector(struct rte_table_action *action)
2243 {
2244         if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
2245                 return NULL;
2246
2247         return ah_default;
2248 }
2249
2250 int
2251 rte_table_action_table_params_get(struct rte_table_action *action,
2252         struct rte_pipeline_table_params *params)
2253 {
2254         rte_pipeline_table_action_handler_hit f_action_hit;
2255         uint32_t total_size;
2256
2257         /* Check input arguments */
2258         if ((action == NULL) ||
2259                 (params == NULL))
2260                 return -EINVAL;
2261
2262         f_action_hit = ah_selector(action);
2263         total_size = rte_align32pow2(action->data.total_size);
2264
2265         /* Fill in params */
2266         params->f_action_hit = f_action_hit;
2267         params->f_action_miss = NULL;
2268         params->arg_ah = (f_action_hit) ? action : NULL;
2269         params->action_data_size = total_size -
2270                 sizeof(struct rte_pipeline_table_entry);
2271
2272         return 0;
2273 }
2274
2275 int
2276 rte_table_action_free(struct rte_table_action *action)
2277 {
2278         if (action == NULL)
2279                 return 0;
2280
2281         rte_free(action);
2282
2283         return 0;
2284 }