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