mbuf: implement generic format for sched field
[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 #include <stdlib.h>
5 #include <string.h>
6
7 #include <rte_common.h>
8 #include <rte_byteorder.h>
9 #include <rte_cycles.h>
10 #include <rte_malloc.h>
11 #include <rte_memcpy.h>
12 #include <rte_ether.h>
13 #include <rte_ip.h>
14 #include <rte_esp.h>
15 #include <rte_tcp.h>
16 #include <rte_udp.h>
17 #include <rte_cryptodev.h>
18 #include <rte_cryptodev_pmd.h>
19
20 #include "rte_table_action.h"
21
22 #define rte_htons rte_cpu_to_be_16
23 #define rte_htonl rte_cpu_to_be_32
24
25 #define rte_ntohs rte_be_to_cpu_16
26 #define rte_ntohl rte_be_to_cpu_32
27
28 /**
29  * RTE_TABLE_ACTION_FWD
30  */
31 #define fwd_data rte_pipeline_table_entry
32
33 static int
34 fwd_apply(struct fwd_data *data,
35         struct rte_table_action_fwd_params *p)
36 {
37         data->action = p->action;
38
39         if (p->action == RTE_PIPELINE_ACTION_PORT)
40                 data->port_id = p->id;
41
42         if (p->action == RTE_PIPELINE_ACTION_TABLE)
43                 data->table_id = p->id;
44
45         return 0;
46 }
47
48 /**
49  * RTE_TABLE_ACTION_LB
50  */
51 static int
52 lb_cfg_check(struct rte_table_action_lb_config *cfg)
53 {
54         if ((cfg == NULL) ||
55                 (cfg->key_size < RTE_TABLE_ACTION_LB_KEY_SIZE_MIN) ||
56                 (cfg->key_size > RTE_TABLE_ACTION_LB_KEY_SIZE_MAX) ||
57                 (!rte_is_power_of_2(cfg->key_size)) ||
58                 (cfg->f_hash == NULL))
59                 return -1;
60
61         return 0;
62 }
63
64 struct lb_data {
65         uint32_t out[RTE_TABLE_ACTION_LB_TABLE_SIZE];
66 } __attribute__((__packed__));
67
68 static int
69 lb_apply(struct lb_data *data,
70         struct rte_table_action_lb_params *p)
71 {
72         memcpy(data->out, p->out, sizeof(data->out));
73
74         return 0;
75 }
76
77 static __rte_always_inline void
78 pkt_work_lb(struct rte_mbuf *mbuf,
79         struct lb_data *data,
80         struct rte_table_action_lb_config *cfg)
81 {
82         uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(mbuf, cfg->key_offset);
83         uint32_t *out = RTE_MBUF_METADATA_UINT32_PTR(mbuf, cfg->out_offset);
84         uint64_t digest, pos;
85         uint32_t out_val;
86
87         digest = cfg->f_hash(pkt_key,
88                 cfg->key_mask,
89                 cfg->key_size,
90                 cfg->seed);
91         pos = digest & (RTE_TABLE_ACTION_LB_TABLE_SIZE - 1);
92         out_val = data->out[pos];
93
94         *out = out_val;
95 }
96
97 /**
98  * RTE_TABLE_ACTION_MTR
99  */
100 static int
101 mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
102 {
103         if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
104                 ((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
105                 (mtr->n_bytes_enabled != 0))
106                 return -ENOTSUP;
107         return 0;
108 }
109
110 struct mtr_trtcm_data {
111         struct rte_meter_trtcm trtcm;
112         uint64_t stats[e_RTE_METER_COLORS];
113 } __attribute__((__packed__));
114
115 #define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
116         (((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
117
118 static void
119 mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
120         uint32_t profile_id)
121 {
122         data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
123         data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
124 }
125
126 #define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
127         (((data)->stats[(color)] & 4LLU) >> 2)
128
129 #define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
130         ((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
131
132 static void
133 mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
134         enum rte_meter_color color,
135         enum rte_table_action_policer action)
136 {
137         if (action == RTE_TABLE_ACTION_POLICER_DROP) {
138                 data->stats[color] |= 4LLU;
139         } else {
140                 data->stats[color] &= ~7LLU;
141                 data->stats[color] |= color & 3LLU;
142         }
143 }
144
145 static uint64_t
146 mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
147         enum rte_meter_color color)
148 {
149         return data->stats[color] >> 8;
150 }
151
152 static void
153 mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
154         enum rte_meter_color color)
155 {
156         data->stats[color] &= 0xFFLU;
157 }
158
159 #define MTR_TRTCM_DATA_STATS_INC(data, color)              \
160         ((data)->stats[(color)] += (1LLU << 8))
161
162 static size_t
163 mtr_data_size(struct rte_table_action_mtr_config *mtr)
164 {
165         return mtr->n_tc * sizeof(struct mtr_trtcm_data);
166 }
167
168 struct dscp_table_entry_data {
169         enum rte_meter_color color;
170         uint16_t tc;
171         uint16_t tc_queue;
172 };
173
174 struct dscp_table_data {
175         struct dscp_table_entry_data entry[64];
176 };
177
178 struct meter_profile_data {
179         struct rte_meter_trtcm_profile profile;
180         uint32_t profile_id;
181         int valid;
182 };
183
184 static struct meter_profile_data *
185 meter_profile_data_find(struct meter_profile_data *mp,
186         uint32_t mp_size,
187         uint32_t profile_id)
188 {
189         uint32_t i;
190
191         for (i = 0; i < mp_size; i++) {
192                 struct meter_profile_data *mp_data = &mp[i];
193
194                 if (mp_data->valid && (mp_data->profile_id == profile_id))
195                         return mp_data;
196         }
197
198         return NULL;
199 }
200
201 static struct meter_profile_data *
202 meter_profile_data_find_unused(struct meter_profile_data *mp,
203         uint32_t mp_size)
204 {
205         uint32_t i;
206
207         for (i = 0; i < mp_size; i++) {
208                 struct meter_profile_data *mp_data = &mp[i];
209
210                 if (!mp_data->valid)
211                         return mp_data;
212         }
213
214         return NULL;
215 }
216
217 static int
218 mtr_apply_check(struct rte_table_action_mtr_params *p,
219         struct rte_table_action_mtr_config *cfg,
220         struct meter_profile_data *mp,
221         uint32_t mp_size)
222 {
223         uint32_t i;
224
225         if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
226                 return -EINVAL;
227
228         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
229                 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
230                 struct meter_profile_data *mp_data;
231
232                 if ((p->tc_mask & (1LLU << i)) == 0)
233                         continue;
234
235                 mp_data = meter_profile_data_find(mp,
236                         mp_size,
237                         p_tc->meter_profile_id);
238                 if (!mp_data)
239                         return -EINVAL;
240         }
241
242         return 0;
243 }
244
245 static int
246 mtr_apply(struct mtr_trtcm_data *data,
247         struct rte_table_action_mtr_params *p,
248         struct rte_table_action_mtr_config *cfg,
249         struct meter_profile_data *mp,
250         uint32_t mp_size)
251 {
252         uint32_t i;
253         int status;
254
255         /* Check input arguments */
256         status = mtr_apply_check(p, cfg, mp, mp_size);
257         if (status)
258                 return status;
259
260         /* Apply */
261         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
262                 struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
263                 struct mtr_trtcm_data *data_tc = &data[i];
264                 struct meter_profile_data *mp_data;
265
266                 if ((p->tc_mask & (1LLU << i)) == 0)
267                         continue;
268
269                 /* Find profile */
270                 mp_data = meter_profile_data_find(mp,
271                         mp_size,
272                         p_tc->meter_profile_id);
273                 if (!mp_data)
274                         return -EINVAL;
275
276                 memset(data_tc, 0, sizeof(*data_tc));
277
278                 /* Meter object */
279                 status = rte_meter_trtcm_config(&data_tc->trtcm,
280                         &mp_data->profile);
281                 if (status)
282                         return status;
283
284                 /* Meter profile */
285                 mtr_trtcm_data_meter_profile_id_set(data_tc,
286                         mp_data - mp);
287
288                 /* Policer actions */
289                 mtr_trtcm_data_policer_action_set(data_tc,
290                         e_RTE_METER_GREEN,
291                         p_tc->policer[e_RTE_METER_GREEN]);
292
293                 mtr_trtcm_data_policer_action_set(data_tc,
294                         e_RTE_METER_YELLOW,
295                         p_tc->policer[e_RTE_METER_YELLOW]);
296
297                 mtr_trtcm_data_policer_action_set(data_tc,
298                         e_RTE_METER_RED,
299                         p_tc->policer[e_RTE_METER_RED]);
300         }
301
302         return 0;
303 }
304
305 static __rte_always_inline uint64_t
306 pkt_work_mtr(struct rte_mbuf *mbuf,
307         struct mtr_trtcm_data *data,
308         struct dscp_table_data *dscp_table,
309         struct meter_profile_data *mp,
310         uint64_t time,
311         uint32_t dscp,
312         uint16_t total_length)
313 {
314         uint64_t drop_mask;
315         struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
316         enum rte_meter_color color_in, color_meter, color_policer;
317         uint32_t tc, mp_id;
318
319         tc = dscp_entry->tc;
320         color_in = dscp_entry->color;
321         data += tc;
322         mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
323
324         /* Meter */
325         color_meter = rte_meter_trtcm_color_aware_check(
326                 &data->trtcm,
327                 &mp[mp_id].profile,
328                 time,
329                 total_length,
330                 color_in);
331
332         /* Stats */
333         MTR_TRTCM_DATA_STATS_INC(data, color_meter);
334
335         /* Police */
336         drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
337         color_policer =
338                 MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
339         rte_mbuf_sched_color_set(mbuf, (uint8_t)color_policer);
340
341         return drop_mask;
342 }
343
344 /**
345  * RTE_TABLE_ACTION_TM
346  */
347 static int
348 tm_cfg_check(struct rte_table_action_tm_config *tm)
349 {
350         if ((tm->n_subports_per_port == 0) ||
351                 (rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
352                 (tm->n_subports_per_port > UINT16_MAX) ||
353                 (tm->n_pipes_per_subport == 0) ||
354                 (rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
355                 return -ENOTSUP;
356
357         return 0;
358 }
359
360 struct tm_data {
361         uint32_t queue_id;
362         uint32_t reserved;
363 } __attribute__((__packed__));
364
365 static int
366 tm_apply_check(struct rte_table_action_tm_params *p,
367         struct rte_table_action_tm_config *cfg)
368 {
369         if ((p->subport_id >= cfg->n_subports_per_port) ||
370                 (p->pipe_id >= cfg->n_pipes_per_subport))
371                 return -EINVAL;
372
373         return 0;
374 }
375
376 static int
377 tm_apply(struct tm_data *data,
378         struct rte_table_action_tm_params *p,
379         struct rte_table_action_tm_config *cfg)
380 {
381         int status;
382
383         /* Check input arguments */
384         status = tm_apply_check(p, cfg);
385         if (status)
386                 return status;
387
388         /* Apply */
389         data->queue_id = p->subport_id <<
390                                 (__builtin_ctz(cfg->n_pipes_per_subport) + 4) |
391                                 p->pipe_id << 4;
392
393         return 0;
394 }
395
396 static __rte_always_inline void
397 pkt_work_tm(struct rte_mbuf *mbuf,
398         struct tm_data *data,
399         struct dscp_table_data *dscp_table,
400         uint32_t dscp)
401 {
402         struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
403         uint32_t queue_id = data->queue_id |
404                                 (dscp_entry->tc << 2) |
405                                 dscp_entry->tc_queue;
406         rte_mbuf_sched_set(mbuf, queue_id, dscp_entry->tc,
407                                 (uint8_t)dscp_entry->color);
408 }
409
410 /**
411  * RTE_TABLE_ACTION_ENCAP
412  */
413 static int
414 encap_valid(enum rte_table_action_encap_type encap)
415 {
416         switch (encap) {
417         case RTE_TABLE_ACTION_ENCAP_ETHER:
418         case RTE_TABLE_ACTION_ENCAP_VLAN:
419         case RTE_TABLE_ACTION_ENCAP_QINQ:
420         case RTE_TABLE_ACTION_ENCAP_MPLS:
421         case RTE_TABLE_ACTION_ENCAP_PPPOE:
422         case RTE_TABLE_ACTION_ENCAP_VXLAN:
423                 return 1;
424         default:
425                 return 0;
426         }
427 }
428
429 static int
430 encap_cfg_check(struct rte_table_action_encap_config *encap)
431 {
432         if ((encap->encap_mask == 0) ||
433                 (__builtin_popcountll(encap->encap_mask) != 1))
434                 return -ENOTSUP;
435
436         return 0;
437 }
438
439 struct encap_ether_data {
440         struct ether_hdr ether;
441 } __attribute__((__packed__));
442
443 #define VLAN(pcp, dei, vid)                                \
444         ((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
445         ((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
446         (((uint64_t)(vid)) & 0xFFFLLU))                    \
447
448 struct encap_vlan_data {
449         struct ether_hdr ether;
450         struct vlan_hdr vlan;
451 } __attribute__((__packed__));
452
453 struct encap_qinq_data {
454         struct ether_hdr ether;
455         struct vlan_hdr svlan;
456         struct vlan_hdr cvlan;
457 } __attribute__((__packed__));
458
459 #define ETHER_TYPE_MPLS_UNICAST                            0x8847
460
461 #define ETHER_TYPE_MPLS_MULTICAST                          0x8848
462
463 #define MPLS(label, tc, s, ttl)                            \
464         ((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
465         ((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
466         ((((uint64_t)(s)) & 0x1LLU) << 8) |                \
467         (((uint64_t)(ttl)) & 0xFFLLU)))
468
469 struct encap_mpls_data {
470         struct ether_hdr ether;
471         uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
472         uint32_t mpls_count;
473 } __attribute__((__packed__));
474
475 #define ETHER_TYPE_PPPOE_SESSION                           0x8864
476
477 #define PPP_PROTOCOL_IP                                    0x0021
478
479 struct pppoe_ppp_hdr {
480         uint16_t ver_type_code;
481         uint16_t session_id;
482         uint16_t length;
483         uint16_t protocol;
484 } __attribute__((__packed__));
485
486 struct encap_pppoe_data {
487         struct ether_hdr ether;
488         struct pppoe_ppp_hdr pppoe_ppp;
489 } __attribute__((__packed__));
490
491 #define IP_PROTO_UDP                                       17
492
493 struct encap_vxlan_ipv4_data {
494         struct ether_hdr ether;
495         struct ipv4_hdr ipv4;
496         struct udp_hdr udp;
497         struct vxlan_hdr vxlan;
498 } __attribute__((__packed__));
499
500 struct encap_vxlan_ipv4_vlan_data {
501         struct ether_hdr ether;
502         struct vlan_hdr vlan;
503         struct ipv4_hdr ipv4;
504         struct udp_hdr udp;
505         struct vxlan_hdr vxlan;
506 } __attribute__((__packed__));
507
508 struct encap_vxlan_ipv6_data {
509         struct ether_hdr ether;
510         struct ipv6_hdr ipv6;
511         struct udp_hdr udp;
512         struct vxlan_hdr vxlan;
513 } __attribute__((__packed__));
514
515 struct encap_vxlan_ipv6_vlan_data {
516         struct ether_hdr ether;
517         struct vlan_hdr vlan;
518         struct ipv6_hdr ipv6;
519         struct udp_hdr udp;
520         struct vxlan_hdr vxlan;
521 } __attribute__((__packed__));
522
523 static size_t
524 encap_data_size(struct rte_table_action_encap_config *encap)
525 {
526         switch (encap->encap_mask) {
527         case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
528                 return sizeof(struct encap_ether_data);
529
530         case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
531                 return sizeof(struct encap_vlan_data);
532
533         case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
534                 return sizeof(struct encap_qinq_data);
535
536         case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
537                 return sizeof(struct encap_mpls_data);
538
539         case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
540                 return sizeof(struct encap_pppoe_data);
541
542         case 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN:
543                 if (encap->vxlan.ip_version)
544                         if (encap->vxlan.vlan)
545                                 return sizeof(struct encap_vxlan_ipv4_vlan_data);
546                         else
547                                 return sizeof(struct encap_vxlan_ipv4_data);
548                 else
549                         if (encap->vxlan.vlan)
550                                 return sizeof(struct encap_vxlan_ipv6_vlan_data);
551                         else
552                                 return sizeof(struct encap_vxlan_ipv6_data);
553
554         default:
555                 return 0;
556         }
557 }
558
559 static int
560 encap_apply_check(struct rte_table_action_encap_params *p,
561         struct rte_table_action_encap_config *cfg)
562 {
563         if ((encap_valid(p->type) == 0) ||
564                 ((cfg->encap_mask & (1LLU << p->type)) == 0))
565                 return -EINVAL;
566
567         switch (p->type) {
568         case RTE_TABLE_ACTION_ENCAP_ETHER:
569                 return 0;
570
571         case RTE_TABLE_ACTION_ENCAP_VLAN:
572                 return 0;
573
574         case RTE_TABLE_ACTION_ENCAP_QINQ:
575                 return 0;
576
577         case RTE_TABLE_ACTION_ENCAP_MPLS:
578                 if ((p->mpls.mpls_count == 0) ||
579                         (p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
580                         return -EINVAL;
581
582                 return 0;
583
584         case RTE_TABLE_ACTION_ENCAP_PPPOE:
585                 return 0;
586
587         case RTE_TABLE_ACTION_ENCAP_VXLAN:
588                 return 0;
589
590         default:
591                 return -EINVAL;
592         }
593 }
594
595 static int
596 encap_ether_apply(void *data,
597         struct rte_table_action_encap_params *p,
598         struct rte_table_action_common_config *common_cfg)
599 {
600         struct encap_ether_data *d = data;
601         uint16_t ethertype = (common_cfg->ip_version) ?
602                 ETHER_TYPE_IPv4 :
603                 ETHER_TYPE_IPv6;
604
605         /* Ethernet */
606         ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
607         ether_addr_copy(&p->ether.ether.sa, &d->ether.s_addr);
608         d->ether.ether_type = rte_htons(ethertype);
609
610         return 0;
611 }
612
613 static int
614 encap_vlan_apply(void *data,
615         struct rte_table_action_encap_params *p,
616         struct rte_table_action_common_config *common_cfg)
617 {
618         struct encap_vlan_data *d = data;
619         uint16_t ethertype = (common_cfg->ip_version) ?
620                 ETHER_TYPE_IPv4 :
621                 ETHER_TYPE_IPv6;
622
623         /* Ethernet */
624         ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
625         ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
626         d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
627
628         /* VLAN */
629         d->vlan.vlan_tci = rte_htons(VLAN(p->vlan.vlan.pcp,
630                 p->vlan.vlan.dei,
631                 p->vlan.vlan.vid));
632         d->vlan.eth_proto = rte_htons(ethertype);
633
634         return 0;
635 }
636
637 static int
638 encap_qinq_apply(void *data,
639         struct rte_table_action_encap_params *p,
640         struct rte_table_action_common_config *common_cfg)
641 {
642         struct encap_qinq_data *d = data;
643         uint16_t ethertype = (common_cfg->ip_version) ?
644                 ETHER_TYPE_IPv4 :
645                 ETHER_TYPE_IPv6;
646
647         /* Ethernet */
648         ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
649         ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
650         d->ether.ether_type = rte_htons(ETHER_TYPE_QINQ);
651
652         /* SVLAN */
653         d->svlan.vlan_tci = rte_htons(VLAN(p->qinq.svlan.pcp,
654                 p->qinq.svlan.dei,
655                 p->qinq.svlan.vid));
656         d->svlan.eth_proto = rte_htons(ETHER_TYPE_VLAN);
657
658         /* CVLAN */
659         d->cvlan.vlan_tci = rte_htons(VLAN(p->qinq.cvlan.pcp,
660                 p->qinq.cvlan.dei,
661                 p->qinq.cvlan.vid));
662         d->cvlan.eth_proto = rte_htons(ethertype);
663
664         return 0;
665 }
666
667 static int
668 encap_mpls_apply(void *data,
669         struct rte_table_action_encap_params *p)
670 {
671         struct encap_mpls_data *d = data;
672         uint16_t ethertype = (p->mpls.unicast) ?
673                 ETHER_TYPE_MPLS_UNICAST :
674                 ETHER_TYPE_MPLS_MULTICAST;
675         uint32_t i;
676
677         /* Ethernet */
678         ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
679         ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
680         d->ether.ether_type = rte_htons(ethertype);
681
682         /* MPLS */
683         for (i = 0; i < p->mpls.mpls_count - 1; i++)
684                 d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
685                         p->mpls.mpls[i].tc,
686                         0,
687                         p->mpls.mpls[i].ttl));
688
689         d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
690                 p->mpls.mpls[i].tc,
691                 1,
692                 p->mpls.mpls[i].ttl));
693
694         d->mpls_count = p->mpls.mpls_count;
695         return 0;
696 }
697
698 static int
699 encap_pppoe_apply(void *data,
700         struct rte_table_action_encap_params *p)
701 {
702         struct encap_pppoe_data *d = data;
703
704         /* Ethernet */
705         ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
706         ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
707         d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
708
709         /* PPPoE and PPP*/
710         d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
711         d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
712         d->pppoe_ppp.length = 0; /* not pre-computed */
713         d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
714
715         return 0;
716 }
717
718 static int
719 encap_vxlan_apply(void *data,
720         struct rte_table_action_encap_params *p,
721         struct rte_table_action_encap_config *cfg)
722 {
723         if ((p->vxlan.vxlan.vni > 0xFFFFFF) ||
724                 (cfg->vxlan.ip_version && (p->vxlan.ipv4.dscp > 0x3F)) ||
725                 (!cfg->vxlan.ip_version && (p->vxlan.ipv6.flow_label > 0xFFFFF)) ||
726                 (!cfg->vxlan.ip_version && (p->vxlan.ipv6.dscp > 0x3F)) ||
727                 (cfg->vxlan.vlan && (p->vxlan.vlan.vid > 0xFFF)))
728                 return -1;
729
730         if (cfg->vxlan.ip_version)
731                 if (cfg->vxlan.vlan) {
732                         struct encap_vxlan_ipv4_vlan_data *d = data;
733
734                         /* Ethernet */
735                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
736                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
737                         d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
738
739                         /* VLAN */
740                         d->vlan.vlan_tci = rte_htons(VLAN(p->vxlan.vlan.pcp,
741                                 p->vxlan.vlan.dei,
742                                 p->vxlan.vlan.vid));
743                         d->vlan.eth_proto = rte_htons(ETHER_TYPE_IPv4);
744
745                         /* IPv4*/
746                         d->ipv4.version_ihl = 0x45;
747                         d->ipv4.type_of_service = p->vxlan.ipv4.dscp << 2;
748                         d->ipv4.total_length = 0; /* not pre-computed */
749                         d->ipv4.packet_id = 0;
750                         d->ipv4.fragment_offset = 0;
751                         d->ipv4.time_to_live = p->vxlan.ipv4.ttl;
752                         d->ipv4.next_proto_id = IP_PROTO_UDP;
753                         d->ipv4.hdr_checksum = 0;
754                         d->ipv4.src_addr = rte_htonl(p->vxlan.ipv4.sa);
755                         d->ipv4.dst_addr = rte_htonl(p->vxlan.ipv4.da);
756
757                         d->ipv4.hdr_checksum = rte_ipv4_cksum(&d->ipv4);
758
759                         /* UDP */
760                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
761                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
762                         d->udp.dgram_len = 0; /* not pre-computed */
763                         d->udp.dgram_cksum = 0;
764
765                         /* VXLAN */
766                         d->vxlan.vx_flags = rte_htonl(0x08000000);
767                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
768
769                         return 0;
770                 } else {
771                         struct encap_vxlan_ipv4_data *d = data;
772
773                         /* Ethernet */
774                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
775                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
776                         d->ether.ether_type = rte_htons(ETHER_TYPE_IPv4);
777
778                         /* IPv4*/
779                         d->ipv4.version_ihl = 0x45;
780                         d->ipv4.type_of_service = p->vxlan.ipv4.dscp << 2;
781                         d->ipv4.total_length = 0; /* not pre-computed */
782                         d->ipv4.packet_id = 0;
783                         d->ipv4.fragment_offset = 0;
784                         d->ipv4.time_to_live = p->vxlan.ipv4.ttl;
785                         d->ipv4.next_proto_id = IP_PROTO_UDP;
786                         d->ipv4.hdr_checksum = 0;
787                         d->ipv4.src_addr = rte_htonl(p->vxlan.ipv4.sa);
788                         d->ipv4.dst_addr = rte_htonl(p->vxlan.ipv4.da);
789
790                         d->ipv4.hdr_checksum = rte_ipv4_cksum(&d->ipv4);
791
792                         /* UDP */
793                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
794                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
795                         d->udp.dgram_len = 0; /* not pre-computed */
796                         d->udp.dgram_cksum = 0;
797
798                         /* VXLAN */
799                         d->vxlan.vx_flags = rte_htonl(0x08000000);
800                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
801
802                         return 0;
803                 }
804         else
805                 if (cfg->vxlan.vlan) {
806                         struct encap_vxlan_ipv6_vlan_data *d = data;
807
808                         /* Ethernet */
809                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
810                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
811                         d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
812
813                         /* VLAN */
814                         d->vlan.vlan_tci = rte_htons(VLAN(p->vxlan.vlan.pcp,
815                                 p->vxlan.vlan.dei,
816                                 p->vxlan.vlan.vid));
817                         d->vlan.eth_proto = rte_htons(ETHER_TYPE_IPv6);
818
819                         /* IPv6*/
820                         d->ipv6.vtc_flow = rte_htonl((6 << 28) |
821                                 (p->vxlan.ipv6.dscp << 22) |
822                                 p->vxlan.ipv6.flow_label);
823                         d->ipv6.payload_len = 0; /* not pre-computed */
824                         d->ipv6.proto = IP_PROTO_UDP;
825                         d->ipv6.hop_limits = p->vxlan.ipv6.hop_limit;
826                         memcpy(d->ipv6.src_addr,
827                                 p->vxlan.ipv6.sa,
828                                 sizeof(p->vxlan.ipv6.sa));
829                         memcpy(d->ipv6.dst_addr,
830                                 p->vxlan.ipv6.da,
831                                 sizeof(p->vxlan.ipv6.da));
832
833                         /* UDP */
834                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
835                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
836                         d->udp.dgram_len = 0; /* not pre-computed */
837                         d->udp.dgram_cksum = 0;
838
839                         /* VXLAN */
840                         d->vxlan.vx_flags = rte_htonl(0x08000000);
841                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
842
843                         return 0;
844                 } else {
845                         struct encap_vxlan_ipv6_data *d = data;
846
847                         /* Ethernet */
848                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
849                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
850                         d->ether.ether_type = rte_htons(ETHER_TYPE_IPv6);
851
852                         /* IPv6*/
853                         d->ipv6.vtc_flow = rte_htonl((6 << 28) |
854                                 (p->vxlan.ipv6.dscp << 22) |
855                                 p->vxlan.ipv6.flow_label);
856                         d->ipv6.payload_len = 0; /* not pre-computed */
857                         d->ipv6.proto = IP_PROTO_UDP;
858                         d->ipv6.hop_limits = p->vxlan.ipv6.hop_limit;
859                         memcpy(d->ipv6.src_addr,
860                                 p->vxlan.ipv6.sa,
861                                 sizeof(p->vxlan.ipv6.sa));
862                         memcpy(d->ipv6.dst_addr,
863                                 p->vxlan.ipv6.da,
864                                 sizeof(p->vxlan.ipv6.da));
865
866                         /* UDP */
867                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
868                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
869                         d->udp.dgram_len = 0; /* not pre-computed */
870                         d->udp.dgram_cksum = 0;
871
872                         /* VXLAN */
873                         d->vxlan.vx_flags = rte_htonl(0x08000000);
874                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
875
876                         return 0;
877                 }
878 }
879
880 static int
881 encap_apply(void *data,
882         struct rte_table_action_encap_params *p,
883         struct rte_table_action_encap_config *cfg,
884         struct rte_table_action_common_config *common_cfg)
885 {
886         int status;
887
888         /* Check input arguments */
889         status = encap_apply_check(p, cfg);
890         if (status)
891                 return status;
892
893         switch (p->type) {
894         case RTE_TABLE_ACTION_ENCAP_ETHER:
895                 return encap_ether_apply(data, p, common_cfg);
896
897         case RTE_TABLE_ACTION_ENCAP_VLAN:
898                 return encap_vlan_apply(data, p, common_cfg);
899
900         case RTE_TABLE_ACTION_ENCAP_QINQ:
901                 return encap_qinq_apply(data, p, common_cfg);
902
903         case RTE_TABLE_ACTION_ENCAP_MPLS:
904                 return encap_mpls_apply(data, p);
905
906         case RTE_TABLE_ACTION_ENCAP_PPPOE:
907                 return encap_pppoe_apply(data, p);
908
909         case RTE_TABLE_ACTION_ENCAP_VXLAN:
910                 return encap_vxlan_apply(data, p, cfg);
911
912         default:
913                 return -EINVAL;
914         }
915 }
916
917 static __rte_always_inline uint16_t
918 encap_vxlan_ipv4_checksum_update(uint16_t cksum0,
919         uint16_t total_length)
920 {
921         int32_t cksum1;
922
923         cksum1 = cksum0;
924         cksum1 = ~cksum1 & 0xFFFF;
925
926         /* Add total length (one's complement logic) */
927         cksum1 += total_length;
928         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
929         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
930
931         return (uint16_t)(~cksum1);
932 }
933
934 static __rte_always_inline void *
935 encap(void *dst, const void *src, size_t n)
936 {
937         dst = ((uint8_t *) dst) - n;
938         return rte_memcpy(dst, src, n);
939 }
940
941 static __rte_always_inline void
942 pkt_work_encap_vxlan_ipv4(struct rte_mbuf *mbuf,
943         struct encap_vxlan_ipv4_data *vxlan_tbl,
944         struct rte_table_action_encap_config *cfg)
945 {
946         uint32_t ether_offset = cfg->vxlan.data_offset;
947         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
948         struct encap_vxlan_ipv4_data *vxlan_pkt;
949         uint16_t ether_length, ipv4_total_length, ipv4_hdr_cksum, udp_length;
950
951         ether_length = (uint16_t)mbuf->pkt_len;
952         ipv4_total_length = ether_length +
953                 (sizeof(struct vxlan_hdr) +
954                 sizeof(struct udp_hdr) +
955                 sizeof(struct ipv4_hdr));
956         ipv4_hdr_cksum = encap_vxlan_ipv4_checksum_update(vxlan_tbl->ipv4.hdr_checksum,
957                 rte_htons(ipv4_total_length));
958         udp_length = ether_length +
959                 (sizeof(struct vxlan_hdr) +
960                 sizeof(struct udp_hdr));
961
962         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
963         vxlan_pkt->ipv4.total_length = rte_htons(ipv4_total_length);
964         vxlan_pkt->ipv4.hdr_checksum = ipv4_hdr_cksum;
965         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
966
967         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
968         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
969 }
970
971 static __rte_always_inline void
972 pkt_work_encap_vxlan_ipv4_vlan(struct rte_mbuf *mbuf,
973         struct encap_vxlan_ipv4_vlan_data *vxlan_tbl,
974         struct rte_table_action_encap_config *cfg)
975 {
976         uint32_t ether_offset = cfg->vxlan.data_offset;
977         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
978         struct encap_vxlan_ipv4_vlan_data *vxlan_pkt;
979         uint16_t ether_length, ipv4_total_length, ipv4_hdr_cksum, udp_length;
980
981         ether_length = (uint16_t)mbuf->pkt_len;
982         ipv4_total_length = ether_length +
983                 (sizeof(struct vxlan_hdr) +
984                 sizeof(struct udp_hdr) +
985                 sizeof(struct ipv4_hdr));
986         ipv4_hdr_cksum = encap_vxlan_ipv4_checksum_update(vxlan_tbl->ipv4.hdr_checksum,
987                 rte_htons(ipv4_total_length));
988         udp_length = ether_length +
989                 (sizeof(struct vxlan_hdr) +
990                 sizeof(struct udp_hdr));
991
992         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
993         vxlan_pkt->ipv4.total_length = rte_htons(ipv4_total_length);
994         vxlan_pkt->ipv4.hdr_checksum = ipv4_hdr_cksum;
995         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
996
997         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
998         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
999 }
1000
1001 static __rte_always_inline void
1002 pkt_work_encap_vxlan_ipv6(struct rte_mbuf *mbuf,
1003         struct encap_vxlan_ipv6_data *vxlan_tbl,
1004         struct rte_table_action_encap_config *cfg)
1005 {
1006         uint32_t ether_offset = cfg->vxlan.data_offset;
1007         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
1008         struct encap_vxlan_ipv6_data *vxlan_pkt;
1009         uint16_t ether_length, ipv6_payload_length, udp_length;
1010
1011         ether_length = (uint16_t)mbuf->pkt_len;
1012         ipv6_payload_length = ether_length +
1013                 (sizeof(struct vxlan_hdr) +
1014                 sizeof(struct udp_hdr));
1015         udp_length = ether_length +
1016                 (sizeof(struct vxlan_hdr) +
1017                 sizeof(struct udp_hdr));
1018
1019         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
1020         vxlan_pkt->ipv6.payload_len = rte_htons(ipv6_payload_length);
1021         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
1022
1023         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
1024         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
1025 }
1026
1027 static __rte_always_inline void
1028 pkt_work_encap_vxlan_ipv6_vlan(struct rte_mbuf *mbuf,
1029         struct encap_vxlan_ipv6_vlan_data *vxlan_tbl,
1030         struct rte_table_action_encap_config *cfg)
1031 {
1032         uint32_t ether_offset = cfg->vxlan.data_offset;
1033         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
1034         struct encap_vxlan_ipv6_vlan_data *vxlan_pkt;
1035         uint16_t ether_length, ipv6_payload_length, udp_length;
1036
1037         ether_length = (uint16_t)mbuf->pkt_len;
1038         ipv6_payload_length = ether_length +
1039                 (sizeof(struct vxlan_hdr) +
1040                 sizeof(struct udp_hdr));
1041         udp_length = ether_length +
1042                 (sizeof(struct vxlan_hdr) +
1043                 sizeof(struct udp_hdr));
1044
1045         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
1046         vxlan_pkt->ipv6.payload_len = rte_htons(ipv6_payload_length);
1047         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
1048
1049         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
1050         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
1051 }
1052
1053 static __rte_always_inline void
1054 pkt_work_encap(struct rte_mbuf *mbuf,
1055         void *data,
1056         struct rte_table_action_encap_config *cfg,
1057         void *ip,
1058         uint16_t total_length,
1059         uint32_t ip_offset)
1060 {
1061         switch (cfg->encap_mask) {
1062         case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
1063                 encap(ip, data, sizeof(struct encap_ether_data));
1064                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1065                         sizeof(struct encap_ether_data));
1066                 mbuf->pkt_len = mbuf->data_len = total_length +
1067                         sizeof(struct encap_ether_data);
1068                 break;
1069
1070         case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
1071                 encap(ip, data, sizeof(struct encap_vlan_data));
1072                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1073                         sizeof(struct encap_vlan_data));
1074                 mbuf->pkt_len = mbuf->data_len = total_length +
1075                         sizeof(struct encap_vlan_data);
1076                 break;
1077
1078         case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
1079                 encap(ip, data, sizeof(struct encap_qinq_data));
1080                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1081                         sizeof(struct encap_qinq_data));
1082                 mbuf->pkt_len = mbuf->data_len = total_length +
1083                         sizeof(struct encap_qinq_data);
1084                 break;
1085
1086         case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
1087         {
1088                 struct encap_mpls_data *mpls = data;
1089                 size_t size = sizeof(struct ether_hdr) +
1090                         mpls->mpls_count * 4;
1091
1092                 encap(ip, data, size);
1093                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
1094                 mbuf->pkt_len = mbuf->data_len = total_length + size;
1095                 break;
1096         }
1097
1098         case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
1099         {
1100                 struct encap_pppoe_data *pppoe =
1101                         encap(ip, data, sizeof(struct encap_pppoe_data));
1102                 pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
1103                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1104                         sizeof(struct encap_pppoe_data));
1105                 mbuf->pkt_len = mbuf->data_len = total_length +
1106                         sizeof(struct encap_pppoe_data);
1107                 break;
1108         }
1109
1110         case 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN:
1111         {
1112                 if (cfg->vxlan.ip_version)
1113                         if (cfg->vxlan.vlan)
1114                                 pkt_work_encap_vxlan_ipv4_vlan(mbuf, data, cfg);
1115                         else
1116                                 pkt_work_encap_vxlan_ipv4(mbuf, data, cfg);
1117                 else
1118                         if (cfg->vxlan.vlan)
1119                                 pkt_work_encap_vxlan_ipv6_vlan(mbuf, data, cfg);
1120                         else
1121                                 pkt_work_encap_vxlan_ipv6(mbuf, data, cfg);
1122         }
1123
1124         default:
1125                 break;
1126         }
1127 }
1128
1129 /**
1130  * RTE_TABLE_ACTION_NAT
1131  */
1132 static int
1133 nat_cfg_check(struct rte_table_action_nat_config *nat)
1134 {
1135         if ((nat->proto != 0x06) &&
1136                 (nat->proto != 0x11))
1137                 return -ENOTSUP;
1138
1139         return 0;
1140 }
1141
1142 struct nat_ipv4_data {
1143         uint32_t addr;
1144         uint16_t port;
1145 } __attribute__((__packed__));
1146
1147 struct nat_ipv6_data {
1148         uint8_t addr[16];
1149         uint16_t port;
1150 } __attribute__((__packed__));
1151
1152 static size_t
1153 nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
1154         struct rte_table_action_common_config *common)
1155 {
1156         int ip_version = common->ip_version;
1157
1158         return (ip_version) ?
1159                 sizeof(struct nat_ipv4_data) :
1160                 sizeof(struct nat_ipv6_data);
1161 }
1162
1163 static int
1164 nat_apply_check(struct rte_table_action_nat_params *p,
1165         struct rte_table_action_common_config *cfg)
1166 {
1167         if ((p->ip_version && (cfg->ip_version == 0)) ||
1168                 ((p->ip_version == 0) && cfg->ip_version))
1169                 return -EINVAL;
1170
1171         return 0;
1172 }
1173
1174 static int
1175 nat_apply(void *data,
1176         struct rte_table_action_nat_params *p,
1177         struct rte_table_action_common_config *cfg)
1178 {
1179         int status;
1180
1181         /* Check input arguments */
1182         status = nat_apply_check(p, cfg);
1183         if (status)
1184                 return status;
1185
1186         /* Apply */
1187         if (p->ip_version) {
1188                 struct nat_ipv4_data *d = data;
1189
1190                 d->addr = rte_htonl(p->addr.ipv4);
1191                 d->port = rte_htons(p->port);
1192         } else {
1193                 struct nat_ipv6_data *d = data;
1194
1195                 memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
1196                 d->port = rte_htons(p->port);
1197         }
1198
1199         return 0;
1200 }
1201
1202 static __rte_always_inline uint16_t
1203 nat_ipv4_checksum_update(uint16_t cksum0,
1204         uint32_t ip0,
1205         uint32_t ip1)
1206 {
1207         int32_t cksum1;
1208
1209         cksum1 = cksum0;
1210         cksum1 = ~cksum1 & 0xFFFF;
1211
1212         /* Subtract ip0 (one's complement logic) */
1213         cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF);
1214         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1215         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1216
1217         /* Add ip1 (one's complement logic) */
1218         cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF);
1219         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1220         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1221
1222         return (uint16_t)(~cksum1);
1223 }
1224
1225 static __rte_always_inline uint16_t
1226 nat_ipv4_tcp_udp_checksum_update(uint16_t cksum0,
1227         uint32_t ip0,
1228         uint32_t ip1,
1229         uint16_t port0,
1230         uint16_t port1)
1231 {
1232         int32_t cksum1;
1233
1234         cksum1 = cksum0;
1235         cksum1 = ~cksum1 & 0xFFFF;
1236
1237         /* Subtract ip0 and port 0 (one's complement logic) */
1238         cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF) + port0;
1239         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1240         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1241
1242         /* Add ip1 and port1 (one's complement logic) */
1243         cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF) + port1;
1244         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1245         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1246
1247         return (uint16_t)(~cksum1);
1248 }
1249
1250 static __rte_always_inline uint16_t
1251 nat_ipv6_tcp_udp_checksum_update(uint16_t cksum0,
1252         uint16_t *ip0,
1253         uint16_t *ip1,
1254         uint16_t port0,
1255         uint16_t port1)
1256 {
1257         int32_t cksum1;
1258
1259         cksum1 = cksum0;
1260         cksum1 = ~cksum1 & 0xFFFF;
1261
1262         /* Subtract ip0 and port 0 (one's complement logic) */
1263         cksum1 -= ip0[0] + ip0[1] + ip0[2] + ip0[3] +
1264                 ip0[4] + ip0[5] + ip0[6] + ip0[7] + port0;
1265         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1266         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1267
1268         /* Add ip1 and port1 (one's complement logic) */
1269         cksum1 += ip1[0] + ip1[1] + ip1[2] + ip1[3] +
1270                 ip1[4] + ip1[5] + ip1[6] + ip1[7] + port1;
1271         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1272         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1273
1274         return (uint16_t)(~cksum1);
1275 }
1276
1277 static __rte_always_inline void
1278 pkt_ipv4_work_nat(struct ipv4_hdr *ip,
1279         struct nat_ipv4_data *data,
1280         struct rte_table_action_nat_config *cfg)
1281 {
1282         if (cfg->source_nat) {
1283                 if (cfg->proto == 0x6) {
1284                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1285                         uint16_t ip_cksum, tcp_cksum;
1286
1287                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1288                                 ip->src_addr,
1289                                 data->addr);
1290
1291                         tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
1292                                 ip->src_addr,
1293                                 data->addr,
1294                                 tcp->src_port,
1295                                 data->port);
1296
1297                         ip->src_addr = data->addr;
1298                         ip->hdr_checksum = ip_cksum;
1299                         tcp->src_port = data->port;
1300                         tcp->cksum = tcp_cksum;
1301                 } else {
1302                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1303                         uint16_t ip_cksum, udp_cksum;
1304
1305                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1306                                 ip->src_addr,
1307                                 data->addr);
1308
1309                         udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
1310                                 ip->src_addr,
1311                                 data->addr,
1312                                 udp->src_port,
1313                                 data->port);
1314
1315                         ip->src_addr = data->addr;
1316                         ip->hdr_checksum = ip_cksum;
1317                         udp->src_port = data->port;
1318                         if (udp->dgram_cksum)
1319                                 udp->dgram_cksum = udp_cksum;
1320                 }
1321         } else {
1322                 if (cfg->proto == 0x6) {
1323                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1324                         uint16_t ip_cksum, tcp_cksum;
1325
1326                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1327                                 ip->dst_addr,
1328                                 data->addr);
1329
1330                         tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
1331                                 ip->dst_addr,
1332                                 data->addr,
1333                                 tcp->dst_port,
1334                                 data->port);
1335
1336                         ip->dst_addr = data->addr;
1337                         ip->hdr_checksum = ip_cksum;
1338                         tcp->dst_port = data->port;
1339                         tcp->cksum = tcp_cksum;
1340                 } else {
1341                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1342                         uint16_t ip_cksum, udp_cksum;
1343
1344                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1345                                 ip->dst_addr,
1346                                 data->addr);
1347
1348                         udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
1349                                 ip->dst_addr,
1350                                 data->addr,
1351                                 udp->dst_port,
1352                                 data->port);
1353
1354                         ip->dst_addr = data->addr;
1355                         ip->hdr_checksum = ip_cksum;
1356                         udp->dst_port = data->port;
1357                         if (udp->dgram_cksum)
1358                                 udp->dgram_cksum = udp_cksum;
1359                 }
1360         }
1361 }
1362
1363 static __rte_always_inline void
1364 pkt_ipv6_work_nat(struct ipv6_hdr *ip,
1365         struct nat_ipv6_data *data,
1366         struct rte_table_action_nat_config *cfg)
1367 {
1368         if (cfg->source_nat) {
1369                 if (cfg->proto == 0x6) {
1370                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1371                         uint16_t tcp_cksum;
1372
1373                         tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
1374                                 (uint16_t *)ip->src_addr,
1375                                 (uint16_t *)data->addr,
1376                                 tcp->src_port,
1377                                 data->port);
1378
1379                         rte_memcpy(ip->src_addr, data->addr, 16);
1380                         tcp->src_port = data->port;
1381                         tcp->cksum = tcp_cksum;
1382                 } else {
1383                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1384                         uint16_t udp_cksum;
1385
1386                         udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
1387                                 (uint16_t *)ip->src_addr,
1388                                 (uint16_t *)data->addr,
1389                                 udp->src_port,
1390                                 data->port);
1391
1392                         rte_memcpy(ip->src_addr, data->addr, 16);
1393                         udp->src_port = data->port;
1394                         udp->dgram_cksum = udp_cksum;
1395                 }
1396         } else {
1397                 if (cfg->proto == 0x6) {
1398                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1399                         uint16_t tcp_cksum;
1400
1401                         tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
1402                                 (uint16_t *)ip->dst_addr,
1403                                 (uint16_t *)data->addr,
1404                                 tcp->dst_port,
1405                                 data->port);
1406
1407                         rte_memcpy(ip->dst_addr, data->addr, 16);
1408                         tcp->dst_port = data->port;
1409                         tcp->cksum = tcp_cksum;
1410                 } else {
1411                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1412                         uint16_t udp_cksum;
1413
1414                         udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
1415                                 (uint16_t *)ip->dst_addr,
1416                                 (uint16_t *)data->addr,
1417                                 udp->dst_port,
1418                                 data->port);
1419
1420                         rte_memcpy(ip->dst_addr, data->addr, 16);
1421                         udp->dst_port = data->port;
1422                         udp->dgram_cksum = udp_cksum;
1423                 }
1424         }
1425 }
1426
1427 /**
1428  * RTE_TABLE_ACTION_TTL
1429  */
1430 static int
1431 ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
1432 {
1433         if (ttl->drop == 0)
1434                 return -ENOTSUP;
1435
1436         return 0;
1437 }
1438
1439 struct ttl_data {
1440         uint32_t n_packets;
1441 } __attribute__((__packed__));
1442
1443 #define TTL_INIT(data, decrement)                         \
1444         ((data)->n_packets = (decrement) ? 1 : 0)
1445
1446 #define TTL_DEC_GET(data)                                  \
1447         ((uint8_t)((data)->n_packets & 1))
1448
1449 #define TTL_STATS_RESET(data)                             \
1450         ((data)->n_packets = ((data)->n_packets & 1))
1451
1452 #define TTL_STATS_READ(data)                               \
1453         ((data)->n_packets >> 1)
1454
1455 #define TTL_STATS_ADD(data, value)                        \
1456         ((data)->n_packets =                                  \
1457                 (((((data)->n_packets >> 1) + (value)) << 1) |    \
1458                 ((data)->n_packets & 1)))
1459
1460 static int
1461 ttl_apply(void *data,
1462         struct rte_table_action_ttl_params *p)
1463 {
1464         struct ttl_data *d = data;
1465
1466         TTL_INIT(d, p->decrement);
1467
1468         return 0;
1469 }
1470
1471 static __rte_always_inline uint64_t
1472 pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
1473         struct ttl_data *data)
1474 {
1475         uint32_t drop;
1476         uint16_t cksum = ip->hdr_checksum;
1477         uint8_t ttl = ip->time_to_live;
1478         uint8_t ttl_diff = TTL_DEC_GET(data);
1479
1480         cksum += ttl_diff;
1481         ttl -= ttl_diff;
1482
1483         ip->hdr_checksum = cksum;
1484         ip->time_to_live = ttl;
1485
1486         drop = (ttl == 0) ? 1 : 0;
1487         TTL_STATS_ADD(data, drop);
1488
1489         return drop;
1490 }
1491
1492 static __rte_always_inline uint64_t
1493 pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
1494         struct ttl_data *data)
1495 {
1496         uint32_t drop;
1497         uint8_t ttl = ip->hop_limits;
1498         uint8_t ttl_diff = TTL_DEC_GET(data);
1499
1500         ttl -= ttl_diff;
1501
1502         ip->hop_limits = ttl;
1503
1504         drop = (ttl == 0) ? 1 : 0;
1505         TTL_STATS_ADD(data, drop);
1506
1507         return drop;
1508 }
1509
1510 /**
1511  * RTE_TABLE_ACTION_STATS
1512  */
1513 static int
1514 stats_cfg_check(struct rte_table_action_stats_config *stats)
1515 {
1516         if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
1517                 return -EINVAL;
1518
1519         return 0;
1520 }
1521
1522 struct stats_data {
1523         uint64_t n_packets;
1524         uint64_t n_bytes;
1525 } __attribute__((__packed__));
1526
1527 static int
1528 stats_apply(struct stats_data *data,
1529         struct rte_table_action_stats_params *p)
1530 {
1531         data->n_packets = p->n_packets;
1532         data->n_bytes = p->n_bytes;
1533
1534         return 0;
1535 }
1536
1537 static __rte_always_inline void
1538 pkt_work_stats(struct stats_data *data,
1539         uint16_t total_length)
1540 {
1541         data->n_packets++;
1542         data->n_bytes += total_length;
1543 }
1544
1545 /**
1546  * RTE_TABLE_ACTION_TIME
1547  */
1548 struct time_data {
1549         uint64_t time;
1550 } __attribute__((__packed__));
1551
1552 static int
1553 time_apply(struct time_data *data,
1554         struct rte_table_action_time_params *p)
1555 {
1556         data->time = p->time;
1557         return 0;
1558 }
1559
1560 static __rte_always_inline void
1561 pkt_work_time(struct time_data *data,
1562         uint64_t time)
1563 {
1564         data->time = time;
1565 }
1566
1567
1568 /**
1569  * RTE_TABLE_ACTION_CRYPTO
1570  */
1571
1572 #define CRYPTO_OP_MASK_CIPHER   0x1
1573 #define CRYPTO_OP_MASK_AUTH     0x2
1574 #define CRYPTO_OP_MASK_AEAD     0x4
1575
1576 struct crypto_op_sym_iv_aad {
1577         struct rte_crypto_op op;
1578         struct rte_crypto_sym_op sym_op;
1579         union {
1580                 struct {
1581                         uint8_t cipher_iv[
1582                                 RTE_TABLE_ACTION_SYM_CRYPTO_IV_SIZE_MAX];
1583                         uint8_t auth_iv[
1584                                 RTE_TABLE_ACTION_SYM_CRYPTO_IV_SIZE_MAX];
1585                 } cipher_auth;
1586
1587                 struct {
1588                         uint8_t iv[RTE_TABLE_ACTION_SYM_CRYPTO_IV_SIZE_MAX];
1589                         uint8_t aad[RTE_TABLE_ACTION_SYM_CRYPTO_AAD_SIZE_MAX];
1590                 } aead_iv_aad;
1591
1592         } iv_aad;
1593 };
1594
1595 struct sym_crypto_data {
1596
1597         union {
1598                 struct {
1599
1600                         /** Length of cipher iv. */
1601                         uint16_t cipher_iv_len;
1602
1603                         /** Offset from start of IP header to the cipher iv. */
1604                         uint16_t cipher_iv_data_offset;
1605
1606                         /** Length of cipher iv to be updated in the mbuf. */
1607                         uint16_t cipher_iv_update_len;
1608
1609                         /** Offset from start of IP header to the auth iv. */
1610                         uint16_t auth_iv_data_offset;
1611
1612                         /** Length of auth iv in the mbuf. */
1613                         uint16_t auth_iv_len;
1614
1615                         /** Length of auth iv to be updated in the mbuf. */
1616                         uint16_t auth_iv_update_len;
1617
1618                 } cipher_auth;
1619                 struct {
1620
1621                         /** Length of iv. */
1622                         uint16_t iv_len;
1623
1624                         /** Offset from start of IP header to the aead iv. */
1625                         uint16_t iv_data_offset;
1626
1627                         /** Length of iv to be updated in the mbuf. */
1628                         uint16_t iv_update_len;
1629
1630                         /** Length of aad */
1631                         uint16_t aad_len;
1632
1633                         /** Offset from start of IP header to the aad. */
1634                         uint16_t aad_data_offset;
1635
1636                         /** Length of aad to updated in the mbuf. */
1637                         uint16_t aad_update_len;
1638
1639                 } aead;
1640         };
1641
1642         /** Offset from start of IP header to the data. */
1643         uint16_t data_offset;
1644
1645         /** Digest length. */
1646         uint16_t digest_len;
1647
1648         /** block size */
1649         uint16_t block_size;
1650
1651         /** Mask of crypto operation */
1652         uint16_t op_mask;
1653
1654         /** Session pointer. */
1655         struct rte_cryptodev_sym_session *session;
1656
1657         /** Direction of crypto, encrypt or decrypt */
1658         uint16_t direction;
1659
1660         /** Private data size to store cipher iv / aad. */
1661         uint8_t iv_aad_data[32];
1662
1663 } __attribute__((__packed__));
1664
1665 static int
1666 sym_crypto_cfg_check(struct rte_table_action_sym_crypto_config *cfg)
1667 {
1668         if (!rte_cryptodev_pmd_is_valid_dev(cfg->cryptodev_id))
1669                 return -EINVAL;
1670         if (cfg->mp_create == NULL || cfg->mp_init == NULL)
1671                 return -EINVAL;
1672
1673         return 0;
1674 }
1675
1676 static int
1677 get_block_size(const struct rte_crypto_sym_xform *xform, uint8_t cdev_id)
1678 {
1679         struct rte_cryptodev_info dev_info;
1680         const struct rte_cryptodev_capabilities *cap;
1681         uint32_t i;
1682
1683         rte_cryptodev_info_get(cdev_id, &dev_info);
1684
1685         for (i = 0; dev_info.capabilities[i].op != RTE_CRYPTO_OP_TYPE_UNDEFINED;
1686                         i++) {
1687                 cap = &dev_info.capabilities[i];
1688
1689                 if (cap->sym.xform_type != xform->type)
1690                         continue;
1691
1692                 if ((xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
1693                                 (cap->sym.cipher.algo == xform->cipher.algo))
1694                         return cap->sym.cipher.block_size;
1695
1696                 if ((xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) &&
1697                                 (cap->sym.aead.algo == xform->aead.algo))
1698                         return cap->sym.aead.block_size;
1699
1700                 if (xform->type == RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED)
1701                         break;
1702         }
1703
1704         return -1;
1705 }
1706
1707 static int
1708 sym_crypto_apply(struct sym_crypto_data *data,
1709         struct rte_table_action_sym_crypto_config *cfg,
1710         struct rte_table_action_sym_crypto_params *p)
1711 {
1712         const struct rte_crypto_cipher_xform *cipher_xform = NULL;
1713         const struct rte_crypto_auth_xform *auth_xform = NULL;
1714         const struct rte_crypto_aead_xform *aead_xform = NULL;
1715         struct rte_crypto_sym_xform *xform = p->xform;
1716         struct rte_cryptodev_sym_session *session;
1717         int ret;
1718
1719         memset(data, 0, sizeof(*data));
1720
1721         while (xform) {
1722                 if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
1723                         cipher_xform = &xform->cipher;
1724
1725                         if (cipher_xform->iv.length >
1726                                 RTE_TABLE_ACTION_SYM_CRYPTO_IV_SIZE_MAX)
1727                                 return -ENOMEM;
1728                         if (cipher_xform->iv.offset !=
1729                                         RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET)
1730                                 return -EINVAL;
1731
1732                         ret = get_block_size(xform, cfg->cryptodev_id);
1733                         if (ret < 0)
1734                                 return -1;
1735                         data->block_size = (uint16_t)ret;
1736                         data->op_mask |= CRYPTO_OP_MASK_CIPHER;
1737
1738                         data->cipher_auth.cipher_iv_len =
1739                                         cipher_xform->iv.length;
1740                         data->cipher_auth.cipher_iv_data_offset = (uint16_t)
1741                                         p->cipher_auth.cipher_iv_update.offset;
1742                         data->cipher_auth.cipher_iv_update_len = (uint16_t)
1743                                         p->cipher_auth.cipher_iv_update.length;
1744
1745                         rte_memcpy(data->iv_aad_data,
1746                                         p->cipher_auth.cipher_iv.val,
1747                                         p->cipher_auth.cipher_iv.length);
1748
1749                         data->direction = cipher_xform->op;
1750
1751                 } else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
1752                         auth_xform = &xform->auth;
1753                         if (auth_xform->iv.length >
1754                                 RTE_TABLE_ACTION_SYM_CRYPTO_IV_SIZE_MAX)
1755                                 return -ENOMEM;
1756                         data->op_mask |= CRYPTO_OP_MASK_AUTH;
1757
1758                         data->cipher_auth.auth_iv_len = auth_xform->iv.length;
1759                         data->cipher_auth.auth_iv_data_offset = (uint16_t)
1760                                         p->cipher_auth.auth_iv_update.offset;
1761                         data->cipher_auth.auth_iv_update_len = (uint16_t)
1762                                         p->cipher_auth.auth_iv_update.length;
1763                         data->digest_len = auth_xform->digest_length;
1764
1765                         data->direction = (auth_xform->op ==
1766                                         RTE_CRYPTO_AUTH_OP_GENERATE) ?
1767                                         RTE_CRYPTO_CIPHER_OP_ENCRYPT :
1768                                         RTE_CRYPTO_CIPHER_OP_DECRYPT;
1769
1770                 } else if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
1771                         aead_xform = &xform->aead;
1772
1773                         if ((aead_xform->iv.length >
1774                                 RTE_TABLE_ACTION_SYM_CRYPTO_IV_SIZE_MAX) || (
1775                                 aead_xform->aad_length >
1776                                 RTE_TABLE_ACTION_SYM_CRYPTO_AAD_SIZE_MAX))
1777                                 return -EINVAL;
1778                         if (aead_xform->iv.offset !=
1779                                         RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET)
1780                                 return -EINVAL;
1781
1782                         ret = get_block_size(xform, cfg->cryptodev_id);
1783                         if (ret < 0)
1784                                 return -1;
1785                         data->block_size = (uint16_t)ret;
1786                         data->op_mask |= CRYPTO_OP_MASK_AEAD;
1787
1788                         data->digest_len = aead_xform->digest_length;
1789                         data->aead.iv_len = aead_xform->iv.length;
1790                         data->aead.aad_len = aead_xform->aad_length;
1791
1792                         data->aead.iv_data_offset = (uint16_t)
1793                                         p->aead.iv_update.offset;
1794                         data->aead.iv_update_len = (uint16_t)
1795                                         p->aead.iv_update.length;
1796                         data->aead.aad_data_offset = (uint16_t)
1797                                         p->aead.aad_update.offset;
1798                         data->aead.aad_update_len = (uint16_t)
1799                                         p->aead.aad_update.length;
1800
1801                         rte_memcpy(data->iv_aad_data,
1802                                         p->aead.iv.val,
1803                                         p->aead.iv.length);
1804
1805                         rte_memcpy(data->iv_aad_data + p->aead.iv.length,
1806                                         p->aead.aad.val,
1807                                         p->aead.aad.length);
1808
1809                         data->direction = (aead_xform->op ==
1810                                         RTE_CRYPTO_AEAD_OP_ENCRYPT) ?
1811                                         RTE_CRYPTO_CIPHER_OP_ENCRYPT :
1812                                         RTE_CRYPTO_CIPHER_OP_DECRYPT;
1813                 } else
1814                         return -EINVAL;
1815
1816                 xform = xform->next;
1817         }
1818
1819         if (auth_xform && auth_xform->iv.length) {
1820                 if (cipher_xform) {
1821                         if (auth_xform->iv.offset !=
1822                                         RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET +
1823                                         cipher_xform->iv.length)
1824                                 return -EINVAL;
1825
1826                         rte_memcpy(data->iv_aad_data + cipher_xform->iv.length,
1827                                         p->cipher_auth.auth_iv.val,
1828                                         p->cipher_auth.auth_iv.length);
1829                 } else {
1830                         rte_memcpy(data->iv_aad_data,
1831                                         p->cipher_auth.auth_iv.val,
1832                                         p->cipher_auth.auth_iv.length);
1833                 }
1834         }
1835
1836         session = rte_cryptodev_sym_session_create(cfg->mp_create);
1837         if (!session)
1838                 return -ENOMEM;
1839
1840         ret = rte_cryptodev_sym_session_init(cfg->cryptodev_id, session,
1841                         p->xform, cfg->mp_init);
1842         if (ret < 0) {
1843                 rte_cryptodev_sym_session_free(session);
1844                 return ret;
1845         }
1846
1847         data->data_offset = (uint16_t)p->data_offset;
1848         data->session = session;
1849
1850         return 0;
1851 }
1852
1853 static __rte_always_inline uint64_t
1854 pkt_work_sym_crypto(struct rte_mbuf *mbuf, struct sym_crypto_data *data,
1855                 struct rte_table_action_sym_crypto_config *cfg,
1856                 uint16_t ip_offset)
1857 {
1858         struct crypto_op_sym_iv_aad *crypto_op = (struct crypto_op_sym_iv_aad *)
1859                         RTE_MBUF_METADATA_UINT8_PTR(mbuf, cfg->op_offset);
1860         struct rte_crypto_op *op = &crypto_op->op;
1861         struct rte_crypto_sym_op *sym = op->sym;
1862         uint32_t pkt_offset = sizeof(*mbuf) + mbuf->data_off;
1863         uint32_t payload_len = pkt_offset + mbuf->data_len - data->data_offset;
1864
1865         op->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
1866         op->sess_type = RTE_CRYPTO_OP_WITH_SESSION;
1867         op->phys_addr = mbuf->buf_iova + cfg->op_offset - sizeof(*mbuf);
1868         op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
1869         sym->m_src = mbuf;
1870         sym->m_dst = NULL;
1871         sym->session = data->session;
1872
1873         /** pad the packet */
1874         if (data->direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
1875                 uint32_t append_len = RTE_ALIGN_CEIL(payload_len,
1876                                 data->block_size) - payload_len;
1877
1878                 if (unlikely(rte_pktmbuf_append(mbuf, append_len +
1879                                 data->digest_len) == NULL))
1880                         return 1;
1881
1882                 payload_len += append_len;
1883         } else
1884                 payload_len -= data->digest_len;
1885
1886         if (data->op_mask & CRYPTO_OP_MASK_CIPHER) {
1887                 /** prepare cipher op */
1888                 uint8_t *iv = crypto_op->iv_aad.cipher_auth.cipher_iv;
1889
1890                 sym->cipher.data.length = payload_len;
1891                 sym->cipher.data.offset = data->data_offset - pkt_offset;
1892
1893                 if (data->cipher_auth.cipher_iv_update_len) {
1894                         uint8_t *pkt_iv = RTE_MBUF_METADATA_UINT8_PTR(mbuf,
1895                                 data->cipher_auth.cipher_iv_data_offset
1896                                 + ip_offset);
1897
1898                         /** For encryption, update the pkt iv field, otherwise
1899                          *  update the iv_aad_field
1900                          **/
1901                         if (data->direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
1902                                 rte_memcpy(pkt_iv, data->iv_aad_data,
1903                                         data->cipher_auth.cipher_iv_update_len);
1904                         else
1905                                 rte_memcpy(data->iv_aad_data, pkt_iv,
1906                                         data->cipher_auth.cipher_iv_update_len);
1907                 }
1908
1909                 /** write iv */
1910                 rte_memcpy(iv, data->iv_aad_data,
1911                                 data->cipher_auth.cipher_iv_len);
1912         }
1913
1914         if (data->op_mask & CRYPTO_OP_MASK_AUTH) {
1915                 /** authentication always start from IP header. */
1916                 sym->auth.data.offset = ip_offset - pkt_offset;
1917                 sym->auth.data.length = mbuf->data_len - sym->auth.data.offset -
1918                                 data->digest_len;
1919                 sym->auth.digest.data = rte_pktmbuf_mtod_offset(mbuf,
1920                                 uint8_t *, rte_pktmbuf_pkt_len(mbuf) -
1921                                 data->digest_len);
1922                 sym->auth.digest.phys_addr = rte_pktmbuf_iova_offset(mbuf,
1923                                 rte_pktmbuf_pkt_len(mbuf) - data->digest_len);
1924
1925                 if (data->cipher_auth.auth_iv_update_len) {
1926                         uint8_t *pkt_iv = RTE_MBUF_METADATA_UINT8_PTR(mbuf,
1927                                         data->cipher_auth.auth_iv_data_offset
1928                                         + ip_offset);
1929                         uint8_t *data_iv = data->iv_aad_data +
1930                                         data->cipher_auth.cipher_iv_len;
1931
1932                         if (data->direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
1933                                 rte_memcpy(pkt_iv, data_iv,
1934                                         data->cipher_auth.auth_iv_update_len);
1935                         else
1936                                 rte_memcpy(data_iv, pkt_iv,
1937                                         data->cipher_auth.auth_iv_update_len);
1938                 }
1939
1940                 if (data->cipher_auth.auth_iv_len) {
1941                         /** prepare cipher op */
1942                         uint8_t *iv = crypto_op->iv_aad.cipher_auth.auth_iv;
1943
1944                         rte_memcpy(iv, data->iv_aad_data +
1945                                         data->cipher_auth.cipher_iv_len,
1946                                         data->cipher_auth.auth_iv_len);
1947                 }
1948         }
1949
1950         if (data->op_mask & CRYPTO_OP_MASK_AEAD) {
1951                 uint8_t *iv = crypto_op->iv_aad.aead_iv_aad.iv;
1952                 uint8_t *aad = crypto_op->iv_aad.aead_iv_aad.aad;
1953
1954                 sym->aead.aad.data = aad;
1955                 sym->aead.aad.phys_addr = rte_pktmbuf_iova_offset(mbuf,
1956                                 aad - rte_pktmbuf_mtod(mbuf, uint8_t *));
1957                 sym->aead.digest.data = rte_pktmbuf_mtod_offset(mbuf,
1958                                 uint8_t *, rte_pktmbuf_pkt_len(mbuf) -
1959                                 data->digest_len);
1960                 sym->aead.digest.phys_addr = rte_pktmbuf_iova_offset(mbuf,
1961                                 rte_pktmbuf_pkt_len(mbuf) - data->digest_len);
1962                 sym->aead.data.offset = data->data_offset - pkt_offset;
1963                 sym->aead.data.length = payload_len;
1964
1965                 if (data->aead.iv_update_len) {
1966                         uint8_t *pkt_iv = RTE_MBUF_METADATA_UINT8_PTR(mbuf,
1967                                         data->aead.iv_data_offset + ip_offset);
1968                         uint8_t *data_iv = data->iv_aad_data;
1969
1970                         if (data->direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
1971                                 rte_memcpy(pkt_iv, data_iv,
1972                                                 data->aead.iv_update_len);
1973                         else
1974                                 rte_memcpy(data_iv, pkt_iv,
1975                                         data->aead.iv_update_len);
1976                 }
1977
1978                 rte_memcpy(iv, data->iv_aad_data, data->aead.iv_len);
1979
1980                 if (data->aead.aad_update_len) {
1981                         uint8_t *pkt_aad = RTE_MBUF_METADATA_UINT8_PTR(mbuf,
1982                                         data->aead.aad_data_offset + ip_offset);
1983                         uint8_t *data_aad = data->iv_aad_data +
1984                                         data->aead.iv_len;
1985
1986                         if (data->direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
1987                                 rte_memcpy(pkt_aad, data_aad,
1988                                                 data->aead.iv_update_len);
1989                         else
1990                                 rte_memcpy(data_aad, pkt_aad,
1991                                         data->aead.iv_update_len);
1992                 }
1993
1994                 rte_memcpy(aad, data->iv_aad_data + data->aead.iv_len,
1995                                         data->aead.aad_len);
1996         }
1997
1998         return 0;
1999 }
2000
2001 /**
2002  * RTE_TABLE_ACTION_TAG
2003  */
2004 struct tag_data {
2005         uint32_t tag;
2006 } __attribute__((__packed__));
2007
2008 static int
2009 tag_apply(struct tag_data *data,
2010         struct rte_table_action_tag_params *p)
2011 {
2012         data->tag = p->tag;
2013         return 0;
2014 }
2015
2016 static __rte_always_inline void
2017 pkt_work_tag(struct rte_mbuf *mbuf,
2018         struct tag_data *data)
2019 {
2020         mbuf->hash.fdir.hi = data->tag;
2021         mbuf->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
2022 }
2023
2024 static __rte_always_inline void
2025 pkt4_work_tag(struct rte_mbuf *mbuf0,
2026         struct rte_mbuf *mbuf1,
2027         struct rte_mbuf *mbuf2,
2028         struct rte_mbuf *mbuf3,
2029         struct tag_data *data0,
2030         struct tag_data *data1,
2031         struct tag_data *data2,
2032         struct tag_data *data3)
2033 {
2034         mbuf0->hash.fdir.hi = data0->tag;
2035         mbuf1->hash.fdir.hi = data1->tag;
2036         mbuf2->hash.fdir.hi = data2->tag;
2037         mbuf3->hash.fdir.hi = data3->tag;
2038
2039         mbuf0->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
2040         mbuf1->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
2041         mbuf2->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
2042         mbuf3->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
2043 }
2044
2045 /**
2046  * RTE_TABLE_ACTION_DECAP
2047  */
2048 struct decap_data {
2049         uint16_t n;
2050 } __attribute__((__packed__));
2051
2052 static int
2053 decap_apply(struct decap_data *data,
2054         struct rte_table_action_decap_params *p)
2055 {
2056         data->n = p->n;
2057         return 0;
2058 }
2059
2060 static __rte_always_inline void
2061 pkt_work_decap(struct rte_mbuf *mbuf,
2062         struct decap_data *data)
2063 {
2064         uint16_t data_off = mbuf->data_off;
2065         uint16_t data_len = mbuf->data_len;
2066         uint32_t pkt_len = mbuf->pkt_len;
2067         uint16_t n = data->n;
2068
2069         mbuf->data_off = data_off + n;
2070         mbuf->data_len = data_len - n;
2071         mbuf->pkt_len = pkt_len - n;
2072 }
2073
2074 static __rte_always_inline void
2075 pkt4_work_decap(struct rte_mbuf *mbuf0,
2076         struct rte_mbuf *mbuf1,
2077         struct rte_mbuf *mbuf2,
2078         struct rte_mbuf *mbuf3,
2079         struct decap_data *data0,
2080         struct decap_data *data1,
2081         struct decap_data *data2,
2082         struct decap_data *data3)
2083 {
2084         uint16_t data_off0 = mbuf0->data_off;
2085         uint16_t data_len0 = mbuf0->data_len;
2086         uint32_t pkt_len0 = mbuf0->pkt_len;
2087
2088         uint16_t data_off1 = mbuf1->data_off;
2089         uint16_t data_len1 = mbuf1->data_len;
2090         uint32_t pkt_len1 = mbuf1->pkt_len;
2091
2092         uint16_t data_off2 = mbuf2->data_off;
2093         uint16_t data_len2 = mbuf2->data_len;
2094         uint32_t pkt_len2 = mbuf2->pkt_len;
2095
2096         uint16_t data_off3 = mbuf3->data_off;
2097         uint16_t data_len3 = mbuf3->data_len;
2098         uint32_t pkt_len3 = mbuf3->pkt_len;
2099
2100         uint16_t n0 = data0->n;
2101         uint16_t n1 = data1->n;
2102         uint16_t n2 = data2->n;
2103         uint16_t n3 = data3->n;
2104
2105         mbuf0->data_off = data_off0 + n0;
2106         mbuf0->data_len = data_len0 - n0;
2107         mbuf0->pkt_len = pkt_len0 - n0;
2108
2109         mbuf1->data_off = data_off1 + n1;
2110         mbuf1->data_len = data_len1 - n1;
2111         mbuf1->pkt_len = pkt_len1 - n1;
2112
2113         mbuf2->data_off = data_off2 + n2;
2114         mbuf2->data_len = data_len2 - n2;
2115         mbuf2->pkt_len = pkt_len2 - n2;
2116
2117         mbuf3->data_off = data_off3 + n3;
2118         mbuf3->data_len = data_len3 - n3;
2119         mbuf3->pkt_len = pkt_len3 - n3;
2120 }
2121
2122 /**
2123  * Action profile
2124  */
2125 static int
2126 action_valid(enum rte_table_action_type action)
2127 {
2128         switch (action) {
2129         case RTE_TABLE_ACTION_FWD:
2130         case RTE_TABLE_ACTION_LB:
2131         case RTE_TABLE_ACTION_MTR:
2132         case RTE_TABLE_ACTION_TM:
2133         case RTE_TABLE_ACTION_ENCAP:
2134         case RTE_TABLE_ACTION_NAT:
2135         case RTE_TABLE_ACTION_TTL:
2136         case RTE_TABLE_ACTION_STATS:
2137         case RTE_TABLE_ACTION_TIME:
2138         case RTE_TABLE_ACTION_SYM_CRYPTO:
2139         case RTE_TABLE_ACTION_TAG:
2140         case RTE_TABLE_ACTION_DECAP:
2141                 return 1;
2142         default:
2143                 return 0;
2144         }
2145 }
2146
2147
2148 #define RTE_TABLE_ACTION_MAX                      64
2149
2150 struct ap_config {
2151         uint64_t action_mask;
2152         struct rte_table_action_common_config common;
2153         struct rte_table_action_lb_config lb;
2154         struct rte_table_action_mtr_config mtr;
2155         struct rte_table_action_tm_config tm;
2156         struct rte_table_action_encap_config encap;
2157         struct rte_table_action_nat_config nat;
2158         struct rte_table_action_ttl_config ttl;
2159         struct rte_table_action_stats_config stats;
2160         struct rte_table_action_sym_crypto_config sym_crypto;
2161 };
2162
2163 static size_t
2164 action_cfg_size(enum rte_table_action_type action)
2165 {
2166         switch (action) {
2167         case RTE_TABLE_ACTION_LB:
2168                 return sizeof(struct rte_table_action_lb_config);
2169         case RTE_TABLE_ACTION_MTR:
2170                 return sizeof(struct rte_table_action_mtr_config);
2171         case RTE_TABLE_ACTION_TM:
2172                 return sizeof(struct rte_table_action_tm_config);
2173         case RTE_TABLE_ACTION_ENCAP:
2174                 return sizeof(struct rte_table_action_encap_config);
2175         case RTE_TABLE_ACTION_NAT:
2176                 return sizeof(struct rte_table_action_nat_config);
2177         case RTE_TABLE_ACTION_TTL:
2178                 return sizeof(struct rte_table_action_ttl_config);
2179         case RTE_TABLE_ACTION_STATS:
2180                 return sizeof(struct rte_table_action_stats_config);
2181         case RTE_TABLE_ACTION_SYM_CRYPTO:
2182                 return sizeof(struct rte_table_action_sym_crypto_config);
2183         default:
2184                 return 0;
2185         }
2186 }
2187
2188 static void*
2189 action_cfg_get(struct ap_config *ap_config,
2190         enum rte_table_action_type type)
2191 {
2192         switch (type) {
2193         case RTE_TABLE_ACTION_LB:
2194                 return &ap_config->lb;
2195
2196         case RTE_TABLE_ACTION_MTR:
2197                 return &ap_config->mtr;
2198
2199         case RTE_TABLE_ACTION_TM:
2200                 return &ap_config->tm;
2201
2202         case RTE_TABLE_ACTION_ENCAP:
2203                 return &ap_config->encap;
2204
2205         case RTE_TABLE_ACTION_NAT:
2206                 return &ap_config->nat;
2207
2208         case RTE_TABLE_ACTION_TTL:
2209                 return &ap_config->ttl;
2210
2211         case RTE_TABLE_ACTION_STATS:
2212                 return &ap_config->stats;
2213
2214         case RTE_TABLE_ACTION_SYM_CRYPTO:
2215                 return &ap_config->sym_crypto;
2216         default:
2217                 return NULL;
2218         }
2219 }
2220
2221 static void
2222 action_cfg_set(struct ap_config *ap_config,
2223         enum rte_table_action_type type,
2224         void *action_cfg)
2225 {
2226         void *dst = action_cfg_get(ap_config, type);
2227
2228         if (dst)
2229                 memcpy(dst, action_cfg, action_cfg_size(type));
2230
2231         ap_config->action_mask |= 1LLU << type;
2232 }
2233
2234 struct ap_data {
2235         size_t offset[RTE_TABLE_ACTION_MAX];
2236         size_t total_size;
2237 };
2238
2239 static size_t
2240 action_data_size(enum rte_table_action_type action,
2241         struct ap_config *ap_config)
2242 {
2243         switch (action) {
2244         case RTE_TABLE_ACTION_FWD:
2245                 return sizeof(struct fwd_data);
2246
2247         case RTE_TABLE_ACTION_LB:
2248                 return sizeof(struct lb_data);
2249
2250         case RTE_TABLE_ACTION_MTR:
2251                 return mtr_data_size(&ap_config->mtr);
2252
2253         case RTE_TABLE_ACTION_TM:
2254                 return sizeof(struct tm_data);
2255
2256         case RTE_TABLE_ACTION_ENCAP:
2257                 return encap_data_size(&ap_config->encap);
2258
2259         case RTE_TABLE_ACTION_NAT:
2260                 return nat_data_size(&ap_config->nat,
2261                         &ap_config->common);
2262
2263         case RTE_TABLE_ACTION_TTL:
2264                 return sizeof(struct ttl_data);
2265
2266         case RTE_TABLE_ACTION_STATS:
2267                 return sizeof(struct stats_data);
2268
2269         case RTE_TABLE_ACTION_TIME:
2270                 return sizeof(struct time_data);
2271
2272         case RTE_TABLE_ACTION_SYM_CRYPTO:
2273                 return (sizeof(struct sym_crypto_data));
2274
2275         case RTE_TABLE_ACTION_TAG:
2276                 return sizeof(struct tag_data);
2277
2278         case RTE_TABLE_ACTION_DECAP:
2279                 return sizeof(struct decap_data);
2280
2281         default:
2282                 return 0;
2283         }
2284 }
2285
2286
2287 static void
2288 action_data_offset_set(struct ap_data *ap_data,
2289         struct ap_config *ap_config)
2290 {
2291         uint64_t action_mask = ap_config->action_mask;
2292         size_t offset;
2293         uint32_t action;
2294
2295         memset(ap_data->offset, 0, sizeof(ap_data->offset));
2296
2297         offset = 0;
2298         for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
2299                 if (action_mask & (1LLU << action)) {
2300                         ap_data->offset[action] = offset;
2301                         offset += action_data_size((enum rte_table_action_type)action,
2302                                 ap_config);
2303                 }
2304
2305         ap_data->total_size = offset;
2306 }
2307
2308 struct rte_table_action_profile {
2309         struct ap_config cfg;
2310         struct ap_data data;
2311         int frozen;
2312 };
2313
2314 struct rte_table_action_profile *
2315 rte_table_action_profile_create(struct rte_table_action_common_config *common)
2316 {
2317         struct rte_table_action_profile *ap;
2318
2319         /* Check input arguments */
2320         if (common == NULL)
2321                 return NULL;
2322
2323         /* Memory allocation */
2324         ap = calloc(1, sizeof(struct rte_table_action_profile));
2325         if (ap == NULL)
2326                 return NULL;
2327
2328         /* Initialization */
2329         memcpy(&ap->cfg.common, common, sizeof(*common));
2330
2331         return ap;
2332 }
2333
2334
2335 int
2336 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
2337         enum rte_table_action_type type,
2338         void *action_config)
2339 {
2340         int status;
2341
2342         /* Check input arguments */
2343         if ((profile == NULL) ||
2344                 profile->frozen ||
2345                 (action_valid(type) == 0) ||
2346                 (profile->cfg.action_mask & (1LLU << type)) ||
2347                 ((action_cfg_size(type) == 0) && action_config) ||
2348                 (action_cfg_size(type) && (action_config == NULL)))
2349                 return -EINVAL;
2350
2351         switch (type) {
2352         case RTE_TABLE_ACTION_LB:
2353                 status = lb_cfg_check(action_config);
2354                 break;
2355
2356         case RTE_TABLE_ACTION_MTR:
2357                 status = mtr_cfg_check(action_config);
2358                 break;
2359
2360         case RTE_TABLE_ACTION_TM:
2361                 status = tm_cfg_check(action_config);
2362                 break;
2363
2364         case RTE_TABLE_ACTION_ENCAP:
2365                 status = encap_cfg_check(action_config);
2366                 break;
2367
2368         case RTE_TABLE_ACTION_NAT:
2369                 status = nat_cfg_check(action_config);
2370                 break;
2371
2372         case RTE_TABLE_ACTION_TTL:
2373                 status = ttl_cfg_check(action_config);
2374                 break;
2375
2376         case RTE_TABLE_ACTION_STATS:
2377                 status = stats_cfg_check(action_config);
2378                 break;
2379
2380         case RTE_TABLE_ACTION_SYM_CRYPTO:
2381                 status = sym_crypto_cfg_check(action_config);
2382                 break;
2383
2384         default:
2385                 status = 0;
2386                 break;
2387         }
2388
2389         if (status)
2390                 return status;
2391
2392         /* Action enable */
2393         action_cfg_set(&profile->cfg, type, action_config);
2394
2395         return 0;
2396 }
2397
2398 int
2399 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
2400 {
2401         if (profile->frozen)
2402                 return -EBUSY;
2403
2404         profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
2405         action_data_offset_set(&profile->data, &profile->cfg);
2406         profile->frozen = 1;
2407
2408         return 0;
2409 }
2410
2411 int
2412 rte_table_action_profile_free(struct rte_table_action_profile *profile)
2413 {
2414         if (profile == NULL)
2415                 return 0;
2416
2417         free(profile);
2418         return 0;
2419 }
2420
2421 /**
2422  * Action
2423  */
2424 #define METER_PROFILES_MAX                                 32
2425
2426 struct rte_table_action {
2427         struct ap_config cfg;
2428         struct ap_data data;
2429         struct dscp_table_data dscp_table;
2430         struct meter_profile_data mp[METER_PROFILES_MAX];
2431 };
2432
2433 struct rte_table_action *
2434 rte_table_action_create(struct rte_table_action_profile *profile,
2435         uint32_t socket_id)
2436 {
2437         struct rte_table_action *action;
2438
2439         /* Check input arguments */
2440         if ((profile == NULL) ||
2441                 (profile->frozen == 0))
2442                 return NULL;
2443
2444         /* Memory allocation */
2445         action = rte_zmalloc_socket(NULL,
2446                 sizeof(struct rte_table_action),
2447                 RTE_CACHE_LINE_SIZE,
2448                 socket_id);
2449         if (action == NULL)
2450                 return NULL;
2451
2452         /* Initialization */
2453         memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
2454         memcpy(&action->data, &profile->data, sizeof(profile->data));
2455
2456         return action;
2457 }
2458
2459 static __rte_always_inline void *
2460 action_data_get(void *data,
2461         struct rte_table_action *action,
2462         enum rte_table_action_type type)
2463 {
2464         size_t offset = action->data.offset[type];
2465         uint8_t *data_bytes = data;
2466
2467         return &data_bytes[offset];
2468 }
2469
2470 int
2471 rte_table_action_apply(struct rte_table_action *action,
2472         void *data,
2473         enum rte_table_action_type type,
2474         void *action_params)
2475 {
2476         void *action_data;
2477
2478         /* Check input arguments */
2479         if ((action == NULL) ||
2480                 (data == NULL) ||
2481                 (action_valid(type) == 0) ||
2482                 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
2483                 (action_params == NULL))
2484                 return -EINVAL;
2485
2486         /* Data update */
2487         action_data = action_data_get(data, action, type);
2488
2489         switch (type) {
2490         case RTE_TABLE_ACTION_FWD:
2491                 return fwd_apply(action_data,
2492                         action_params);
2493
2494         case RTE_TABLE_ACTION_LB:
2495                 return lb_apply(action_data,
2496                         action_params);
2497
2498         case RTE_TABLE_ACTION_MTR:
2499                 return mtr_apply(action_data,
2500                         action_params,
2501                         &action->cfg.mtr,
2502                         action->mp,
2503                         RTE_DIM(action->mp));
2504
2505         case RTE_TABLE_ACTION_TM:
2506                 return tm_apply(action_data,
2507                         action_params,
2508                         &action->cfg.tm);
2509
2510         case RTE_TABLE_ACTION_ENCAP:
2511                 return encap_apply(action_data,
2512                         action_params,
2513                         &action->cfg.encap,
2514                         &action->cfg.common);
2515
2516         case RTE_TABLE_ACTION_NAT:
2517                 return nat_apply(action_data,
2518                         action_params,
2519                         &action->cfg.common);
2520
2521         case RTE_TABLE_ACTION_TTL:
2522                 return ttl_apply(action_data,
2523                         action_params);
2524
2525         case RTE_TABLE_ACTION_STATS:
2526                 return stats_apply(action_data,
2527                         action_params);
2528
2529         case RTE_TABLE_ACTION_TIME:
2530                 return time_apply(action_data,
2531                         action_params);
2532
2533         case RTE_TABLE_ACTION_SYM_CRYPTO:
2534                 return sym_crypto_apply(action_data,
2535                                 &action->cfg.sym_crypto,
2536                                 action_params);
2537
2538         case RTE_TABLE_ACTION_TAG:
2539                 return tag_apply(action_data,
2540                         action_params);
2541
2542         case RTE_TABLE_ACTION_DECAP:
2543                 return decap_apply(action_data,
2544                         action_params);
2545
2546         default:
2547                 return -EINVAL;
2548         }
2549 }
2550
2551 int
2552 rte_table_action_dscp_table_update(struct rte_table_action *action,
2553         uint64_t dscp_mask,
2554         struct rte_table_action_dscp_table *table)
2555 {
2556         uint32_t i;
2557
2558         /* Check input arguments */
2559         if ((action == NULL) ||
2560                 ((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
2561                 (1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
2562                 (dscp_mask == 0) ||
2563                 (table == NULL))
2564                 return -EINVAL;
2565
2566         for (i = 0; i < RTE_DIM(table->entry); i++) {
2567                 struct dscp_table_entry_data *data =
2568                         &action->dscp_table.entry[i];
2569                 struct rte_table_action_dscp_table_entry *entry =
2570                         &table->entry[i];
2571
2572                 if ((dscp_mask & (1LLU << i)) == 0)
2573                         continue;
2574
2575                 data->color = entry->color;
2576                 data->tc = entry->tc_id;
2577                 data->tc_queue = entry->tc_queue_id;
2578         }
2579
2580         return 0;
2581 }
2582
2583 int
2584 rte_table_action_meter_profile_add(struct rte_table_action *action,
2585         uint32_t meter_profile_id,
2586         struct rte_table_action_meter_profile *profile)
2587 {
2588         struct meter_profile_data *mp_data;
2589         uint32_t status;
2590
2591         /* Check input arguments */
2592         if ((action == NULL) ||
2593                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
2594                 (profile == NULL))
2595                 return -EINVAL;
2596
2597         if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
2598                 return -ENOTSUP;
2599
2600         mp_data = meter_profile_data_find(action->mp,
2601                 RTE_DIM(action->mp),
2602                 meter_profile_id);
2603         if (mp_data)
2604                 return -EEXIST;
2605
2606         mp_data = meter_profile_data_find_unused(action->mp,
2607                 RTE_DIM(action->mp));
2608         if (!mp_data)
2609                 return -ENOSPC;
2610
2611         /* Install new profile */
2612         status = rte_meter_trtcm_profile_config(&mp_data->profile,
2613                 &profile->trtcm);
2614         if (status)
2615                 return status;
2616
2617         mp_data->profile_id = meter_profile_id;
2618         mp_data->valid = 1;
2619
2620         return 0;
2621 }
2622
2623 int
2624 rte_table_action_meter_profile_delete(struct rte_table_action *action,
2625         uint32_t meter_profile_id)
2626 {
2627         struct meter_profile_data *mp_data;
2628
2629         /* Check input arguments */
2630         if ((action == NULL) ||
2631                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
2632                 return -EINVAL;
2633
2634         mp_data = meter_profile_data_find(action->mp,
2635                 RTE_DIM(action->mp),
2636                 meter_profile_id);
2637         if (!mp_data)
2638                 return 0;
2639
2640         /* Uninstall profile */
2641         mp_data->valid = 0;
2642
2643         return 0;
2644 }
2645
2646 int
2647 rte_table_action_meter_read(struct rte_table_action *action,
2648         void *data,
2649         uint32_t tc_mask,
2650         struct rte_table_action_mtr_counters *stats,
2651         int clear)
2652 {
2653         struct mtr_trtcm_data *mtr_data;
2654         uint32_t i;
2655
2656         /* Check input arguments */
2657         if ((action == NULL) ||
2658                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
2659                 (data == NULL) ||
2660                 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
2661                 return -EINVAL;
2662
2663         mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
2664
2665         /* Read */
2666         if (stats) {
2667                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
2668                         struct rte_table_action_mtr_counters_tc *dst =
2669                                 &stats->stats[i];
2670                         struct mtr_trtcm_data *src = &mtr_data[i];
2671
2672                         if ((tc_mask & (1 << i)) == 0)
2673                                 continue;
2674
2675                         dst->n_packets[e_RTE_METER_GREEN] =
2676                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
2677
2678                         dst->n_packets[e_RTE_METER_YELLOW] =
2679                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
2680
2681                         dst->n_packets[e_RTE_METER_RED] =
2682                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
2683
2684                         dst->n_packets_valid = 1;
2685                         dst->n_bytes_valid = 0;
2686                 }
2687
2688                 stats->tc_mask = tc_mask;
2689         }
2690
2691         /* Clear */
2692         if (clear)
2693                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
2694                         struct mtr_trtcm_data *src = &mtr_data[i];
2695
2696                         if ((tc_mask & (1 << i)) == 0)
2697                                 continue;
2698
2699                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
2700                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
2701                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
2702                 }
2703
2704
2705         return 0;
2706 }
2707
2708 int
2709 rte_table_action_ttl_read(struct rte_table_action *action,
2710         void *data,
2711         struct rte_table_action_ttl_counters *stats,
2712         int clear)
2713 {
2714         struct ttl_data *ttl_data;
2715
2716         /* Check input arguments */
2717         if ((action == NULL) ||
2718                 ((action->cfg.action_mask &
2719                 (1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
2720                 (data == NULL))
2721                 return -EINVAL;
2722
2723         ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
2724
2725         /* Read */
2726         if (stats)
2727                 stats->n_packets = TTL_STATS_READ(ttl_data);
2728
2729         /* Clear */
2730         if (clear)
2731                 TTL_STATS_RESET(ttl_data);
2732
2733         return 0;
2734 }
2735
2736 int
2737 rte_table_action_stats_read(struct rte_table_action *action,
2738         void *data,
2739         struct rte_table_action_stats_counters *stats,
2740         int clear)
2741 {
2742         struct stats_data *stats_data;
2743
2744         /* Check input arguments */
2745         if ((action == NULL) ||
2746                 ((action->cfg.action_mask &
2747                 (1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
2748                 (data == NULL))
2749                 return -EINVAL;
2750
2751         stats_data = action_data_get(data, action,
2752                 RTE_TABLE_ACTION_STATS);
2753
2754         /* Read */
2755         if (stats) {
2756                 stats->n_packets = stats_data->n_packets;
2757                 stats->n_bytes = stats_data->n_bytes;
2758                 stats->n_packets_valid = 1;
2759                 stats->n_bytes_valid = 1;
2760         }
2761
2762         /* Clear */
2763         if (clear) {
2764                 stats_data->n_packets = 0;
2765                 stats_data->n_bytes = 0;
2766         }
2767
2768         return 0;
2769 }
2770
2771 int
2772 rte_table_action_time_read(struct rte_table_action *action,
2773         void *data,
2774         uint64_t *timestamp)
2775 {
2776         struct time_data *time_data;
2777
2778         /* Check input arguments */
2779         if ((action == NULL) ||
2780                 ((action->cfg.action_mask &
2781                 (1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
2782                 (data == NULL) ||
2783                 (timestamp == NULL))
2784                 return -EINVAL;
2785
2786         time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
2787
2788         /* Read */
2789         *timestamp = time_data->time;
2790
2791         return 0;
2792 }
2793
2794 struct rte_cryptodev_sym_session *
2795 rte_table_action_crypto_sym_session_get(struct rte_table_action *action,
2796         void *data)
2797 {
2798         struct sym_crypto_data *sym_crypto_data;
2799
2800         /* Check input arguments */
2801         if ((action == NULL) ||
2802                 ((action->cfg.action_mask &
2803                 (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) == 0) ||
2804                 (data == NULL))
2805                 return NULL;
2806
2807         sym_crypto_data = action_data_get(data, action,
2808                         RTE_TABLE_ACTION_SYM_CRYPTO);
2809
2810         return sym_crypto_data->session;
2811 }
2812
2813 static __rte_always_inline uint64_t
2814 pkt_work(struct rte_mbuf *mbuf,
2815         struct rte_pipeline_table_entry *table_entry,
2816         uint64_t time,
2817         struct rte_table_action *action,
2818         struct ap_config *cfg)
2819 {
2820         uint64_t drop_mask = 0;
2821
2822         uint32_t ip_offset = action->cfg.common.ip_offset;
2823         void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
2824
2825         uint32_t dscp;
2826         uint16_t total_length;
2827
2828         if (cfg->common.ip_version) {
2829                 struct ipv4_hdr *hdr = ip;
2830
2831                 dscp = hdr->type_of_service >> 2;
2832                 total_length = rte_ntohs(hdr->total_length);
2833         } else {
2834                 struct ipv6_hdr *hdr = ip;
2835
2836                 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
2837                 total_length =
2838                         rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
2839         }
2840
2841         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2842                 void *data =
2843                         action_data_get(table_entry, action, RTE_TABLE_ACTION_LB);
2844
2845                 pkt_work_lb(mbuf,
2846                         data,
2847                         &cfg->lb);
2848         }
2849         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2850                 void *data =
2851                         action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
2852
2853                 drop_mask |= pkt_work_mtr(mbuf,
2854                         data,
2855                         &action->dscp_table,
2856                         action->mp,
2857                         time,
2858                         dscp,
2859                         total_length);
2860         }
2861
2862         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2863                 void *data =
2864                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
2865
2866                 pkt_work_tm(mbuf,
2867                         data,
2868                         &action->dscp_table,
2869                         dscp);
2870         }
2871
2872         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
2873                 void *data = action_data_get(table_entry,
2874                         action,
2875                         RTE_TABLE_ACTION_DECAP);
2876
2877                 pkt_work_decap(mbuf, data);
2878         }
2879
2880         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2881                 void *data =
2882                         action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
2883
2884                 pkt_work_encap(mbuf,
2885                         data,
2886                         &cfg->encap,
2887                         ip,
2888                         total_length,
2889                         ip_offset);
2890         }
2891
2892         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2893                 void *data =
2894                         action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
2895
2896                 if (cfg->common.ip_version)
2897                         pkt_ipv4_work_nat(ip, data, &cfg->nat);
2898                 else
2899                         pkt_ipv6_work_nat(ip, data, &cfg->nat);
2900         }
2901
2902         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2903                 void *data =
2904                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
2905
2906                 if (cfg->common.ip_version)
2907                         drop_mask |= pkt_ipv4_work_ttl(ip, data);
2908                 else
2909                         drop_mask |= pkt_ipv6_work_ttl(ip, data);
2910         }
2911
2912         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2913                 void *data =
2914                         action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
2915
2916                 pkt_work_stats(data, total_length);
2917         }
2918
2919         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2920                 void *data =
2921                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
2922
2923                 pkt_work_time(data, time);
2924         }
2925
2926         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
2927                 void *data = action_data_get(table_entry, action,
2928                                 RTE_TABLE_ACTION_SYM_CRYPTO);
2929
2930                 drop_mask |= pkt_work_sym_crypto(mbuf, data, &cfg->sym_crypto,
2931                                 ip_offset);
2932         }
2933
2934         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
2935                 void *data = action_data_get(table_entry,
2936                         action,
2937                         RTE_TABLE_ACTION_TAG);
2938
2939                 pkt_work_tag(mbuf, data);
2940         }
2941
2942         return drop_mask;
2943 }
2944
2945 static __rte_always_inline uint64_t
2946 pkt4_work(struct rte_mbuf **mbufs,
2947         struct rte_pipeline_table_entry **table_entries,
2948         uint64_t time,
2949         struct rte_table_action *action,
2950         struct ap_config *cfg)
2951 {
2952         uint64_t drop_mask0 = 0;
2953         uint64_t drop_mask1 = 0;
2954         uint64_t drop_mask2 = 0;
2955         uint64_t drop_mask3 = 0;
2956
2957         struct rte_mbuf *mbuf0 = mbufs[0];
2958         struct rte_mbuf *mbuf1 = mbufs[1];
2959         struct rte_mbuf *mbuf2 = mbufs[2];
2960         struct rte_mbuf *mbuf3 = mbufs[3];
2961
2962         struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
2963         struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
2964         struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
2965         struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
2966
2967         uint32_t ip_offset = action->cfg.common.ip_offset;
2968         void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
2969         void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
2970         void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
2971         void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
2972
2973         uint32_t dscp0, dscp1, dscp2, dscp3;
2974         uint16_t total_length0, total_length1, total_length2, total_length3;
2975
2976         if (cfg->common.ip_version) {
2977                 struct ipv4_hdr *hdr0 = ip0;
2978                 struct ipv4_hdr *hdr1 = ip1;
2979                 struct ipv4_hdr *hdr2 = ip2;
2980                 struct ipv4_hdr *hdr3 = ip3;
2981
2982                 dscp0 = hdr0->type_of_service >> 2;
2983                 dscp1 = hdr1->type_of_service >> 2;
2984                 dscp2 = hdr2->type_of_service >> 2;
2985                 dscp3 = hdr3->type_of_service >> 2;
2986
2987                 total_length0 = rte_ntohs(hdr0->total_length);
2988                 total_length1 = rte_ntohs(hdr1->total_length);
2989                 total_length2 = rte_ntohs(hdr2->total_length);
2990                 total_length3 = rte_ntohs(hdr3->total_length);
2991         } else {
2992                 struct ipv6_hdr *hdr0 = ip0;
2993                 struct ipv6_hdr *hdr1 = ip1;
2994                 struct ipv6_hdr *hdr2 = ip2;
2995                 struct ipv6_hdr *hdr3 = ip3;
2996
2997                 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
2998                 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
2999                 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
3000                 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
3001
3002                 total_length0 =
3003                         rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
3004                 total_length1 =
3005                         rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
3006                 total_length2 =
3007                         rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
3008                 total_length3 =
3009                         rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
3010         }
3011
3012         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
3013                 void *data0 =
3014                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_LB);
3015                 void *data1 =
3016                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_LB);
3017                 void *data2 =
3018                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_LB);
3019                 void *data3 =
3020                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_LB);
3021
3022                 pkt_work_lb(mbuf0,
3023                         data0,
3024                         &cfg->lb);
3025
3026                 pkt_work_lb(mbuf1,
3027                         data1,
3028                         &cfg->lb);
3029
3030                 pkt_work_lb(mbuf2,
3031                         data2,
3032                         &cfg->lb);
3033
3034                 pkt_work_lb(mbuf3,
3035                         data3,
3036                         &cfg->lb);
3037         }
3038
3039         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
3040                 void *data0 =
3041                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
3042                 void *data1 =
3043                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
3044                 void *data2 =
3045                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
3046                 void *data3 =
3047                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
3048
3049                 drop_mask0 |= pkt_work_mtr(mbuf0,
3050                         data0,
3051                         &action->dscp_table,
3052                         action->mp,
3053                         time,
3054                         dscp0,
3055                         total_length0);
3056
3057                 drop_mask1 |= pkt_work_mtr(mbuf1,
3058                         data1,
3059                         &action->dscp_table,
3060                         action->mp,
3061                         time,
3062                         dscp1,
3063                         total_length1);
3064
3065                 drop_mask2 |= pkt_work_mtr(mbuf2,
3066                         data2,
3067                         &action->dscp_table,
3068                         action->mp,
3069                         time,
3070                         dscp2,
3071                         total_length2);
3072
3073                 drop_mask3 |= pkt_work_mtr(mbuf3,
3074                         data3,
3075                         &action->dscp_table,
3076                         action->mp,
3077                         time,
3078                         dscp3,
3079                         total_length3);
3080         }
3081
3082         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
3083                 void *data0 =
3084                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
3085                 void *data1 =
3086                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
3087                 void *data2 =
3088                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
3089                 void *data3 =
3090                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
3091
3092                 pkt_work_tm(mbuf0,
3093                         data0,
3094                         &action->dscp_table,
3095                         dscp0);
3096
3097                 pkt_work_tm(mbuf1,
3098                         data1,
3099                         &action->dscp_table,
3100                         dscp1);
3101
3102                 pkt_work_tm(mbuf2,
3103                         data2,
3104                         &action->dscp_table,
3105                         dscp2);
3106
3107                 pkt_work_tm(mbuf3,
3108                         data3,
3109                         &action->dscp_table,
3110                         dscp3);
3111         }
3112
3113         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
3114                 void *data0 = action_data_get(table_entry0,
3115                         action,
3116                         RTE_TABLE_ACTION_DECAP);
3117                 void *data1 = action_data_get(table_entry1,
3118                         action,
3119                         RTE_TABLE_ACTION_DECAP);
3120                 void *data2 = action_data_get(table_entry2,
3121                         action,
3122                         RTE_TABLE_ACTION_DECAP);
3123                 void *data3 = action_data_get(table_entry3,
3124                         action,
3125                         RTE_TABLE_ACTION_DECAP);
3126
3127                 pkt4_work_decap(mbuf0, mbuf1, mbuf2, mbuf3,
3128                         data0, data1, data2, data3);
3129         }
3130
3131         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
3132                 void *data0 =
3133                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
3134                 void *data1 =
3135                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
3136                 void *data2 =
3137                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
3138                 void *data3 =
3139                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
3140
3141                 pkt_work_encap(mbuf0,
3142                         data0,
3143                         &cfg->encap,
3144                         ip0,
3145                         total_length0,
3146                         ip_offset);
3147
3148                 pkt_work_encap(mbuf1,
3149                         data1,
3150                         &cfg->encap,
3151                         ip1,
3152                         total_length1,
3153                         ip_offset);
3154
3155                 pkt_work_encap(mbuf2,
3156                         data2,
3157                         &cfg->encap,
3158                         ip2,
3159                         total_length2,
3160                         ip_offset);
3161
3162                 pkt_work_encap(mbuf3,
3163                         data3,
3164                         &cfg->encap,
3165                         ip3,
3166                         total_length3,
3167                         ip_offset);
3168         }
3169
3170         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
3171                 void *data0 =
3172                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
3173                 void *data1 =
3174                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
3175                 void *data2 =
3176                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
3177                 void *data3 =
3178                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
3179
3180                 if (cfg->common.ip_version) {
3181                         pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
3182                         pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
3183                         pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
3184                         pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
3185                 } else {
3186                         pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
3187                         pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
3188                         pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
3189                         pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
3190                 }
3191         }
3192
3193         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
3194                 void *data0 =
3195                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
3196                 void *data1 =
3197                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
3198                 void *data2 =
3199                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
3200                 void *data3 =
3201                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
3202
3203                 if (cfg->common.ip_version) {
3204                         drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
3205                         drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
3206                         drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
3207                         drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
3208                 } else {
3209                         drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
3210                         drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
3211                         drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
3212                         drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
3213                 }
3214         }
3215
3216         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
3217                 void *data0 =
3218                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
3219                 void *data1 =
3220                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
3221                 void *data2 =
3222                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
3223                 void *data3 =
3224                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
3225
3226                 pkt_work_stats(data0, total_length0);
3227                 pkt_work_stats(data1, total_length1);
3228                 pkt_work_stats(data2, total_length2);
3229                 pkt_work_stats(data3, total_length3);
3230         }
3231
3232         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
3233                 void *data0 =
3234                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
3235                 void *data1 =
3236                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
3237                 void *data2 =
3238                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
3239                 void *data3 =
3240                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
3241
3242                 pkt_work_time(data0, time);
3243                 pkt_work_time(data1, time);
3244                 pkt_work_time(data2, time);
3245                 pkt_work_time(data3, time);
3246         }
3247
3248         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
3249                 void *data0 = action_data_get(table_entry0, action,
3250                                 RTE_TABLE_ACTION_SYM_CRYPTO);
3251                 void *data1 = action_data_get(table_entry1, action,
3252                                 RTE_TABLE_ACTION_SYM_CRYPTO);
3253                 void *data2 = action_data_get(table_entry2, action,
3254                                 RTE_TABLE_ACTION_SYM_CRYPTO);
3255                 void *data3 = action_data_get(table_entry3, action,
3256                                 RTE_TABLE_ACTION_SYM_CRYPTO);
3257
3258                 drop_mask0 |= pkt_work_sym_crypto(mbuf0, data0, &cfg->sym_crypto,
3259                                 ip_offset);
3260                 drop_mask1 |= pkt_work_sym_crypto(mbuf1, data1, &cfg->sym_crypto,
3261                                 ip_offset);
3262                 drop_mask2 |= pkt_work_sym_crypto(mbuf2, data2, &cfg->sym_crypto,
3263                                 ip_offset);
3264                 drop_mask3 |= pkt_work_sym_crypto(mbuf3, data3, &cfg->sym_crypto,
3265                                 ip_offset);
3266         }
3267
3268         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
3269                 void *data0 = action_data_get(table_entry0,
3270                         action,
3271                         RTE_TABLE_ACTION_TAG);
3272                 void *data1 = action_data_get(table_entry1,
3273                         action,
3274                         RTE_TABLE_ACTION_TAG);
3275                 void *data2 = action_data_get(table_entry2,
3276                         action,
3277                         RTE_TABLE_ACTION_TAG);
3278                 void *data3 = action_data_get(table_entry3,
3279                         action,
3280                         RTE_TABLE_ACTION_TAG);
3281
3282                 pkt4_work_tag(mbuf0, mbuf1, mbuf2, mbuf3,
3283                         data0, data1, data2, data3);
3284         }
3285
3286         return drop_mask0 |
3287                 (drop_mask1 << 1) |
3288                 (drop_mask2 << 2) |
3289                 (drop_mask3 << 3);
3290 }
3291
3292 static __rte_always_inline int
3293 ah(struct rte_pipeline *p,
3294         struct rte_mbuf **pkts,
3295         uint64_t pkts_mask,
3296         struct rte_pipeline_table_entry **entries,
3297         struct rte_table_action *action,
3298         struct ap_config *cfg)
3299 {
3300         uint64_t pkts_drop_mask = 0;
3301         uint64_t time = 0;
3302
3303         if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
3304                 (1LLU << RTE_TABLE_ACTION_TIME)))
3305                 time = rte_rdtsc();
3306
3307         if ((pkts_mask & (pkts_mask + 1)) == 0) {
3308                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
3309                 uint32_t i;
3310
3311                 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
3312                         uint64_t drop_mask;
3313
3314                         drop_mask = pkt4_work(&pkts[i],
3315                                 &entries[i],
3316                                 time,
3317                                 action,
3318                                 cfg);
3319
3320                         pkts_drop_mask |= drop_mask << i;
3321                 }
3322
3323                 for ( ; i < n_pkts; i++) {
3324                         uint64_t drop_mask;
3325
3326                         drop_mask = pkt_work(pkts[i],
3327                                 entries[i],
3328                                 time,
3329                                 action,
3330                                 cfg);
3331
3332                         pkts_drop_mask |= drop_mask << i;
3333                 }
3334         } else
3335                 for ( ; pkts_mask; ) {
3336                         uint32_t pos = __builtin_ctzll(pkts_mask);
3337                         uint64_t pkt_mask = 1LLU << pos;
3338                         uint64_t drop_mask;
3339
3340                         drop_mask = pkt_work(pkts[pos],
3341                                 entries[pos],
3342                                 time,
3343                                 action,
3344                                 cfg);
3345
3346                         pkts_mask &= ~pkt_mask;
3347                         pkts_drop_mask |= drop_mask << pos;
3348                 }
3349
3350         rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
3351
3352         return 0;
3353 }
3354
3355 static int
3356 ah_default(struct rte_pipeline *p,
3357         struct rte_mbuf **pkts,
3358         uint64_t pkts_mask,
3359         struct rte_pipeline_table_entry **entries,
3360         void *arg)
3361 {
3362         struct rte_table_action *action = arg;
3363
3364         return ah(p,
3365                 pkts,
3366                 pkts_mask,
3367                 entries,
3368                 action,
3369                 &action->cfg);
3370 }
3371
3372 static rte_pipeline_table_action_handler_hit
3373 ah_selector(struct rte_table_action *action)
3374 {
3375         if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
3376                 return NULL;
3377
3378         return ah_default;
3379 }
3380
3381 int
3382 rte_table_action_table_params_get(struct rte_table_action *action,
3383         struct rte_pipeline_table_params *params)
3384 {
3385         rte_pipeline_table_action_handler_hit f_action_hit;
3386         uint32_t total_size;
3387
3388         /* Check input arguments */
3389         if ((action == NULL) ||
3390                 (params == NULL))
3391                 return -EINVAL;
3392
3393         f_action_hit = ah_selector(action);
3394         total_size = rte_align32pow2(action->data.total_size);
3395
3396         /* Fill in params */
3397         params->f_action_hit = f_action_hit;
3398         params->f_action_miss = NULL;
3399         params->arg_ah = (f_action_hit) ? action : NULL;
3400         params->action_data_size = total_size -
3401                 sizeof(struct rte_pipeline_table_entry);
3402
3403         return 0;
3404 }
3405
3406 int
3407 rte_table_action_free(struct rte_table_action *action)
3408 {
3409         if (action == NULL)
3410                 return 0;
3411
3412         rte_free(action);
3413
3414         return 0;
3415 }