pipeline: add VXLAN encap table action
[dpdk.git] / lib / librte_pipeline / rte_table_action.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <rte_common.h>
9 #include <rte_byteorder.h>
10 #include <rte_cycles.h>
11 #include <rte_malloc.h>
12 #include <rte_memcpy.h>
13 #include <rte_ether.h>
14 #include <rte_ip.h>
15 #include <rte_esp.h>
16 #include <rte_tcp.h>
17 #include <rte_udp.h>
18
19 #include "rte_table_action.h"
20
21 #define rte_htons rte_cpu_to_be_16
22 #define rte_htonl rte_cpu_to_be_32
23
24 #define rte_ntohs rte_be_to_cpu_16
25 #define rte_ntohl rte_be_to_cpu_32
26
27 /**
28  * RTE_TABLE_ACTION_FWD
29  */
30 #define fwd_data rte_pipeline_table_entry
31
32 static int
33 fwd_apply(struct fwd_data *data,
34         struct rte_table_action_fwd_params *p)
35 {
36         data->action = p->action;
37
38         if (p->action == RTE_PIPELINE_ACTION_PORT)
39                 data->port_id = p->id;
40
41         if (p->action == RTE_PIPELINE_ACTION_TABLE)
42                 data->table_id = p->id;
43
44         return 0;
45 }
46
47 /**
48  * RTE_TABLE_ACTION_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         case RTE_TABLE_ACTION_ENCAP_VXLAN:
434                 return 1;
435         default:
436                 return 0;
437         }
438 }
439
440 static int
441 encap_cfg_check(struct rte_table_action_encap_config *encap)
442 {
443         if ((encap->encap_mask == 0) ||
444                 (__builtin_popcountll(encap->encap_mask) != 1))
445                 return -ENOTSUP;
446
447         return 0;
448 }
449
450 struct encap_ether_data {
451         struct ether_hdr ether;
452 } __attribute__((__packed__));
453
454 #define VLAN(pcp, dei, vid)                                \
455         ((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
456         ((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
457         (((uint64_t)(vid)) & 0xFFFLLU))                    \
458
459 struct encap_vlan_data {
460         struct ether_hdr ether;
461         struct vlan_hdr vlan;
462 } __attribute__((__packed__));
463
464 struct encap_qinq_data {
465         struct ether_hdr ether;
466         struct vlan_hdr svlan;
467         struct vlan_hdr cvlan;
468 } __attribute__((__packed__));
469
470 #define ETHER_TYPE_MPLS_UNICAST                            0x8847
471
472 #define ETHER_TYPE_MPLS_MULTICAST                          0x8848
473
474 #define MPLS(label, tc, s, ttl)                            \
475         ((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
476         ((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
477         ((((uint64_t)(s)) & 0x1LLU) << 8) |                \
478         (((uint64_t)(ttl)) & 0xFFLLU)))
479
480 struct encap_mpls_data {
481         struct ether_hdr ether;
482         uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
483         uint32_t mpls_count;
484 } __attribute__((__packed__));
485
486 #define ETHER_TYPE_PPPOE_SESSION                           0x8864
487
488 #define PPP_PROTOCOL_IP                                    0x0021
489
490 struct pppoe_ppp_hdr {
491         uint16_t ver_type_code;
492         uint16_t session_id;
493         uint16_t length;
494         uint16_t protocol;
495 } __attribute__((__packed__));
496
497 struct encap_pppoe_data {
498         struct ether_hdr ether;
499         struct pppoe_ppp_hdr pppoe_ppp;
500 } __attribute__((__packed__));
501
502 #define IP_PROTO_UDP                                       17
503
504 struct encap_vxlan_ipv4_data {
505         struct ether_hdr ether;
506         struct ipv4_hdr ipv4;
507         struct udp_hdr udp;
508         struct vxlan_hdr vxlan;
509 } __attribute__((__packed__));
510
511 struct encap_vxlan_ipv4_vlan_data {
512         struct ether_hdr ether;
513         struct vlan_hdr vlan;
514         struct ipv4_hdr ipv4;
515         struct udp_hdr udp;
516         struct vxlan_hdr vxlan;
517 } __attribute__((__packed__));
518
519 struct encap_vxlan_ipv6_data {
520         struct ether_hdr ether;
521         struct ipv6_hdr ipv6;
522         struct udp_hdr udp;
523         struct vxlan_hdr vxlan;
524 } __attribute__((__packed__));
525
526 struct encap_vxlan_ipv6_vlan_data {
527         struct ether_hdr ether;
528         struct vlan_hdr vlan;
529         struct ipv6_hdr ipv6;
530         struct udp_hdr udp;
531         struct vxlan_hdr vxlan;
532 } __attribute__((__packed__));
533
534 static size_t
535 encap_data_size(struct rte_table_action_encap_config *encap)
536 {
537         switch (encap->encap_mask) {
538         case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
539                 return sizeof(struct encap_ether_data);
540
541         case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
542                 return sizeof(struct encap_vlan_data);
543
544         case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
545                 return sizeof(struct encap_qinq_data);
546
547         case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
548                 return sizeof(struct encap_mpls_data);
549
550         case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
551                 return sizeof(struct encap_pppoe_data);
552
553         case 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN:
554                 if (encap->vxlan.ip_version)
555                         if (encap->vxlan.vlan)
556                                 return sizeof(struct encap_vxlan_ipv4_vlan_data);
557                         else
558                                 return sizeof(struct encap_vxlan_ipv4_data);
559                 else
560                         if (encap->vxlan.vlan)
561                                 return sizeof(struct encap_vxlan_ipv6_vlan_data);
562                         else
563                                 return sizeof(struct encap_vxlan_ipv6_data);
564
565         default:
566                 return 0;
567         }
568 }
569
570 static int
571 encap_apply_check(struct rte_table_action_encap_params *p,
572         struct rte_table_action_encap_config *cfg)
573 {
574         if ((encap_valid(p->type) == 0) ||
575                 ((cfg->encap_mask & (1LLU << p->type)) == 0))
576                 return -EINVAL;
577
578         switch (p->type) {
579         case RTE_TABLE_ACTION_ENCAP_ETHER:
580                 return 0;
581
582         case RTE_TABLE_ACTION_ENCAP_VLAN:
583                 return 0;
584
585         case RTE_TABLE_ACTION_ENCAP_QINQ:
586                 return 0;
587
588         case RTE_TABLE_ACTION_ENCAP_MPLS:
589                 if ((p->mpls.mpls_count == 0) ||
590                         (p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
591                         return -EINVAL;
592
593                 return 0;
594
595         case RTE_TABLE_ACTION_ENCAP_PPPOE:
596                 return 0;
597
598         case RTE_TABLE_ACTION_ENCAP_VXLAN:
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                 ETHER_TYPE_IPv4 :
614                 ETHER_TYPE_IPv6;
615
616         /* Ethernet */
617         ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
618         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                 ETHER_TYPE_IPv4 :
632                 ETHER_TYPE_IPv6;
633
634         /* Ethernet */
635         ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
636         ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
637         d->ether.ether_type = rte_htons(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                 ETHER_TYPE_IPv4 :
656                 ETHER_TYPE_IPv6;
657
658         /* Ethernet */
659         ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
660         ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
661         d->ether.ether_type = rte_htons(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(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_mpls_apply(void *data,
680         struct rte_table_action_encap_params *p)
681 {
682         struct encap_mpls_data *d = data;
683         uint16_t ethertype = (p->mpls.unicast) ?
684                 ETHER_TYPE_MPLS_UNICAST :
685                 ETHER_TYPE_MPLS_MULTICAST;
686         uint32_t i;
687
688         /* Ethernet */
689         ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
690         ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
691         d->ether.ether_type = rte_htons(ethertype);
692
693         /* MPLS */
694         for (i = 0; i < p->mpls.mpls_count - 1; i++)
695                 d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
696                         p->mpls.mpls[i].tc,
697                         0,
698                         p->mpls.mpls[i].ttl));
699
700         d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
701                 p->mpls.mpls[i].tc,
702                 1,
703                 p->mpls.mpls[i].ttl));
704
705         d->mpls_count = p->mpls.mpls_count;
706         return 0;
707 }
708
709 static int
710 encap_pppoe_apply(void *data,
711         struct rte_table_action_encap_params *p)
712 {
713         struct encap_pppoe_data *d = data;
714
715         /* Ethernet */
716         ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
717         ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
718         d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
719
720         /* PPPoE and PPP*/
721         d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
722         d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
723         d->pppoe_ppp.length = 0; /* not pre-computed */
724         d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
725
726         return 0;
727 }
728
729 static int
730 encap_vxlan_apply(void *data,
731         struct rte_table_action_encap_params *p,
732         struct rte_table_action_encap_config *cfg)
733 {
734         if ((p->vxlan.vxlan.vni > 0xFFFFFF) ||
735                 (cfg->vxlan.ip_version && (p->vxlan.ipv4.dscp > 0x3F)) ||
736                 (!cfg->vxlan.ip_version && (p->vxlan.ipv6.flow_label > 0xFFFFF)) ||
737                 (!cfg->vxlan.ip_version && (p->vxlan.ipv6.dscp > 0x3F)) ||
738                 (cfg->vxlan.vlan && (p->vxlan.vlan.vid > 0xFFF)))
739                 return -1;
740
741         if (cfg->vxlan.ip_version)
742                 if (cfg->vxlan.vlan) {
743                         struct encap_vxlan_ipv4_vlan_data *d = data;
744
745                         /* Ethernet */
746                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
747                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
748                         d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
749
750                         /* VLAN */
751                         d->vlan.vlan_tci = rte_htons(VLAN(p->vxlan.vlan.pcp,
752                                 p->vxlan.vlan.dei,
753                                 p->vxlan.vlan.vid));
754                         d->vlan.eth_proto = rte_htons(ETHER_TYPE_IPv4);
755
756                         /* IPv4*/
757                         d->ipv4.version_ihl = 0x45;
758                         d->ipv4.type_of_service = p->vxlan.ipv4.dscp << 2;
759                         d->ipv4.total_length = 0; /* not pre-computed */
760                         d->ipv4.packet_id = 0;
761                         d->ipv4.fragment_offset = 0;
762                         d->ipv4.time_to_live = p->vxlan.ipv4.ttl;
763                         d->ipv4.next_proto_id = IP_PROTO_UDP;
764                         d->ipv4.hdr_checksum = 0;
765                         d->ipv4.src_addr = rte_htonl(p->vxlan.ipv4.sa);
766                         d->ipv4.dst_addr = rte_htonl(p->vxlan.ipv4.da);
767
768                         d->ipv4.hdr_checksum = rte_ipv4_cksum(&d->ipv4);
769
770                         /* UDP */
771                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
772                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
773                         d->udp.dgram_len = 0; /* not pre-computed */
774                         d->udp.dgram_cksum = 0;
775
776                         /* VXLAN */
777                         d->vxlan.vx_flags = rte_htonl(0x08000000);
778                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
779
780                         return 0;
781                 } else {
782                         struct encap_vxlan_ipv4_data *d = data;
783
784                         /* Ethernet */
785                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
786                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
787                         d->ether.ether_type = rte_htons(ETHER_TYPE_IPv4);
788
789                         /* IPv4*/
790                         d->ipv4.version_ihl = 0x45;
791                         d->ipv4.type_of_service = p->vxlan.ipv4.dscp << 2;
792                         d->ipv4.total_length = 0; /* not pre-computed */
793                         d->ipv4.packet_id = 0;
794                         d->ipv4.fragment_offset = 0;
795                         d->ipv4.time_to_live = p->vxlan.ipv4.ttl;
796                         d->ipv4.next_proto_id = IP_PROTO_UDP;
797                         d->ipv4.hdr_checksum = 0;
798                         d->ipv4.src_addr = rte_htonl(p->vxlan.ipv4.sa);
799                         d->ipv4.dst_addr = rte_htonl(p->vxlan.ipv4.da);
800
801                         d->ipv4.hdr_checksum = rte_ipv4_cksum(&d->ipv4);
802
803                         /* UDP */
804                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
805                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
806                         d->udp.dgram_len = 0; /* not pre-computed */
807                         d->udp.dgram_cksum = 0;
808
809                         /* VXLAN */
810                         d->vxlan.vx_flags = rte_htonl(0x08000000);
811                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
812
813                         return 0;
814                 }
815         else
816                 if (cfg->vxlan.vlan) {
817                         struct encap_vxlan_ipv6_vlan_data *d = data;
818
819                         /* Ethernet */
820                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
821                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
822                         d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
823
824                         /* VLAN */
825                         d->vlan.vlan_tci = rte_htons(VLAN(p->vxlan.vlan.pcp,
826                                 p->vxlan.vlan.dei,
827                                 p->vxlan.vlan.vid));
828                         d->vlan.eth_proto = rte_htons(ETHER_TYPE_IPv6);
829
830                         /* IPv6*/
831                         d->ipv6.vtc_flow = rte_htonl((6 << 28) |
832                                 (p->vxlan.ipv6.dscp << 22) |
833                                 p->vxlan.ipv6.flow_label);
834                         d->ipv6.payload_len = 0; /* not pre-computed */
835                         d->ipv6.proto = IP_PROTO_UDP;
836                         d->ipv6.hop_limits = p->vxlan.ipv6.hop_limit;
837                         memcpy(d->ipv6.src_addr,
838                                 p->vxlan.ipv6.sa,
839                                 sizeof(p->vxlan.ipv6.sa));
840                         memcpy(d->ipv6.dst_addr,
841                                 p->vxlan.ipv6.da,
842                                 sizeof(p->vxlan.ipv6.da));
843
844                         /* UDP */
845                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
846                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
847                         d->udp.dgram_len = 0; /* not pre-computed */
848                         d->udp.dgram_cksum = 0;
849
850                         /* VXLAN */
851                         d->vxlan.vx_flags = rte_htonl(0x08000000);
852                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
853
854                         return 0;
855                 } else {
856                         struct encap_vxlan_ipv6_data *d = data;
857
858                         /* Ethernet */
859                         ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
860                         ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
861                         d->ether.ether_type = rte_htons(ETHER_TYPE_IPv6);
862
863                         /* IPv6*/
864                         d->ipv6.vtc_flow = rte_htonl((6 << 28) |
865                                 (p->vxlan.ipv6.dscp << 22) |
866                                 p->vxlan.ipv6.flow_label);
867                         d->ipv6.payload_len = 0; /* not pre-computed */
868                         d->ipv6.proto = IP_PROTO_UDP;
869                         d->ipv6.hop_limits = p->vxlan.ipv6.hop_limit;
870                         memcpy(d->ipv6.src_addr,
871                                 p->vxlan.ipv6.sa,
872                                 sizeof(p->vxlan.ipv6.sa));
873                         memcpy(d->ipv6.dst_addr,
874                                 p->vxlan.ipv6.da,
875                                 sizeof(p->vxlan.ipv6.da));
876
877                         /* UDP */
878                         d->udp.src_port = rte_htons(p->vxlan.udp.sp);
879                         d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
880                         d->udp.dgram_len = 0; /* not pre-computed */
881                         d->udp.dgram_cksum = 0;
882
883                         /* VXLAN */
884                         d->vxlan.vx_flags = rte_htonl(0x08000000);
885                         d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
886
887                         return 0;
888                 }
889 }
890
891 static int
892 encap_apply(void *data,
893         struct rte_table_action_encap_params *p,
894         struct rte_table_action_encap_config *cfg,
895         struct rte_table_action_common_config *common_cfg)
896 {
897         int status;
898
899         /* Check input arguments */
900         status = encap_apply_check(p, cfg);
901         if (status)
902                 return status;
903
904         switch (p->type) {
905         case RTE_TABLE_ACTION_ENCAP_ETHER:
906                 return encap_ether_apply(data, p, common_cfg);
907
908         case RTE_TABLE_ACTION_ENCAP_VLAN:
909                 return encap_vlan_apply(data, p, common_cfg);
910
911         case RTE_TABLE_ACTION_ENCAP_QINQ:
912                 return encap_qinq_apply(data, p, common_cfg);
913
914         case RTE_TABLE_ACTION_ENCAP_MPLS:
915                 return encap_mpls_apply(data, p);
916
917         case RTE_TABLE_ACTION_ENCAP_PPPOE:
918                 return encap_pppoe_apply(data, p);
919
920         case RTE_TABLE_ACTION_ENCAP_VXLAN:
921                 return encap_vxlan_apply(data, p, cfg);
922
923         default:
924                 return -EINVAL;
925         }
926 }
927
928 static __rte_always_inline uint16_t
929 encap_vxlan_ipv4_checksum_update(uint16_t cksum0,
930         uint16_t total_length)
931 {
932         int32_t cksum1;
933
934         cksum1 = cksum0;
935         cksum1 = ~cksum1 & 0xFFFF;
936
937         /* Add total length (one's complement logic) */
938         cksum1 += total_length;
939         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
940         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
941
942         return (uint16_t)(~cksum1);
943 }
944
945 static __rte_always_inline void *
946 encap(void *dst, const void *src, size_t n)
947 {
948         dst = ((uint8_t *) dst) - n;
949         return rte_memcpy(dst, src, n);
950 }
951
952 static __rte_always_inline void
953 pkt_work_encap_vxlan_ipv4(struct rte_mbuf *mbuf,
954         struct encap_vxlan_ipv4_data *vxlan_tbl,
955         struct rte_table_action_encap_config *cfg)
956 {
957         uint32_t ether_offset = cfg->vxlan.data_offset;
958         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
959         struct encap_vxlan_ipv4_data *vxlan_pkt;
960         uint16_t ether_length, ipv4_total_length, ipv4_hdr_cksum, udp_length;
961
962         ether_length = (uint16_t)mbuf->pkt_len;
963         ipv4_total_length = ether_length +
964                 (sizeof(struct vxlan_hdr) +
965                 sizeof(struct udp_hdr) +
966                 sizeof(struct ipv4_hdr));
967         ipv4_hdr_cksum = encap_vxlan_ipv4_checksum_update(vxlan_tbl->ipv4.hdr_checksum,
968                 rte_htons(ipv4_total_length));
969         udp_length = ether_length +
970                 (sizeof(struct vxlan_hdr) +
971                 sizeof(struct udp_hdr));
972
973         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
974         vxlan_pkt->ipv4.total_length = rte_htons(ipv4_total_length);
975         vxlan_pkt->ipv4.hdr_checksum = ipv4_hdr_cksum;
976         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
977
978         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
979         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
980 }
981
982 static __rte_always_inline void
983 pkt_work_encap_vxlan_ipv4_vlan(struct rte_mbuf *mbuf,
984         struct encap_vxlan_ipv4_vlan_data *vxlan_tbl,
985         struct rte_table_action_encap_config *cfg)
986 {
987         uint32_t ether_offset = cfg->vxlan.data_offset;
988         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
989         struct encap_vxlan_ipv4_vlan_data *vxlan_pkt;
990         uint16_t ether_length, ipv4_total_length, ipv4_hdr_cksum, udp_length;
991
992         ether_length = (uint16_t)mbuf->pkt_len;
993         ipv4_total_length = ether_length +
994                 (sizeof(struct vxlan_hdr) +
995                 sizeof(struct udp_hdr) +
996                 sizeof(struct ipv4_hdr));
997         ipv4_hdr_cksum = encap_vxlan_ipv4_checksum_update(vxlan_tbl->ipv4.hdr_checksum,
998                 rte_htons(ipv4_total_length));
999         udp_length = ether_length +
1000                 (sizeof(struct vxlan_hdr) +
1001                 sizeof(struct udp_hdr));
1002
1003         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
1004         vxlan_pkt->ipv4.total_length = rte_htons(ipv4_total_length);
1005         vxlan_pkt->ipv4.hdr_checksum = ipv4_hdr_cksum;
1006         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
1007
1008         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
1009         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
1010 }
1011
1012 static __rte_always_inline void
1013 pkt_work_encap_vxlan_ipv6(struct rte_mbuf *mbuf,
1014         struct encap_vxlan_ipv6_data *vxlan_tbl,
1015         struct rte_table_action_encap_config *cfg)
1016 {
1017         uint32_t ether_offset = cfg->vxlan.data_offset;
1018         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
1019         struct encap_vxlan_ipv6_data *vxlan_pkt;
1020         uint16_t ether_length, ipv6_payload_length, udp_length;
1021
1022         ether_length = (uint16_t)mbuf->pkt_len;
1023         ipv6_payload_length = ether_length +
1024                 (sizeof(struct vxlan_hdr) +
1025                 sizeof(struct udp_hdr));
1026         udp_length = ether_length +
1027                 (sizeof(struct vxlan_hdr) +
1028                 sizeof(struct udp_hdr));
1029
1030         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
1031         vxlan_pkt->ipv6.payload_len = rte_htons(ipv6_payload_length);
1032         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
1033
1034         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
1035         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
1036 }
1037
1038 static __rte_always_inline void
1039 pkt_work_encap_vxlan_ipv6_vlan(struct rte_mbuf *mbuf,
1040         struct encap_vxlan_ipv6_vlan_data *vxlan_tbl,
1041         struct rte_table_action_encap_config *cfg)
1042 {
1043         uint32_t ether_offset = cfg->vxlan.data_offset;
1044         void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
1045         struct encap_vxlan_ipv6_vlan_data *vxlan_pkt;
1046         uint16_t ether_length, ipv6_payload_length, udp_length;
1047
1048         ether_length = (uint16_t)mbuf->pkt_len;
1049         ipv6_payload_length = ether_length +
1050                 (sizeof(struct vxlan_hdr) +
1051                 sizeof(struct udp_hdr));
1052         udp_length = ether_length +
1053                 (sizeof(struct vxlan_hdr) +
1054                 sizeof(struct udp_hdr));
1055
1056         vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
1057         vxlan_pkt->ipv6.payload_len = rte_htons(ipv6_payload_length);
1058         vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
1059
1060         mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
1061         mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
1062 }
1063
1064 static __rte_always_inline void
1065 pkt_work_encap(struct rte_mbuf *mbuf,
1066         void *data,
1067         struct rte_table_action_encap_config *cfg,
1068         void *ip,
1069         uint16_t total_length,
1070         uint32_t ip_offset)
1071 {
1072         switch (cfg->encap_mask) {
1073         case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
1074                 encap(ip, data, sizeof(struct encap_ether_data));
1075                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1076                         sizeof(struct encap_ether_data));
1077                 mbuf->pkt_len = mbuf->data_len = total_length +
1078                         sizeof(struct encap_ether_data);
1079                 break;
1080
1081         case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
1082                 encap(ip, data, sizeof(struct encap_vlan_data));
1083                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1084                         sizeof(struct encap_vlan_data));
1085                 mbuf->pkt_len = mbuf->data_len = total_length +
1086                         sizeof(struct encap_vlan_data);
1087                 break;
1088
1089         case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
1090                 encap(ip, data, sizeof(struct encap_qinq_data));
1091                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1092                         sizeof(struct encap_qinq_data));
1093                 mbuf->pkt_len = mbuf->data_len = total_length +
1094                         sizeof(struct encap_qinq_data);
1095                 break;
1096
1097         case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
1098         {
1099                 struct encap_mpls_data *mpls = data;
1100                 size_t size = sizeof(struct ether_hdr) +
1101                         mpls->mpls_count * 4;
1102
1103                 encap(ip, data, size);
1104                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
1105                 mbuf->pkt_len = mbuf->data_len = total_length + size;
1106                 break;
1107         }
1108
1109         case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
1110         {
1111                 struct encap_pppoe_data *pppoe =
1112                         encap(ip, data, sizeof(struct encap_pppoe_data));
1113                 pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
1114                 mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
1115                         sizeof(struct encap_pppoe_data));
1116                 mbuf->pkt_len = mbuf->data_len = total_length +
1117                         sizeof(struct encap_pppoe_data);
1118                 break;
1119         }
1120
1121         case 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN:
1122         {
1123                 if (cfg->vxlan.ip_version)
1124                         if (cfg->vxlan.vlan)
1125                                 pkt_work_encap_vxlan_ipv4_vlan(mbuf, data, cfg);
1126                         else
1127                                 pkt_work_encap_vxlan_ipv4(mbuf, data, cfg);
1128                 else
1129                         if (cfg->vxlan.vlan)
1130                                 pkt_work_encap_vxlan_ipv6_vlan(mbuf, data, cfg);
1131                         else
1132                                 pkt_work_encap_vxlan_ipv6(mbuf, data, cfg);
1133         }
1134
1135         default:
1136                 break;
1137         }
1138 }
1139
1140 /**
1141  * RTE_TABLE_ACTION_NAT
1142  */
1143 static int
1144 nat_cfg_check(struct rte_table_action_nat_config *nat)
1145 {
1146         if ((nat->proto != 0x06) &&
1147                 (nat->proto != 0x11))
1148                 return -ENOTSUP;
1149
1150         return 0;
1151 }
1152
1153 struct nat_ipv4_data {
1154         uint32_t addr;
1155         uint16_t port;
1156 } __attribute__((__packed__));
1157
1158 struct nat_ipv6_data {
1159         uint8_t addr[16];
1160         uint16_t port;
1161 } __attribute__((__packed__));
1162
1163 static size_t
1164 nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
1165         struct rte_table_action_common_config *common)
1166 {
1167         int ip_version = common->ip_version;
1168
1169         return (ip_version) ?
1170                 sizeof(struct nat_ipv4_data) :
1171                 sizeof(struct nat_ipv6_data);
1172 }
1173
1174 static int
1175 nat_apply_check(struct rte_table_action_nat_params *p,
1176         struct rte_table_action_common_config *cfg)
1177 {
1178         if ((p->ip_version && (cfg->ip_version == 0)) ||
1179                 ((p->ip_version == 0) && cfg->ip_version))
1180                 return -EINVAL;
1181
1182         return 0;
1183 }
1184
1185 static int
1186 nat_apply(void *data,
1187         struct rte_table_action_nat_params *p,
1188         struct rte_table_action_common_config *cfg)
1189 {
1190         int status;
1191
1192         /* Check input arguments */
1193         status = nat_apply_check(p, cfg);
1194         if (status)
1195                 return status;
1196
1197         /* Apply */
1198         if (p->ip_version) {
1199                 struct nat_ipv4_data *d = data;
1200
1201                 d->addr = rte_htonl(p->addr.ipv4);
1202                 d->port = rte_htons(p->port);
1203         } else {
1204                 struct nat_ipv6_data *d = data;
1205
1206                 memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
1207                 d->port = rte_htons(p->port);
1208         }
1209
1210         return 0;
1211 }
1212
1213 static __rte_always_inline uint16_t
1214 nat_ipv4_checksum_update(uint16_t cksum0,
1215         uint32_t ip0,
1216         uint32_t ip1)
1217 {
1218         int32_t cksum1;
1219
1220         cksum1 = cksum0;
1221         cksum1 = ~cksum1 & 0xFFFF;
1222
1223         /* Subtract ip0 (one's complement logic) */
1224         cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF);
1225         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1226         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1227
1228         /* Add ip1 (one's complement logic) */
1229         cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF);
1230         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1231         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1232
1233         return (uint16_t)(~cksum1);
1234 }
1235
1236 static __rte_always_inline uint16_t
1237 nat_ipv4_tcp_udp_checksum_update(uint16_t cksum0,
1238         uint32_t ip0,
1239         uint32_t ip1,
1240         uint16_t port0,
1241         uint16_t port1)
1242 {
1243         int32_t cksum1;
1244
1245         cksum1 = cksum0;
1246         cksum1 = ~cksum1 & 0xFFFF;
1247
1248         /* Subtract ip0 and port 0 (one's complement logic) */
1249         cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF) + port0;
1250         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1251         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1252
1253         /* Add ip1 and port1 (one's complement logic) */
1254         cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF) + port1;
1255         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1256         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1257
1258         return (uint16_t)(~cksum1);
1259 }
1260
1261 static __rte_always_inline uint16_t
1262 nat_ipv6_tcp_udp_checksum_update(uint16_t cksum0,
1263         uint16_t *ip0,
1264         uint16_t *ip1,
1265         uint16_t port0,
1266         uint16_t port1)
1267 {
1268         int32_t cksum1;
1269
1270         cksum1 = cksum0;
1271         cksum1 = ~cksum1 & 0xFFFF;
1272
1273         /* Subtract ip0 and port 0 (one's complement logic) */
1274         cksum1 -= ip0[0] + ip0[1] + ip0[2] + ip0[3] +
1275                 ip0[4] + ip0[5] + ip0[6] + ip0[7] + port0;
1276         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1277         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1278
1279         /* Add ip1 and port1 (one's complement logic) */
1280         cksum1 += ip1[0] + ip1[1] + ip1[2] + ip1[3] +
1281                 ip1[4] + ip1[5] + ip1[6] + ip1[7] + port1;
1282         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1283         cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
1284
1285         return (uint16_t)(~cksum1);
1286 }
1287
1288 static __rte_always_inline void
1289 pkt_ipv4_work_nat(struct ipv4_hdr *ip,
1290         struct nat_ipv4_data *data,
1291         struct rte_table_action_nat_config *cfg)
1292 {
1293         if (cfg->source_nat) {
1294                 if (cfg->proto == 0x6) {
1295                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1296                         uint16_t ip_cksum, tcp_cksum;
1297
1298                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1299                                 ip->src_addr,
1300                                 data->addr);
1301
1302                         tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
1303                                 ip->src_addr,
1304                                 data->addr,
1305                                 tcp->src_port,
1306                                 data->port);
1307
1308                         ip->src_addr = data->addr;
1309                         ip->hdr_checksum = ip_cksum;
1310                         tcp->src_port = data->port;
1311                         tcp->cksum = tcp_cksum;
1312                 } else {
1313                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1314                         uint16_t ip_cksum, udp_cksum;
1315
1316                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1317                                 ip->src_addr,
1318                                 data->addr);
1319
1320                         udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
1321                                 ip->src_addr,
1322                                 data->addr,
1323                                 udp->src_port,
1324                                 data->port);
1325
1326                         ip->src_addr = data->addr;
1327                         ip->hdr_checksum = ip_cksum;
1328                         udp->src_port = data->port;
1329                         if (udp->dgram_cksum)
1330                                 udp->dgram_cksum = udp_cksum;
1331                 }
1332         } else {
1333                 if (cfg->proto == 0x6) {
1334                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1335                         uint16_t ip_cksum, tcp_cksum;
1336
1337                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1338                                 ip->dst_addr,
1339                                 data->addr);
1340
1341                         tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
1342                                 ip->dst_addr,
1343                                 data->addr,
1344                                 tcp->dst_port,
1345                                 data->port);
1346
1347                         ip->dst_addr = data->addr;
1348                         ip->hdr_checksum = ip_cksum;
1349                         tcp->dst_port = data->port;
1350                         tcp->cksum = tcp_cksum;
1351                 } else {
1352                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1353                         uint16_t ip_cksum, udp_cksum;
1354
1355                         ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
1356                                 ip->dst_addr,
1357                                 data->addr);
1358
1359                         udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
1360                                 ip->dst_addr,
1361                                 data->addr,
1362                                 udp->dst_port,
1363                                 data->port);
1364
1365                         ip->dst_addr = data->addr;
1366                         ip->hdr_checksum = ip_cksum;
1367                         udp->dst_port = data->port;
1368                         if (udp->dgram_cksum)
1369                                 udp->dgram_cksum = udp_cksum;
1370                 }
1371         }
1372 }
1373
1374 static __rte_always_inline void
1375 pkt_ipv6_work_nat(struct ipv6_hdr *ip,
1376         struct nat_ipv6_data *data,
1377         struct rte_table_action_nat_config *cfg)
1378 {
1379         if (cfg->source_nat) {
1380                 if (cfg->proto == 0x6) {
1381                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1382                         uint16_t tcp_cksum;
1383
1384                         tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
1385                                 (uint16_t *)ip->src_addr,
1386                                 (uint16_t *)data->addr,
1387                                 tcp->src_port,
1388                                 data->port);
1389
1390                         rte_memcpy(ip->src_addr, data->addr, 16);
1391                         tcp->src_port = data->port;
1392                         tcp->cksum = tcp_cksum;
1393                 } else {
1394                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1395                         uint16_t udp_cksum;
1396
1397                         udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
1398                                 (uint16_t *)ip->src_addr,
1399                                 (uint16_t *)data->addr,
1400                                 udp->src_port,
1401                                 data->port);
1402
1403                         rte_memcpy(ip->src_addr, data->addr, 16);
1404                         udp->src_port = data->port;
1405                         udp->dgram_cksum = udp_cksum;
1406                 }
1407         } else {
1408                 if (cfg->proto == 0x6) {
1409                         struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
1410                         uint16_t tcp_cksum;
1411
1412                         tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
1413                                 (uint16_t *)ip->dst_addr,
1414                                 (uint16_t *)data->addr,
1415                                 tcp->dst_port,
1416                                 data->port);
1417
1418                         rte_memcpy(ip->dst_addr, data->addr, 16);
1419                         tcp->dst_port = data->port;
1420                         tcp->cksum = tcp_cksum;
1421                 } else {
1422                         struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
1423                         uint16_t udp_cksum;
1424
1425                         udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
1426                                 (uint16_t *)ip->dst_addr,
1427                                 (uint16_t *)data->addr,
1428                                 udp->dst_port,
1429                                 data->port);
1430
1431                         rte_memcpy(ip->dst_addr, data->addr, 16);
1432                         udp->dst_port = data->port;
1433                         udp->dgram_cksum = udp_cksum;
1434                 }
1435         }
1436 }
1437
1438 /**
1439  * RTE_TABLE_ACTION_TTL
1440  */
1441 static int
1442 ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
1443 {
1444         if (ttl->drop == 0)
1445                 return -ENOTSUP;
1446
1447         return 0;
1448 }
1449
1450 struct ttl_data {
1451         uint32_t n_packets;
1452 } __attribute__((__packed__));
1453
1454 #define TTL_INIT(data, decrement)                         \
1455         ((data)->n_packets = (decrement) ? 1 : 0)
1456
1457 #define TTL_DEC_GET(data)                                  \
1458         ((uint8_t)((data)->n_packets & 1))
1459
1460 #define TTL_STATS_RESET(data)                             \
1461         ((data)->n_packets = ((data)->n_packets & 1))
1462
1463 #define TTL_STATS_READ(data)                               \
1464         ((data)->n_packets >> 1)
1465
1466 #define TTL_STATS_ADD(data, value)                        \
1467         ((data)->n_packets =                                  \
1468                 (((((data)->n_packets >> 1) + (value)) << 1) |    \
1469                 ((data)->n_packets & 1)))
1470
1471 static int
1472 ttl_apply(void *data,
1473         struct rte_table_action_ttl_params *p)
1474 {
1475         struct ttl_data *d = data;
1476
1477         TTL_INIT(d, p->decrement);
1478
1479         return 0;
1480 }
1481
1482 static __rte_always_inline uint64_t
1483 pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
1484         struct ttl_data *data)
1485 {
1486         uint32_t drop;
1487         uint16_t cksum = ip->hdr_checksum;
1488         uint8_t ttl = ip->time_to_live;
1489         uint8_t ttl_diff = TTL_DEC_GET(data);
1490
1491         cksum += ttl_diff;
1492         ttl -= ttl_diff;
1493
1494         ip->hdr_checksum = cksum;
1495         ip->time_to_live = ttl;
1496
1497         drop = (ttl == 0) ? 1 : 0;
1498         TTL_STATS_ADD(data, drop);
1499
1500         return drop;
1501 }
1502
1503 static __rte_always_inline uint64_t
1504 pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
1505         struct ttl_data *data)
1506 {
1507         uint32_t drop;
1508         uint8_t ttl = ip->hop_limits;
1509         uint8_t ttl_diff = TTL_DEC_GET(data);
1510
1511         ttl -= ttl_diff;
1512
1513         ip->hop_limits = ttl;
1514
1515         drop = (ttl == 0) ? 1 : 0;
1516         TTL_STATS_ADD(data, drop);
1517
1518         return drop;
1519 }
1520
1521 /**
1522  * RTE_TABLE_ACTION_STATS
1523  */
1524 static int
1525 stats_cfg_check(struct rte_table_action_stats_config *stats)
1526 {
1527         if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
1528                 return -EINVAL;
1529
1530         return 0;
1531 }
1532
1533 struct stats_data {
1534         uint64_t n_packets;
1535         uint64_t n_bytes;
1536 } __attribute__((__packed__));
1537
1538 static int
1539 stats_apply(struct stats_data *data,
1540         struct rte_table_action_stats_params *p)
1541 {
1542         data->n_packets = p->n_packets;
1543         data->n_bytes = p->n_bytes;
1544
1545         return 0;
1546 }
1547
1548 static __rte_always_inline void
1549 pkt_work_stats(struct stats_data *data,
1550         uint16_t total_length)
1551 {
1552         data->n_packets++;
1553         data->n_bytes += total_length;
1554 }
1555
1556 /**
1557  * RTE_TABLE_ACTION_TIME
1558  */
1559 struct time_data {
1560         uint64_t time;
1561 } __attribute__((__packed__));
1562
1563 static int
1564 time_apply(struct time_data *data,
1565         struct rte_table_action_time_params *p)
1566 {
1567         data->time = p->time;
1568         return 0;
1569 }
1570
1571 static __rte_always_inline void
1572 pkt_work_time(struct time_data *data,
1573         uint64_t time)
1574 {
1575         data->time = time;
1576 }
1577
1578 /**
1579  * Action profile
1580  */
1581 static int
1582 action_valid(enum rte_table_action_type action)
1583 {
1584         switch (action) {
1585         case RTE_TABLE_ACTION_FWD:
1586         case RTE_TABLE_ACTION_LB:
1587         case RTE_TABLE_ACTION_MTR:
1588         case RTE_TABLE_ACTION_TM:
1589         case RTE_TABLE_ACTION_ENCAP:
1590         case RTE_TABLE_ACTION_NAT:
1591         case RTE_TABLE_ACTION_TTL:
1592         case RTE_TABLE_ACTION_STATS:
1593         case RTE_TABLE_ACTION_TIME:
1594                 return 1;
1595         default:
1596                 return 0;
1597         }
1598 }
1599
1600
1601 #define RTE_TABLE_ACTION_MAX                      64
1602
1603 struct ap_config {
1604         uint64_t action_mask;
1605         struct rte_table_action_common_config common;
1606         struct rte_table_action_lb_config lb;
1607         struct rte_table_action_mtr_config mtr;
1608         struct rte_table_action_tm_config tm;
1609         struct rte_table_action_encap_config encap;
1610         struct rte_table_action_nat_config nat;
1611         struct rte_table_action_ttl_config ttl;
1612         struct rte_table_action_stats_config stats;
1613 };
1614
1615 static size_t
1616 action_cfg_size(enum rte_table_action_type action)
1617 {
1618         switch (action) {
1619         case RTE_TABLE_ACTION_LB:
1620                 return sizeof(struct rte_table_action_lb_config);
1621         case RTE_TABLE_ACTION_MTR:
1622                 return sizeof(struct rte_table_action_mtr_config);
1623         case RTE_TABLE_ACTION_TM:
1624                 return sizeof(struct rte_table_action_tm_config);
1625         case RTE_TABLE_ACTION_ENCAP:
1626                 return sizeof(struct rte_table_action_encap_config);
1627         case RTE_TABLE_ACTION_NAT:
1628                 return sizeof(struct rte_table_action_nat_config);
1629         case RTE_TABLE_ACTION_TTL:
1630                 return sizeof(struct rte_table_action_ttl_config);
1631         case RTE_TABLE_ACTION_STATS:
1632                 return sizeof(struct rte_table_action_stats_config);
1633         default:
1634                 return 0;
1635         }
1636 }
1637
1638 static void*
1639 action_cfg_get(struct ap_config *ap_config,
1640         enum rte_table_action_type type)
1641 {
1642         switch (type) {
1643         case RTE_TABLE_ACTION_LB:
1644                 return &ap_config->lb;
1645
1646         case RTE_TABLE_ACTION_MTR:
1647                 return &ap_config->mtr;
1648
1649         case RTE_TABLE_ACTION_TM:
1650                 return &ap_config->tm;
1651
1652         case RTE_TABLE_ACTION_ENCAP:
1653                 return &ap_config->encap;
1654
1655         case RTE_TABLE_ACTION_NAT:
1656                 return &ap_config->nat;
1657
1658         case RTE_TABLE_ACTION_TTL:
1659                 return &ap_config->ttl;
1660
1661         case RTE_TABLE_ACTION_STATS:
1662                 return &ap_config->stats;
1663
1664         default:
1665                 return NULL;
1666         }
1667 }
1668
1669 static void
1670 action_cfg_set(struct ap_config *ap_config,
1671         enum rte_table_action_type type,
1672         void *action_cfg)
1673 {
1674         void *dst = action_cfg_get(ap_config, type);
1675
1676         if (dst)
1677                 memcpy(dst, action_cfg, action_cfg_size(type));
1678
1679         ap_config->action_mask |= 1LLU << type;
1680 }
1681
1682 struct ap_data {
1683         size_t offset[RTE_TABLE_ACTION_MAX];
1684         size_t total_size;
1685 };
1686
1687 static size_t
1688 action_data_size(enum rte_table_action_type action,
1689         struct ap_config *ap_config)
1690 {
1691         switch (action) {
1692         case RTE_TABLE_ACTION_FWD:
1693                 return sizeof(struct fwd_data);
1694
1695         case RTE_TABLE_ACTION_LB:
1696                 return sizeof(struct lb_data);
1697
1698         case RTE_TABLE_ACTION_MTR:
1699                 return mtr_data_size(&ap_config->mtr);
1700
1701         case RTE_TABLE_ACTION_TM:
1702                 return sizeof(struct tm_data);
1703
1704         case RTE_TABLE_ACTION_ENCAP:
1705                 return encap_data_size(&ap_config->encap);
1706
1707         case RTE_TABLE_ACTION_NAT:
1708                 return nat_data_size(&ap_config->nat,
1709                         &ap_config->common);
1710
1711         case RTE_TABLE_ACTION_TTL:
1712                 return sizeof(struct ttl_data);
1713
1714         case RTE_TABLE_ACTION_STATS:
1715                 return sizeof(struct stats_data);
1716
1717         case RTE_TABLE_ACTION_TIME:
1718                 return sizeof(struct time_data);
1719
1720         default:
1721                 return 0;
1722         }
1723 }
1724
1725
1726 static void
1727 action_data_offset_set(struct ap_data *ap_data,
1728         struct ap_config *ap_config)
1729 {
1730         uint64_t action_mask = ap_config->action_mask;
1731         size_t offset;
1732         uint32_t action;
1733
1734         memset(ap_data->offset, 0, sizeof(ap_data->offset));
1735
1736         offset = 0;
1737         for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
1738                 if (action_mask & (1LLU << action)) {
1739                         ap_data->offset[action] = offset;
1740                         offset += action_data_size((enum rte_table_action_type)action,
1741                                 ap_config);
1742                 }
1743
1744         ap_data->total_size = offset;
1745 }
1746
1747 struct rte_table_action_profile {
1748         struct ap_config cfg;
1749         struct ap_data data;
1750         int frozen;
1751 };
1752
1753 struct rte_table_action_profile *
1754 rte_table_action_profile_create(struct rte_table_action_common_config *common)
1755 {
1756         struct rte_table_action_profile *ap;
1757
1758         /* Check input arguments */
1759         if (common == NULL)
1760                 return NULL;
1761
1762         /* Memory allocation */
1763         ap = calloc(1, sizeof(struct rte_table_action_profile));
1764         if (ap == NULL)
1765                 return NULL;
1766
1767         /* Initialization */
1768         memcpy(&ap->cfg.common, common, sizeof(*common));
1769
1770         return ap;
1771 }
1772
1773
1774 int
1775 rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
1776         enum rte_table_action_type type,
1777         void *action_config)
1778 {
1779         int status;
1780
1781         /* Check input arguments */
1782         if ((profile == NULL) ||
1783                 profile->frozen ||
1784                 (action_valid(type) == 0) ||
1785                 (profile->cfg.action_mask & (1LLU << type)) ||
1786                 ((action_cfg_size(type) == 0) && action_config) ||
1787                 (action_cfg_size(type) && (action_config == NULL)))
1788                 return -EINVAL;
1789
1790         switch (type) {
1791         case RTE_TABLE_ACTION_LB:
1792                 status = lb_cfg_check(action_config);
1793                 break;
1794
1795         case RTE_TABLE_ACTION_MTR:
1796                 status = mtr_cfg_check(action_config);
1797                 break;
1798
1799         case RTE_TABLE_ACTION_TM:
1800                 status = tm_cfg_check(action_config);
1801                 break;
1802
1803         case RTE_TABLE_ACTION_ENCAP:
1804                 status = encap_cfg_check(action_config);
1805                 break;
1806
1807         case RTE_TABLE_ACTION_NAT:
1808                 status = nat_cfg_check(action_config);
1809                 break;
1810
1811         case RTE_TABLE_ACTION_TTL:
1812                 status = ttl_cfg_check(action_config);
1813                 break;
1814
1815         case RTE_TABLE_ACTION_STATS:
1816                 status = stats_cfg_check(action_config);
1817                 break;
1818
1819         default:
1820                 status = 0;
1821                 break;
1822         }
1823
1824         if (status)
1825                 return status;
1826
1827         /* Action enable */
1828         action_cfg_set(&profile->cfg, type, action_config);
1829
1830         return 0;
1831 }
1832
1833 int
1834 rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
1835 {
1836         if (profile->frozen)
1837                 return -EBUSY;
1838
1839         profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1840         action_data_offset_set(&profile->data, &profile->cfg);
1841         profile->frozen = 1;
1842
1843         return 0;
1844 }
1845
1846 int
1847 rte_table_action_profile_free(struct rte_table_action_profile *profile)
1848 {
1849         if (profile == NULL)
1850                 return 0;
1851
1852         free(profile);
1853         return 0;
1854 }
1855
1856 /**
1857  * Action
1858  */
1859 #define METER_PROFILES_MAX                                 32
1860
1861 struct rte_table_action {
1862         struct ap_config cfg;
1863         struct ap_data data;
1864         struct dscp_table_data dscp_table;
1865         struct meter_profile_data mp[METER_PROFILES_MAX];
1866 };
1867
1868 struct rte_table_action *
1869 rte_table_action_create(struct rte_table_action_profile *profile,
1870         uint32_t socket_id)
1871 {
1872         struct rte_table_action *action;
1873
1874         /* Check input arguments */
1875         if ((profile == NULL) ||
1876                 (profile->frozen == 0))
1877                 return NULL;
1878
1879         /* Memory allocation */
1880         action = rte_zmalloc_socket(NULL,
1881                 sizeof(struct rte_table_action),
1882                 RTE_CACHE_LINE_SIZE,
1883                 socket_id);
1884         if (action == NULL)
1885                 return NULL;
1886
1887         /* Initialization */
1888         memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
1889         memcpy(&action->data, &profile->data, sizeof(profile->data));
1890
1891         return action;
1892 }
1893
1894 static __rte_always_inline void *
1895 action_data_get(void *data,
1896         struct rte_table_action *action,
1897         enum rte_table_action_type type)
1898 {
1899         size_t offset = action->data.offset[type];
1900         uint8_t *data_bytes = data;
1901
1902         return &data_bytes[offset];
1903 }
1904
1905 int
1906 rte_table_action_apply(struct rte_table_action *action,
1907         void *data,
1908         enum rte_table_action_type type,
1909         void *action_params)
1910 {
1911         void *action_data;
1912
1913         /* Check input arguments */
1914         if ((action == NULL) ||
1915                 (data == NULL) ||
1916                 (action_valid(type) == 0) ||
1917                 ((action->cfg.action_mask & (1LLU << type)) == 0) ||
1918                 (action_params == NULL))
1919                 return -EINVAL;
1920
1921         /* Data update */
1922         action_data = action_data_get(data, action, type);
1923
1924         switch (type) {
1925         case RTE_TABLE_ACTION_FWD:
1926                 return fwd_apply(action_data,
1927                         action_params);
1928
1929         case RTE_TABLE_ACTION_LB:
1930                 return lb_apply(action_data,
1931                         action_params);
1932
1933         case RTE_TABLE_ACTION_MTR:
1934                 return mtr_apply(action_data,
1935                         action_params,
1936                         &action->cfg.mtr,
1937                         action->mp,
1938                         RTE_DIM(action->mp));
1939
1940         case RTE_TABLE_ACTION_TM:
1941                 return tm_apply(action_data,
1942                         action_params,
1943                         &action->cfg.tm);
1944
1945         case RTE_TABLE_ACTION_ENCAP:
1946                 return encap_apply(action_data,
1947                         action_params,
1948                         &action->cfg.encap,
1949                         &action->cfg.common);
1950
1951         case RTE_TABLE_ACTION_NAT:
1952                 return nat_apply(action_data,
1953                         action_params,
1954                         &action->cfg.common);
1955
1956         case RTE_TABLE_ACTION_TTL:
1957                 return ttl_apply(action_data,
1958                         action_params);
1959
1960         case RTE_TABLE_ACTION_STATS:
1961                 return stats_apply(action_data,
1962                         action_params);
1963
1964         case RTE_TABLE_ACTION_TIME:
1965                 return time_apply(action_data,
1966                         action_params);
1967
1968         default:
1969                 return -EINVAL;
1970         }
1971 }
1972
1973 int
1974 rte_table_action_dscp_table_update(struct rte_table_action *action,
1975         uint64_t dscp_mask,
1976         struct rte_table_action_dscp_table *table)
1977 {
1978         uint32_t i;
1979
1980         /* Check input arguments */
1981         if ((action == NULL) ||
1982                 ((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
1983                 (1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
1984                 (dscp_mask == 0) ||
1985                 (table == NULL))
1986                 return -EINVAL;
1987
1988         for (i = 0; i < RTE_DIM(table->entry); i++) {
1989                 struct dscp_table_entry_data *data =
1990                         &action->dscp_table.entry[i];
1991                 struct rte_table_action_dscp_table_entry *entry =
1992                         &table->entry[i];
1993                 uint16_t queue_tc_color =
1994                         MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
1995                                 entry->tc_id,
1996                                 entry->color);
1997
1998                 if ((dscp_mask & (1LLU << i)) == 0)
1999                         continue;
2000
2001                 data->color = entry->color;
2002                 data->tc = entry->tc_id;
2003                 data->queue_tc_color = queue_tc_color;
2004         }
2005
2006         return 0;
2007 }
2008
2009 int
2010 rte_table_action_meter_profile_add(struct rte_table_action *action,
2011         uint32_t meter_profile_id,
2012         struct rte_table_action_meter_profile *profile)
2013 {
2014         struct meter_profile_data *mp_data;
2015         uint32_t status;
2016
2017         /* Check input arguments */
2018         if ((action == NULL) ||
2019                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
2020                 (profile == NULL))
2021                 return -EINVAL;
2022
2023         if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
2024                 return -ENOTSUP;
2025
2026         mp_data = meter_profile_data_find(action->mp,
2027                 RTE_DIM(action->mp),
2028                 meter_profile_id);
2029         if (mp_data)
2030                 return -EEXIST;
2031
2032         mp_data = meter_profile_data_find_unused(action->mp,
2033                 RTE_DIM(action->mp));
2034         if (!mp_data)
2035                 return -ENOSPC;
2036
2037         /* Install new profile */
2038         status = rte_meter_trtcm_profile_config(&mp_data->profile,
2039                 &profile->trtcm);
2040         if (status)
2041                 return status;
2042
2043         mp_data->profile_id = meter_profile_id;
2044         mp_data->valid = 1;
2045
2046         return 0;
2047 }
2048
2049 int
2050 rte_table_action_meter_profile_delete(struct rte_table_action *action,
2051         uint32_t meter_profile_id)
2052 {
2053         struct meter_profile_data *mp_data;
2054
2055         /* Check input arguments */
2056         if ((action == NULL) ||
2057                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
2058                 return -EINVAL;
2059
2060         mp_data = meter_profile_data_find(action->mp,
2061                 RTE_DIM(action->mp),
2062                 meter_profile_id);
2063         if (!mp_data)
2064                 return 0;
2065
2066         /* Uninstall profile */
2067         mp_data->valid = 0;
2068
2069         return 0;
2070 }
2071
2072 int
2073 rte_table_action_meter_read(struct rte_table_action *action,
2074         void *data,
2075         uint32_t tc_mask,
2076         struct rte_table_action_mtr_counters *stats,
2077         int clear)
2078 {
2079         struct mtr_trtcm_data *mtr_data;
2080         uint32_t i;
2081
2082         /* Check input arguments */
2083         if ((action == NULL) ||
2084                 ((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
2085                 (data == NULL) ||
2086                 (tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
2087                 return -EINVAL;
2088
2089         mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
2090
2091         /* Read */
2092         if (stats) {
2093                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
2094                         struct rte_table_action_mtr_counters_tc *dst =
2095                                 &stats->stats[i];
2096                         struct mtr_trtcm_data *src = &mtr_data[i];
2097
2098                         if ((tc_mask & (1 << i)) == 0)
2099                                 continue;
2100
2101                         dst->n_packets[e_RTE_METER_GREEN] =
2102                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
2103
2104                         dst->n_packets[e_RTE_METER_YELLOW] =
2105                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
2106
2107                         dst->n_packets[e_RTE_METER_RED] =
2108                                 mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
2109
2110                         dst->n_packets_valid = 1;
2111                         dst->n_bytes_valid = 0;
2112                 }
2113
2114                 stats->tc_mask = tc_mask;
2115         }
2116
2117         /* Clear */
2118         if (clear)
2119                 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
2120                         struct mtr_trtcm_data *src = &mtr_data[i];
2121
2122                         if ((tc_mask & (1 << i)) == 0)
2123                                 continue;
2124
2125                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
2126                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
2127                         mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
2128                 }
2129
2130
2131         return 0;
2132 }
2133
2134 int
2135 rte_table_action_ttl_read(struct rte_table_action *action,
2136         void *data,
2137         struct rte_table_action_ttl_counters *stats,
2138         int clear)
2139 {
2140         struct ttl_data *ttl_data;
2141
2142         /* Check input arguments */
2143         if ((action == NULL) ||
2144                 ((action->cfg.action_mask &
2145                 (1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
2146                 (data == NULL))
2147                 return -EINVAL;
2148
2149         ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
2150
2151         /* Read */
2152         if (stats)
2153                 stats->n_packets = TTL_STATS_READ(ttl_data);
2154
2155         /* Clear */
2156         if (clear)
2157                 TTL_STATS_RESET(ttl_data);
2158
2159         return 0;
2160 }
2161
2162 int
2163 rte_table_action_stats_read(struct rte_table_action *action,
2164         void *data,
2165         struct rte_table_action_stats_counters *stats,
2166         int clear)
2167 {
2168         struct stats_data *stats_data;
2169
2170         /* Check input arguments */
2171         if ((action == NULL) ||
2172                 ((action->cfg.action_mask &
2173                 (1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
2174                 (data == NULL))
2175                 return -EINVAL;
2176
2177         stats_data = action_data_get(data, action,
2178                 RTE_TABLE_ACTION_STATS);
2179
2180         /* Read */
2181         if (stats) {
2182                 stats->n_packets = stats_data->n_packets;
2183                 stats->n_bytes = stats_data->n_bytes;
2184                 stats->n_packets_valid = 1;
2185                 stats->n_bytes_valid = 1;
2186         }
2187
2188         /* Clear */
2189         if (clear) {
2190                 stats_data->n_packets = 0;
2191                 stats_data->n_bytes = 0;
2192         }
2193
2194         return 0;
2195 }
2196
2197 int
2198 rte_table_action_time_read(struct rte_table_action *action,
2199         void *data,
2200         uint64_t *timestamp)
2201 {
2202         struct time_data *time_data;
2203
2204         /* Check input arguments */
2205         if ((action == NULL) ||
2206                 ((action->cfg.action_mask &
2207                 (1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
2208                 (data == NULL) ||
2209                 (timestamp == NULL))
2210                 return -EINVAL;
2211
2212         time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
2213
2214         /* Read */
2215         *timestamp = time_data->time;
2216
2217         return 0;
2218 }
2219
2220 static __rte_always_inline uint64_t
2221 pkt_work(struct rte_mbuf *mbuf,
2222         struct rte_pipeline_table_entry *table_entry,
2223         uint64_t time,
2224         struct rte_table_action *action,
2225         struct ap_config *cfg)
2226 {
2227         uint64_t drop_mask = 0;
2228
2229         uint32_t ip_offset = action->cfg.common.ip_offset;
2230         void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
2231
2232         uint32_t dscp;
2233         uint16_t total_length;
2234
2235         if (cfg->common.ip_version) {
2236                 struct ipv4_hdr *hdr = ip;
2237
2238                 dscp = hdr->type_of_service >> 2;
2239                 total_length = rte_ntohs(hdr->total_length);
2240         } else {
2241                 struct ipv6_hdr *hdr = ip;
2242
2243                 dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
2244                 total_length =
2245                         rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
2246         }
2247
2248         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2249                 void *data =
2250                         action_data_get(table_entry, action, RTE_TABLE_ACTION_LB);
2251
2252                 pkt_work_lb(mbuf,
2253                         data,
2254                         &cfg->lb);
2255         }
2256         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2257                 void *data =
2258                         action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
2259
2260                 drop_mask |= pkt_work_mtr(mbuf,
2261                         data,
2262                         &action->dscp_table,
2263                         action->mp,
2264                         time,
2265                         dscp,
2266                         total_length);
2267         }
2268
2269         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2270                 void *data =
2271                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
2272
2273                 pkt_work_tm(mbuf,
2274                         data,
2275                         &action->dscp_table,
2276                         dscp);
2277         }
2278
2279         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2280                 void *data =
2281                         action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
2282
2283                 pkt_work_encap(mbuf,
2284                         data,
2285                         &cfg->encap,
2286                         ip,
2287                         total_length,
2288                         ip_offset);
2289         }
2290
2291         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2292                 void *data =
2293                         action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
2294
2295                 if (cfg->common.ip_version)
2296                         pkt_ipv4_work_nat(ip, data, &cfg->nat);
2297                 else
2298                         pkt_ipv6_work_nat(ip, data, &cfg->nat);
2299         }
2300
2301         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2302                 void *data =
2303                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
2304
2305                 if (cfg->common.ip_version)
2306                         drop_mask |= pkt_ipv4_work_ttl(ip, data);
2307                 else
2308                         drop_mask |= pkt_ipv6_work_ttl(ip, data);
2309         }
2310
2311         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2312                 void *data =
2313                         action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
2314
2315                 pkt_work_stats(data, total_length);
2316         }
2317
2318         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2319                 void *data =
2320                         action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
2321
2322                 pkt_work_time(data, time);
2323         }
2324
2325         return drop_mask;
2326 }
2327
2328 static __rte_always_inline uint64_t
2329 pkt4_work(struct rte_mbuf **mbufs,
2330         struct rte_pipeline_table_entry **table_entries,
2331         uint64_t time,
2332         struct rte_table_action *action,
2333         struct ap_config *cfg)
2334 {
2335         uint64_t drop_mask0 = 0;
2336         uint64_t drop_mask1 = 0;
2337         uint64_t drop_mask2 = 0;
2338         uint64_t drop_mask3 = 0;
2339
2340         struct rte_mbuf *mbuf0 = mbufs[0];
2341         struct rte_mbuf *mbuf1 = mbufs[1];
2342         struct rte_mbuf *mbuf2 = mbufs[2];
2343         struct rte_mbuf *mbuf3 = mbufs[3];
2344
2345         struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
2346         struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
2347         struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
2348         struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
2349
2350         uint32_t ip_offset = action->cfg.common.ip_offset;
2351         void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
2352         void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
2353         void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
2354         void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
2355
2356         uint32_t dscp0, dscp1, dscp2, dscp3;
2357         uint16_t total_length0, total_length1, total_length2, total_length3;
2358
2359         if (cfg->common.ip_version) {
2360                 struct ipv4_hdr *hdr0 = ip0;
2361                 struct ipv4_hdr *hdr1 = ip1;
2362                 struct ipv4_hdr *hdr2 = ip2;
2363                 struct ipv4_hdr *hdr3 = ip3;
2364
2365                 dscp0 = hdr0->type_of_service >> 2;
2366                 dscp1 = hdr1->type_of_service >> 2;
2367                 dscp2 = hdr2->type_of_service >> 2;
2368                 dscp3 = hdr3->type_of_service >> 2;
2369
2370                 total_length0 = rte_ntohs(hdr0->total_length);
2371                 total_length1 = rte_ntohs(hdr1->total_length);
2372                 total_length2 = rte_ntohs(hdr2->total_length);
2373                 total_length3 = rte_ntohs(hdr3->total_length);
2374         } else {
2375                 struct ipv6_hdr *hdr0 = ip0;
2376                 struct ipv6_hdr *hdr1 = ip1;
2377                 struct ipv6_hdr *hdr2 = ip2;
2378                 struct ipv6_hdr *hdr3 = ip3;
2379
2380                 dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
2381                 dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
2382                 dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
2383                 dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
2384
2385                 total_length0 =
2386                         rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
2387                 total_length1 =
2388                         rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
2389                 total_length2 =
2390                         rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
2391                 total_length3 =
2392                         rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
2393         }
2394
2395         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2396                 void *data0 =
2397                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_LB);
2398                 void *data1 =
2399                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_LB);
2400                 void *data2 =
2401                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_LB);
2402                 void *data3 =
2403                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_LB);
2404
2405                 pkt_work_lb(mbuf0,
2406                         data0,
2407                         &cfg->lb);
2408
2409                 pkt_work_lb(mbuf1,
2410                         data1,
2411                         &cfg->lb);
2412
2413                 pkt_work_lb(mbuf2,
2414                         data2,
2415                         &cfg->lb);
2416
2417                 pkt_work_lb(mbuf3,
2418                         data3,
2419                         &cfg->lb);
2420         }
2421
2422         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2423                 void *data0 =
2424                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
2425                 void *data1 =
2426                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
2427                 void *data2 =
2428                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
2429                 void *data3 =
2430                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
2431
2432                 drop_mask0 |= pkt_work_mtr(mbuf0,
2433                         data0,
2434                         &action->dscp_table,
2435                         action->mp,
2436                         time,
2437                         dscp0,
2438                         total_length0);
2439
2440                 drop_mask1 |= pkt_work_mtr(mbuf1,
2441                         data1,
2442                         &action->dscp_table,
2443                         action->mp,
2444                         time,
2445                         dscp1,
2446                         total_length1);
2447
2448                 drop_mask2 |= pkt_work_mtr(mbuf2,
2449                         data2,
2450                         &action->dscp_table,
2451                         action->mp,
2452                         time,
2453                         dscp2,
2454                         total_length2);
2455
2456                 drop_mask3 |= pkt_work_mtr(mbuf3,
2457                         data3,
2458                         &action->dscp_table,
2459                         action->mp,
2460                         time,
2461                         dscp3,
2462                         total_length3);
2463         }
2464
2465         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2466                 void *data0 =
2467                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
2468                 void *data1 =
2469                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
2470                 void *data2 =
2471                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
2472                 void *data3 =
2473                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
2474
2475                 pkt_work_tm(mbuf0,
2476                         data0,
2477                         &action->dscp_table,
2478                         dscp0);
2479
2480                 pkt_work_tm(mbuf1,
2481                         data1,
2482                         &action->dscp_table,
2483                         dscp1);
2484
2485                 pkt_work_tm(mbuf2,
2486                         data2,
2487                         &action->dscp_table,
2488                         dscp2);
2489
2490                 pkt_work_tm(mbuf3,
2491                         data3,
2492                         &action->dscp_table,
2493                         dscp3);
2494         }
2495
2496         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2497                 void *data0 =
2498                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
2499                 void *data1 =
2500                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
2501                 void *data2 =
2502                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
2503                 void *data3 =
2504                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
2505
2506                 pkt_work_encap(mbuf0,
2507                         data0,
2508                         &cfg->encap,
2509                         ip0,
2510                         total_length0,
2511                         ip_offset);
2512
2513                 pkt_work_encap(mbuf1,
2514                         data1,
2515                         &cfg->encap,
2516                         ip1,
2517                         total_length1,
2518                         ip_offset);
2519
2520                 pkt_work_encap(mbuf2,
2521                         data2,
2522                         &cfg->encap,
2523                         ip2,
2524                         total_length2,
2525                         ip_offset);
2526
2527                 pkt_work_encap(mbuf3,
2528                         data3,
2529                         &cfg->encap,
2530                         ip3,
2531                         total_length3,
2532                         ip_offset);
2533         }
2534
2535         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2536                 void *data0 =
2537                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
2538                 void *data1 =
2539                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
2540                 void *data2 =
2541                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
2542                 void *data3 =
2543                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
2544
2545                 if (cfg->common.ip_version) {
2546                         pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
2547                         pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
2548                         pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
2549                         pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
2550                 } else {
2551                         pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
2552                         pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
2553                         pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
2554                         pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
2555                 }
2556         }
2557
2558         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2559                 void *data0 =
2560                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
2561                 void *data1 =
2562                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
2563                 void *data2 =
2564                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
2565                 void *data3 =
2566                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
2567
2568                 if (cfg->common.ip_version) {
2569                         drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
2570                         drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
2571                         drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
2572                         drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
2573                 } else {
2574                         drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
2575                         drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
2576                         drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
2577                         drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
2578                 }
2579         }
2580
2581         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2582                 void *data0 =
2583                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
2584                 void *data1 =
2585                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
2586                 void *data2 =
2587                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
2588                 void *data3 =
2589                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
2590
2591                 pkt_work_stats(data0, total_length0);
2592                 pkt_work_stats(data1, total_length1);
2593                 pkt_work_stats(data2, total_length2);
2594                 pkt_work_stats(data3, total_length3);
2595         }
2596
2597         if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2598                 void *data0 =
2599                         action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
2600                 void *data1 =
2601                         action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
2602                 void *data2 =
2603                         action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
2604                 void *data3 =
2605                         action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
2606
2607                 pkt_work_time(data0, time);
2608                 pkt_work_time(data1, time);
2609                 pkt_work_time(data2, time);
2610                 pkt_work_time(data3, time);
2611         }
2612
2613         return drop_mask0 |
2614                 (drop_mask1 << 1) |
2615                 (drop_mask2 << 2) |
2616                 (drop_mask3 << 3);
2617 }
2618
2619 static __rte_always_inline int
2620 ah(struct rte_pipeline *p,
2621         struct rte_mbuf **pkts,
2622         uint64_t pkts_mask,
2623         struct rte_pipeline_table_entry **entries,
2624         struct rte_table_action *action,
2625         struct ap_config *cfg)
2626 {
2627         uint64_t pkts_drop_mask = 0;
2628         uint64_t time = 0;
2629
2630         if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
2631                 (1LLU << RTE_TABLE_ACTION_TIME)))
2632                 time = rte_rdtsc();
2633
2634         if ((pkts_mask & (pkts_mask + 1)) == 0) {
2635                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
2636                 uint32_t i;
2637
2638                 for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2639                         uint64_t drop_mask;
2640
2641                         drop_mask = pkt4_work(&pkts[i],
2642                                 &entries[i],
2643                                 time,
2644                                 action,
2645                                 cfg);
2646
2647                         pkts_drop_mask |= drop_mask << i;
2648                 }
2649
2650                 for ( ; i < n_pkts; i++) {
2651                         uint64_t drop_mask;
2652
2653                         drop_mask = pkt_work(pkts[i],
2654                                 entries[i],
2655                                 time,
2656                                 action,
2657                                 cfg);
2658
2659                         pkts_drop_mask |= drop_mask << i;
2660                 }
2661         } else
2662                 for ( ; pkts_mask; ) {
2663                         uint32_t pos = __builtin_ctzll(pkts_mask);
2664                         uint64_t pkt_mask = 1LLU << pos;
2665                         uint64_t drop_mask;
2666
2667                         drop_mask = pkt_work(pkts[pos],
2668                                 entries[pos],
2669                                 time,
2670                                 action,
2671                                 cfg);
2672
2673                         pkts_mask &= ~pkt_mask;
2674                         pkts_drop_mask |= drop_mask << pos;
2675                 }
2676
2677         rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2678
2679         return 0;
2680 }
2681
2682 static int
2683 ah_default(struct rte_pipeline *p,
2684         struct rte_mbuf **pkts,
2685         uint64_t pkts_mask,
2686         struct rte_pipeline_table_entry **entries,
2687         void *arg)
2688 {
2689         struct rte_table_action *action = arg;
2690
2691         return ah(p,
2692                 pkts,
2693                 pkts_mask,
2694                 entries,
2695                 action,
2696                 &action->cfg);
2697 }
2698
2699 static rte_pipeline_table_action_handler_hit
2700 ah_selector(struct rte_table_action *action)
2701 {
2702         if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
2703                 return NULL;
2704
2705         return ah_default;
2706 }
2707
2708 int
2709 rte_table_action_table_params_get(struct rte_table_action *action,
2710         struct rte_pipeline_table_params *params)
2711 {
2712         rte_pipeline_table_action_handler_hit f_action_hit;
2713         uint32_t total_size;
2714
2715         /* Check input arguments */
2716         if ((action == NULL) ||
2717                 (params == NULL))
2718                 return -EINVAL;
2719
2720         f_action_hit = ah_selector(action);
2721         total_size = rte_align32pow2(action->data.total_size);
2722
2723         /* Fill in params */
2724         params->f_action_hit = f_action_hit;
2725         params->f_action_miss = NULL;
2726         params->arg_ah = (f_action_hit) ? action : NULL;
2727         params->action_data_size = total_size -
2728                 sizeof(struct rte_pipeline_table_entry);
2729
2730         return 0;
2731 }
2732
2733 int
2734 rte_table_action_free(struct rte_table_action *action)
2735 {
2736         if (action == NULL)
2737                 return 0;
2738
2739         rte_free(action);
2740
2741         return 0;
2742 }