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