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