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