New upstream version 18.11-rc1
[deb_dpdk.git] / examples / ip_pipeline / pipeline.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_ip.h>
10 #include <rte_tcp.h>
11
12 #include <rte_string_fns.h>
13 #include <rte_port_ethdev.h>
14 #ifdef RTE_LIBRTE_KNI
15 #include <rte_port_kni.h>
16 #endif
17 #include <rte_port_ring.h>
18 #include <rte_port_source_sink.h>
19 #include <rte_port_fd.h>
20 #include <rte_port_sched.h>
21 #include <rte_port_sym_crypto.h>
22
23 #include <rte_table_acl.h>
24 #include <rte_table_array.h>
25 #include <rte_table_hash.h>
26 #include <rte_table_hash_func.h>
27 #include <rte_table_lpm.h>
28 #include <rte_table_lpm_ipv6.h>
29 #include <rte_table_stub.h>
30
31 #ifdef RTE_LIBRTE_KNI
32 #include "kni.h"
33 #endif
34 #include "link.h"
35 #include "mempool.h"
36 #include "pipeline.h"
37 #include "tap.h"
38 #include "tmgr.h"
39 #include "swq.h"
40 #include "cryptodev.h"
41
42 #ifndef PIPELINE_MSGQ_SIZE
43 #define PIPELINE_MSGQ_SIZE                                 64
44 #endif
45
46 #ifndef TABLE_LPM_NUMBER_TBL8
47 #define TABLE_LPM_NUMBER_TBL8                              256
48 #endif
49
50 static struct pipeline_list pipeline_list;
51
52 int
53 pipeline_init(void)
54 {
55         TAILQ_INIT(&pipeline_list);
56
57         return 0;
58 }
59
60 struct pipeline *
61 pipeline_find(const char *name)
62 {
63         struct pipeline *pipeline;
64
65         if (name == NULL)
66                 return NULL;
67
68         TAILQ_FOREACH(pipeline, &pipeline_list, node)
69                 if (strcmp(name, pipeline->name) == 0)
70                         return pipeline;
71
72         return NULL;
73 }
74
75 struct pipeline *
76 pipeline_create(const char *name, struct pipeline_params *params)
77 {
78         char msgq_name[NAME_MAX];
79         struct rte_pipeline_params pp;
80         struct pipeline *pipeline;
81         struct rte_pipeline *p;
82         struct rte_ring *msgq_req;
83         struct rte_ring *msgq_rsp;
84
85         /* Check input params */
86         if ((name == NULL) ||
87                 pipeline_find(name) ||
88                 (params == NULL) ||
89                 (params->timer_period_ms == 0))
90                 return NULL;
91
92         /* Resource create */
93         snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name);
94
95         msgq_req = rte_ring_create(msgq_name,
96                 PIPELINE_MSGQ_SIZE,
97                 params->cpu_id,
98                 RING_F_SP_ENQ | RING_F_SC_DEQ);
99         if (msgq_req == NULL)
100                 return NULL;
101
102         snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name);
103
104         msgq_rsp = rte_ring_create(msgq_name,
105                 PIPELINE_MSGQ_SIZE,
106                 params->cpu_id,
107                 RING_F_SP_ENQ | RING_F_SC_DEQ);
108         if (msgq_rsp == NULL) {
109                 rte_ring_free(msgq_req);
110                 return NULL;
111         }
112
113         pp.name = name;
114         pp.socket_id = (int) params->cpu_id;
115         pp.offset_port_id = params->offset_port_id;
116
117         p = rte_pipeline_create(&pp);
118         if (p == NULL) {
119                 rte_ring_free(msgq_rsp);
120                 rte_ring_free(msgq_req);
121                 return NULL;
122         }
123
124         /* Node allocation */
125         pipeline = calloc(1, sizeof(struct pipeline));
126         if (pipeline == NULL) {
127                 rte_pipeline_free(p);
128                 rte_ring_free(msgq_rsp);
129                 rte_ring_free(msgq_req);
130                 return NULL;
131         }
132
133         /* Node fill in */
134         strlcpy(pipeline->name, name, sizeof(pipeline->name));
135         pipeline->p = p;
136         pipeline->n_ports_in = 0;
137         pipeline->n_ports_out = 0;
138         pipeline->n_tables = 0;
139         pipeline->msgq_req = msgq_req;
140         pipeline->msgq_rsp = msgq_rsp;
141         pipeline->timer_period_ms = params->timer_period_ms;
142         pipeline->enabled = 0;
143         pipeline->cpu_id = params->cpu_id;
144
145         /* Node add to list */
146         TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node);
147
148         return pipeline;
149 }
150
151 int
152 pipeline_port_in_create(const char *pipeline_name,
153         struct port_in_params *params,
154         int enabled)
155 {
156         struct rte_pipeline_port_in_params p;
157
158         union {
159                 struct rte_port_ethdev_reader_params ethdev;
160                 struct rte_port_ring_reader_params ring;
161                 struct rte_port_sched_reader_params sched;
162                 struct rte_port_fd_reader_params fd;
163 #ifdef RTE_LIBRTE_KNI
164                 struct rte_port_kni_reader_params kni;
165 #endif
166                 struct rte_port_source_params source;
167                 struct rte_port_sym_crypto_reader_params sym_crypto;
168         } pp;
169
170         struct pipeline *pipeline;
171         struct port_in *port_in;
172         struct port_in_action_profile *ap;
173         struct rte_port_in_action *action;
174         uint32_t port_id;
175         int status;
176
177         memset(&p, 0, sizeof(p));
178         memset(&pp, 0, sizeof(pp));
179
180         /* Check input params */
181         if ((pipeline_name == NULL) ||
182                 (params == NULL) ||
183                 (params->burst_size == 0) ||
184                 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
185                 return -1;
186
187         pipeline = pipeline_find(pipeline_name);
188         if (pipeline == NULL)
189                 return -1;
190
191         ap = NULL;
192         if (params->action_profile_name) {
193                 ap = port_in_action_profile_find(params->action_profile_name);
194                 if (ap == NULL)
195                         return -1;
196         }
197
198         switch (params->type) {
199         case PORT_IN_RXQ:
200         {
201                 struct link *link;
202
203                 link = link_find(params->dev_name);
204                 if (link == NULL)
205                         return -1;
206
207                 if (params->rxq.queue_id >= link->n_rxq)
208                         return -1;
209
210                 pp.ethdev.port_id = link->port_id;
211                 pp.ethdev.queue_id = params->rxq.queue_id;
212
213                 p.ops = &rte_port_ethdev_reader_ops;
214                 p.arg_create = &pp.ethdev;
215                 break;
216         }
217
218         case PORT_IN_SWQ:
219         {
220                 struct swq *swq;
221
222                 swq = swq_find(params->dev_name);
223                 if (swq == NULL)
224                         return -1;
225
226                 pp.ring.ring = swq->r;
227
228                 p.ops = &rte_port_ring_reader_ops;
229                 p.arg_create = &pp.ring;
230                 break;
231         }
232
233         case PORT_IN_TMGR:
234         {
235                 struct tmgr_port *tmgr_port;
236
237                 tmgr_port = tmgr_port_find(params->dev_name);
238                 if (tmgr_port == NULL)
239                         return -1;
240
241                 pp.sched.sched = tmgr_port->s;
242
243                 p.ops = &rte_port_sched_reader_ops;
244                 p.arg_create = &pp.sched;
245                 break;
246         }
247
248         case PORT_IN_TAP:
249         {
250                 struct tap *tap;
251                 struct mempool *mempool;
252
253                 tap = tap_find(params->dev_name);
254                 mempool = mempool_find(params->tap.mempool_name);
255                 if ((tap == NULL) || (mempool == NULL))
256                         return -1;
257
258                 pp.fd.fd = tap->fd;
259                 pp.fd.mempool = mempool->m;
260                 pp.fd.mtu = params->tap.mtu;
261
262                 p.ops = &rte_port_fd_reader_ops;
263                 p.arg_create = &pp.fd;
264                 break;
265         }
266
267 #ifdef RTE_LIBRTE_KNI
268         case PORT_IN_KNI:
269         {
270                 struct kni *kni;
271
272                 kni = kni_find(params->dev_name);
273                 if (kni == NULL)
274                         return -1;
275
276                 pp.kni.kni = kni->k;
277
278                 p.ops = &rte_port_kni_reader_ops;
279                 p.arg_create = &pp.kni;
280                 break;
281         }
282 #endif
283
284         case PORT_IN_SOURCE:
285         {
286                 struct mempool *mempool;
287
288                 mempool = mempool_find(params->source.mempool_name);
289                 if (mempool == NULL)
290                         return -1;
291
292                 pp.source.mempool = mempool->m;
293                 pp.source.file_name = params->source.file_name;
294                 pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
295
296                 p.ops = &rte_port_source_ops;
297                 p.arg_create = &pp.source;
298                 break;
299         }
300
301         case PORT_IN_CRYPTODEV:
302         {
303                 struct cryptodev *cryptodev;
304
305                 cryptodev = cryptodev_find(params->dev_name);
306                 if (cryptodev == NULL)
307                         return -1;
308
309                 if (params->rxq.queue_id > cryptodev->n_queues - 1)
310                         return -1;
311
312                 pp.sym_crypto.cryptodev_id = cryptodev->dev_id;
313                 pp.sym_crypto.queue_id = params->cryptodev.queue_id;
314                 pp.sym_crypto.f_callback = params->cryptodev.f_callback;
315                 pp.sym_crypto.arg_callback = params->cryptodev.arg_callback;
316                 p.ops = &rte_port_sym_crypto_reader_ops;
317                 p.arg_create = &pp.sym_crypto;
318
319                 break;
320         }
321
322         default:
323                 return -1;
324         }
325
326         p.burst_size = params->burst_size;
327
328         /* Resource create */
329         action = NULL;
330         p.f_action = NULL;
331         p.arg_ah = NULL;
332
333         if (ap) {
334                 action = rte_port_in_action_create(ap->ap,
335                         pipeline->cpu_id);
336                 if (action == NULL)
337                         return -1;
338
339                 status = rte_port_in_action_params_get(
340                         action,
341                         &p);
342                 if (status) {
343                         rte_port_in_action_free(action);
344                         return -1;
345                 }
346         }
347
348         status = rte_pipeline_port_in_create(pipeline->p,
349                 &p,
350                 &port_id);
351         if (status) {
352                 rte_port_in_action_free(action);
353                 return -1;
354         }
355
356         if (enabled)
357                 rte_pipeline_port_in_enable(pipeline->p, port_id);
358
359         /* Pipeline */
360         port_in = &pipeline->port_in[pipeline->n_ports_in];
361         memcpy(&port_in->params, params, sizeof(*params));
362         port_in->ap = ap;
363         port_in->a = action;
364         pipeline->n_ports_in++;
365
366         return 0;
367 }
368
369 int
370 pipeline_port_in_connect_to_table(const char *pipeline_name,
371         uint32_t port_id,
372         uint32_t table_id)
373 {
374         struct pipeline *pipeline;
375         int status;
376
377         /* Check input params */
378         if (pipeline_name == NULL)
379                 return -1;
380
381         pipeline = pipeline_find(pipeline_name);
382         if ((pipeline == NULL) ||
383                 (port_id >= pipeline->n_ports_in) ||
384                 (table_id >= pipeline->n_tables))
385                 return -1;
386
387         /* Resource */
388         status = rte_pipeline_port_in_connect_to_table(pipeline->p,
389                 port_id,
390                 table_id);
391
392         return status;
393
394 }
395
396 int
397 pipeline_port_out_create(const char *pipeline_name,
398         struct port_out_params *params)
399 {
400         struct rte_pipeline_port_out_params p;
401
402         union {
403                 struct rte_port_ethdev_writer_params ethdev;
404                 struct rte_port_ring_writer_params ring;
405                 struct rte_port_sched_writer_params sched;
406                 struct rte_port_fd_writer_params fd;
407 #ifdef RTE_LIBRTE_KNI
408                 struct rte_port_kni_writer_params kni;
409 #endif
410                 struct rte_port_sink_params sink;
411                 struct rte_port_sym_crypto_writer_params sym_crypto;
412         } pp;
413
414         union {
415                 struct rte_port_ethdev_writer_nodrop_params ethdev;
416                 struct rte_port_ring_writer_nodrop_params ring;
417                 struct rte_port_fd_writer_nodrop_params fd;
418 #ifdef RTE_LIBRTE_KNI
419                 struct rte_port_kni_writer_nodrop_params kni;
420 #endif
421                 struct rte_port_sym_crypto_writer_nodrop_params sym_crypto;
422         } pp_nodrop;
423
424         struct pipeline *pipeline;
425         uint32_t port_id;
426         int status;
427
428         memset(&p, 0, sizeof(p));
429         memset(&pp, 0, sizeof(pp));
430         memset(&pp_nodrop, 0, sizeof(pp_nodrop));
431
432         /* Check input params */
433         if ((pipeline_name == NULL) ||
434                 (params == NULL) ||
435                 (params->burst_size == 0) ||
436                 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
437                 return -1;
438
439         pipeline = pipeline_find(pipeline_name);
440         if (pipeline == NULL)
441                 return -1;
442
443         switch (params->type) {
444         case PORT_OUT_TXQ:
445         {
446                 struct link *link;
447
448                 link = link_find(params->dev_name);
449                 if (link == NULL)
450                         return -1;
451
452                 if (params->txq.queue_id >= link->n_txq)
453                         return -1;
454
455                 pp.ethdev.port_id = link->port_id;
456                 pp.ethdev.queue_id = params->txq.queue_id;
457                 pp.ethdev.tx_burst_sz = params->burst_size;
458
459                 pp_nodrop.ethdev.port_id = link->port_id;
460                 pp_nodrop.ethdev.queue_id = params->txq.queue_id;
461                 pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
462                 pp_nodrop.ethdev.n_retries = params->n_retries;
463
464                 if (params->retry == 0) {
465                         p.ops = &rte_port_ethdev_writer_ops;
466                         p.arg_create = &pp.ethdev;
467                 } else {
468                         p.ops = &rte_port_ethdev_writer_nodrop_ops;
469                         p.arg_create = &pp_nodrop.ethdev;
470                 }
471                 break;
472         }
473
474         case PORT_OUT_SWQ:
475         {
476                 struct swq *swq;
477
478                 swq = swq_find(params->dev_name);
479                 if (swq == NULL)
480                         return -1;
481
482                 pp.ring.ring = swq->r;
483                 pp.ring.tx_burst_sz = params->burst_size;
484
485                 pp_nodrop.ring.ring = swq->r;
486                 pp_nodrop.ring.tx_burst_sz = params->burst_size;
487                 pp_nodrop.ring.n_retries = params->n_retries;
488
489                 if (params->retry == 0) {
490                         p.ops = &rte_port_ring_writer_ops;
491                         p.arg_create = &pp.ring;
492                 } else {
493                         p.ops = &rte_port_ring_writer_nodrop_ops;
494                         p.arg_create = &pp_nodrop.ring;
495                 }
496                 break;
497         }
498
499         case PORT_OUT_TMGR:
500         {
501                 struct tmgr_port *tmgr_port;
502
503                 tmgr_port = tmgr_port_find(params->dev_name);
504                 if (tmgr_port == NULL)
505                         return -1;
506
507                 pp.sched.sched = tmgr_port->s;
508                 pp.sched.tx_burst_sz = params->burst_size;
509
510                 p.ops = &rte_port_sched_writer_ops;
511                 p.arg_create = &pp.sched;
512                 break;
513         }
514
515         case PORT_OUT_TAP:
516         {
517                 struct tap *tap;
518
519                 tap = tap_find(params->dev_name);
520                 if (tap == NULL)
521                         return -1;
522
523                 pp.fd.fd = tap->fd;
524                 pp.fd.tx_burst_sz = params->burst_size;
525
526                 pp_nodrop.fd.fd = tap->fd;
527                 pp_nodrop.fd.tx_burst_sz = params->burst_size;
528                 pp_nodrop.fd.n_retries = params->n_retries;
529
530                 if (params->retry == 0) {
531                         p.ops = &rte_port_fd_writer_ops;
532                         p.arg_create = &pp.fd;
533                 } else {
534                         p.ops = &rte_port_fd_writer_nodrop_ops;
535                         p.arg_create = &pp_nodrop.fd;
536                 }
537                 break;
538         }
539
540 #ifdef RTE_LIBRTE_KNI
541         case PORT_OUT_KNI:
542         {
543                 struct kni *kni;
544
545                 kni = kni_find(params->dev_name);
546                 if (kni == NULL)
547                         return -1;
548
549                 pp.kni.kni = kni->k;
550                 pp.kni.tx_burst_sz = params->burst_size;
551
552                 pp_nodrop.kni.kni = kni->k;
553                 pp_nodrop.kni.tx_burst_sz = params->burst_size;
554                 pp_nodrop.kni.n_retries = params->n_retries;
555
556                 if (params->retry == 0) {
557                         p.ops = &rte_port_kni_writer_ops;
558                         p.arg_create = &pp.kni;
559                 } else {
560                         p.ops = &rte_port_kni_writer_nodrop_ops;
561                         p.arg_create = &pp_nodrop.kni;
562                 }
563                 break;
564         }
565 #endif
566
567         case PORT_OUT_SINK:
568         {
569                 pp.sink.file_name = params->sink.file_name;
570                 pp.sink.max_n_pkts = params->sink.max_n_pkts;
571
572                 p.ops = &rte_port_sink_ops;
573                 p.arg_create = &pp.sink;
574                 break;
575         }
576
577         case PORT_OUT_CRYPTODEV:
578         {
579                 struct cryptodev *cryptodev;
580
581                 cryptodev = cryptodev_find(params->dev_name);
582                 if (cryptodev == NULL)
583                         return -1;
584
585                 if (params->cryptodev.queue_id >= cryptodev->n_queues)
586                         return -1;
587
588                 pp.sym_crypto.cryptodev_id = cryptodev->dev_id;
589                 pp.sym_crypto.queue_id = params->cryptodev.queue_id;
590                 pp.sym_crypto.tx_burst_sz = params->burst_size;
591                 pp.sym_crypto.crypto_op_offset = params->cryptodev.op_offset;
592
593                 pp_nodrop.sym_crypto.cryptodev_id = cryptodev->dev_id;
594                 pp_nodrop.sym_crypto.queue_id = params->cryptodev.queue_id;
595                 pp_nodrop.sym_crypto.tx_burst_sz = params->burst_size;
596                 pp_nodrop.sym_crypto.n_retries = params->retry;
597                 pp_nodrop.sym_crypto.crypto_op_offset =
598                                 params->cryptodev.op_offset;
599
600                 if (params->retry == 0) {
601                         p.ops = &rte_port_sym_crypto_writer_ops;
602                         p.arg_create = &pp.sym_crypto;
603                 } else {
604                         p.ops = &rte_port_sym_crypto_writer_nodrop_ops;
605                         p.arg_create = &pp_nodrop.sym_crypto;
606                 }
607
608                 break;
609         }
610
611         default:
612                 return -1;
613         }
614
615         p.f_action = NULL;
616         p.arg_ah = NULL;
617
618         /* Resource create */
619         status = rte_pipeline_port_out_create(pipeline->p,
620                 &p,
621                 &port_id);
622
623         if (status)
624                 return -1;
625
626         /* Pipeline */
627         pipeline->n_ports_out++;
628
629         return 0;
630 }
631
632 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
633         /* Protocol */
634         [0] = {
635                 .type = RTE_ACL_FIELD_TYPE_BITMASK,
636                 .size = sizeof(uint8_t),
637                 .field_index = 0,
638                 .input_index = 0,
639                 .offset = offsetof(struct ipv4_hdr, next_proto_id),
640         },
641
642         /* Source IP address (IPv4) */
643         [1] = {
644                 .type = RTE_ACL_FIELD_TYPE_MASK,
645                 .size = sizeof(uint32_t),
646                 .field_index = 1,
647                 .input_index = 1,
648                 .offset = offsetof(struct ipv4_hdr, src_addr),
649         },
650
651         /* Destination IP address (IPv4) */
652         [2] = {
653                 .type = RTE_ACL_FIELD_TYPE_MASK,
654                 .size = sizeof(uint32_t),
655                 .field_index = 2,
656                 .input_index = 2,
657                 .offset = offsetof(struct ipv4_hdr, dst_addr),
658         },
659
660         /* Source Port */
661         [3] = {
662                 .type = RTE_ACL_FIELD_TYPE_RANGE,
663                 .size = sizeof(uint16_t),
664                 .field_index = 3,
665                 .input_index = 3,
666                 .offset = sizeof(struct ipv4_hdr) +
667                         offsetof(struct tcp_hdr, src_port),
668         },
669
670         /* Destination Port */
671         [4] = {
672                 .type = RTE_ACL_FIELD_TYPE_RANGE,
673                 .size = sizeof(uint16_t),
674                 .field_index = 4,
675                 .input_index = 3,
676                 .offset = sizeof(struct ipv4_hdr) +
677                         offsetof(struct tcp_hdr, dst_port),
678         },
679 };
680
681 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
682         /* Protocol */
683         [0] = {
684                 .type = RTE_ACL_FIELD_TYPE_BITMASK,
685                 .size = sizeof(uint8_t),
686                 .field_index = 0,
687                 .input_index = 0,
688                 .offset = offsetof(struct ipv6_hdr, proto),
689         },
690
691         /* Source IP address (IPv6) */
692         [1] = {
693                 .type = RTE_ACL_FIELD_TYPE_MASK,
694                 .size = sizeof(uint32_t),
695                 .field_index = 1,
696                 .input_index = 1,
697                 .offset = offsetof(struct ipv6_hdr, src_addr[0]),
698         },
699
700         [2] = {
701                 .type = RTE_ACL_FIELD_TYPE_MASK,
702                 .size = sizeof(uint32_t),
703                 .field_index = 2,
704                 .input_index = 2,
705                 .offset = offsetof(struct ipv6_hdr, src_addr[4]),
706         },
707
708         [3] = {
709                 .type = RTE_ACL_FIELD_TYPE_MASK,
710                 .size = sizeof(uint32_t),
711                 .field_index = 3,
712                 .input_index = 3,
713                 .offset = offsetof(struct ipv6_hdr, src_addr[8]),
714         },
715
716         [4] = {
717                 .type = RTE_ACL_FIELD_TYPE_MASK,
718                 .size = sizeof(uint32_t),
719                 .field_index = 4,
720                 .input_index = 4,
721                 .offset = offsetof(struct ipv6_hdr, src_addr[12]),
722         },
723
724         /* Destination IP address (IPv6) */
725         [5] = {
726                 .type = RTE_ACL_FIELD_TYPE_MASK,
727                 .size = sizeof(uint32_t),
728                 .field_index = 5,
729                 .input_index = 5,
730                 .offset = offsetof(struct ipv6_hdr, dst_addr[0]),
731         },
732
733         [6] = {
734                 .type = RTE_ACL_FIELD_TYPE_MASK,
735                 .size = sizeof(uint32_t),
736                 .field_index = 6,
737                 .input_index = 6,
738                 .offset = offsetof(struct ipv6_hdr, dst_addr[4]),
739         },
740
741         [7] = {
742                 .type = RTE_ACL_FIELD_TYPE_MASK,
743                 .size = sizeof(uint32_t),
744                 .field_index = 7,
745                 .input_index = 7,
746                 .offset = offsetof(struct ipv6_hdr, dst_addr[8]),
747         },
748
749         [8] = {
750                 .type = RTE_ACL_FIELD_TYPE_MASK,
751                 .size = sizeof(uint32_t),
752                 .field_index = 8,
753                 .input_index = 8,
754                 .offset = offsetof(struct ipv6_hdr, dst_addr[12]),
755         },
756
757         /* Source Port */
758         [9] = {
759                 .type = RTE_ACL_FIELD_TYPE_RANGE,
760                 .size = sizeof(uint16_t),
761                 .field_index = 9,
762                 .input_index = 9,
763                 .offset = sizeof(struct ipv6_hdr) +
764                         offsetof(struct tcp_hdr, src_port),
765         },
766
767         /* Destination Port */
768         [10] = {
769                 .type = RTE_ACL_FIELD_TYPE_RANGE,
770                 .size = sizeof(uint16_t),
771                 .field_index = 10,
772                 .input_index = 9,
773                 .offset = sizeof(struct ipv6_hdr) +
774                         offsetof(struct tcp_hdr, dst_port),
775         },
776 };
777
778 int
779 pipeline_table_create(const char *pipeline_name,
780         struct table_params *params)
781 {
782         char name[NAME_MAX];
783         struct rte_pipeline_table_params p;
784
785         union {
786                 struct rte_table_acl_params acl;
787                 struct rte_table_array_params array;
788                 struct rte_table_hash_params hash;
789                 struct rte_table_lpm_params lpm;
790                 struct rte_table_lpm_ipv6_params lpm_ipv6;
791         } pp;
792
793         struct pipeline *pipeline;
794         struct table *table;
795         struct table_action_profile *ap;
796         struct rte_table_action *action;
797         uint32_t table_id;
798         int status;
799
800         memset(&p, 0, sizeof(p));
801         memset(&pp, 0, sizeof(pp));
802
803         /* Check input params */
804         if ((pipeline_name == NULL) ||
805                 (params == NULL))
806                 return -1;
807
808         pipeline = pipeline_find(pipeline_name);
809         if ((pipeline == NULL) ||
810                 (pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX))
811                 return -1;
812
813         ap = NULL;
814         if (params->action_profile_name) {
815                 ap = table_action_profile_find(params->action_profile_name);
816                 if (ap == NULL)
817                         return -1;
818         }
819
820         snprintf(name, NAME_MAX, "%s_table%u",
821                 pipeline_name, pipeline->n_tables);
822
823         switch (params->match_type) {
824         case TABLE_ACL:
825         {
826                 uint32_t ip_header_offset = params->match.acl.ip_header_offset -
827                         (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
828                 uint32_t i;
829
830                 if (params->match.acl.n_rules == 0)
831                         return -1;
832
833                 pp.acl.name = name;
834                 pp.acl.n_rules = params->match.acl.n_rules;
835                 if (params->match.acl.ip_version) {
836                         memcpy(&pp.acl.field_format,
837                                 &table_acl_field_format_ipv4,
838                                 sizeof(table_acl_field_format_ipv4));
839                         pp.acl.n_rule_fields =
840                                 RTE_DIM(table_acl_field_format_ipv4);
841                 } else {
842                         memcpy(&pp.acl.field_format,
843                                 &table_acl_field_format_ipv6,
844                                 sizeof(table_acl_field_format_ipv6));
845                         pp.acl.n_rule_fields =
846                                 RTE_DIM(table_acl_field_format_ipv6);
847                 }
848
849                 for (i = 0; i < pp.acl.n_rule_fields; i++)
850                         pp.acl.field_format[i].offset += ip_header_offset;
851
852                 p.ops = &rte_table_acl_ops;
853                 p.arg_create = &pp.acl;
854                 break;
855         }
856
857         case TABLE_ARRAY:
858         {
859                 if (params->match.array.n_keys == 0)
860                         return -1;
861
862                 pp.array.n_entries = params->match.array.n_keys;
863                 pp.array.offset = params->match.array.key_offset;
864
865                 p.ops = &rte_table_array_ops;
866                 p.arg_create = &pp.array;
867                 break;
868         }
869
870         case TABLE_HASH:
871         {
872                 struct rte_table_ops *ops;
873                 rte_table_hash_op_hash f_hash;
874
875                 if (params->match.hash.n_keys == 0)
876                         return -1;
877
878                 switch (params->match.hash.key_size) {
879                 case  8:
880                         f_hash = rte_table_hash_crc_key8;
881                         break;
882                 case 16:
883                         f_hash = rte_table_hash_crc_key16;
884                         break;
885                 case 24:
886                         f_hash = rte_table_hash_crc_key24;
887                         break;
888                 case 32:
889                         f_hash = rte_table_hash_crc_key32;
890                         break;
891                 case 40:
892                         f_hash = rte_table_hash_crc_key40;
893                         break;
894                 case 48:
895                         f_hash = rte_table_hash_crc_key48;
896                         break;
897                 case 56:
898                         f_hash = rte_table_hash_crc_key56;
899                         break;
900                 case 64:
901                         f_hash = rte_table_hash_crc_key64;
902                         break;
903                 default:
904                         return -1;
905                 }
906
907                 pp.hash.name = name;
908                 pp.hash.key_size = params->match.hash.key_size;
909                 pp.hash.key_offset = params->match.hash.key_offset;
910                 pp.hash.key_mask = params->match.hash.key_mask;
911                 pp.hash.n_keys = params->match.hash.n_keys;
912                 pp.hash.n_buckets = params->match.hash.n_buckets;
913                 pp.hash.f_hash = f_hash;
914                 pp.hash.seed = 0;
915
916                 if (params->match.hash.extendable_bucket)
917                         switch (params->match.hash.key_size) {
918                         case  8:
919                                 ops = &rte_table_hash_key8_ext_ops;
920                                 break;
921                         case 16:
922                                 ops = &rte_table_hash_key16_ext_ops;
923                                 break;
924                         default:
925                                 ops = &rte_table_hash_ext_ops;
926                         }
927                 else
928                         switch (params->match.hash.key_size) {
929                         case  8:
930                                 ops = &rte_table_hash_key8_lru_ops;
931                                 break;
932                         case 16:
933                                 ops = &rte_table_hash_key16_lru_ops;
934                                 break;
935                         default:
936                                 ops = &rte_table_hash_lru_ops;
937                         }
938
939                 p.ops = ops;
940                 p.arg_create = &pp.hash;
941                 break;
942         }
943
944         case TABLE_LPM:
945         {
946                 if (params->match.lpm.n_rules == 0)
947                         return -1;
948
949                 switch (params->match.lpm.key_size) {
950                 case 4:
951                 {
952                         pp.lpm.name = name;
953                         pp.lpm.n_rules = params->match.lpm.n_rules;
954                         pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
955                         pp.lpm.flags = 0;
956                         pp.lpm.entry_unique_size = p.action_data_size +
957                                 sizeof(struct rte_pipeline_table_entry);
958                         pp.lpm.offset = params->match.lpm.key_offset;
959
960                         p.ops = &rte_table_lpm_ops;
961                         p.arg_create = &pp.lpm;
962                         break;
963                 }
964
965                 case 16:
966                 {
967                         pp.lpm_ipv6.name = name;
968                         pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
969                         pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
970                         pp.lpm_ipv6.entry_unique_size = p.action_data_size +
971                                 sizeof(struct rte_pipeline_table_entry);
972                         pp.lpm_ipv6.offset = params->match.lpm.key_offset;
973
974                         p.ops = &rte_table_lpm_ipv6_ops;
975                         p.arg_create = &pp.lpm_ipv6;
976                         break;
977                 }
978
979                 default:
980                         return -1;
981                 }
982
983                 break;
984         }
985
986         case TABLE_STUB:
987         {
988                 p.ops = &rte_table_stub_ops;
989                 p.arg_create = NULL;
990                 break;
991         }
992
993         default:
994                 return -1;
995         }
996
997         /* Resource create */
998         action = NULL;
999         p.f_action_hit = NULL;
1000         p.f_action_miss = NULL;
1001         p.arg_ah = NULL;
1002
1003         if (ap) {
1004                 action = rte_table_action_create(ap->ap,
1005                         pipeline->cpu_id);
1006                 if (action == NULL)
1007                         return -1;
1008
1009                 status = rte_table_action_table_params_get(
1010                         action,
1011                         &p);
1012                 if (status ||
1013                         ((p.action_data_size +
1014                         sizeof(struct rte_pipeline_table_entry)) >
1015                         TABLE_RULE_ACTION_SIZE_MAX)) {
1016                         rte_table_action_free(action);
1017                         return -1;
1018                 }
1019         }
1020
1021         if (params->match_type == TABLE_LPM) {
1022                 if (params->match.lpm.key_size == 4)
1023                         pp.lpm.entry_unique_size = p.action_data_size +
1024                                 sizeof(struct rte_pipeline_table_entry);
1025
1026                 if (params->match.lpm.key_size == 16)
1027                         pp.lpm_ipv6.entry_unique_size = p.action_data_size +
1028                                 sizeof(struct rte_pipeline_table_entry);
1029         }
1030
1031         status = rte_pipeline_table_create(pipeline->p,
1032                 &p,
1033                 &table_id);
1034         if (status) {
1035                 rte_table_action_free(action);
1036                 return -1;
1037         }
1038
1039         /* Pipeline */
1040         table = &pipeline->table[pipeline->n_tables];
1041         memcpy(&table->params, params, sizeof(*params));
1042         table->ap = ap;
1043         table->a = action;
1044         pipeline->n_tables++;
1045
1046         return 0;
1047 }