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