36d92c9f5f8ce25d4439d130151215fc12f69477
[dpdk.git] / lib / librte_pipeline / rte_pipeline.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <stdio.h>
36
37 #include <rte_common.h>
38 #include <rte_memory.h>
39 #include <rte_memzone.h>
40 #include <rte_cycles.h>
41 #include <rte_prefetch.h>
42 #include <rte_branch_prediction.h>
43 #include <rte_mbuf.h>
44 #include <rte_malloc.h>
45 #include <rte_string_fns.h>
46
47 #include "rte_pipeline.h"
48
49 #define RTE_TABLE_INVALID                                 UINT32_MAX
50
51 struct rte_port_in {
52         /* Input parameters */
53         struct rte_port_in_ops ops;
54         rte_pipeline_port_in_action_handler f_action;
55         void *arg_ah;
56         uint32_t burst_size;
57
58         /* The table to which this port is connected */
59         uint32_t table_id;
60
61         /* Handle to low-level port */
62         void *h_port;
63
64         /* List of enabled ports */
65         struct rte_port_in *next;
66 };
67
68 struct rte_port_out {
69         /* Input parameters */
70         struct rte_port_out_ops ops;
71         rte_pipeline_port_out_action_handler f_action;
72         rte_pipeline_port_out_action_handler_bulk f_action_bulk;
73         void *arg_ah;
74
75         /* Handle to low-level port */
76         void *h_port;
77 };
78
79 struct rte_table {
80         /* Input parameters */
81         struct rte_table_ops ops;
82         rte_pipeline_table_action_handler_hit f_action_hit;
83         rte_pipeline_table_action_handler_miss f_action_miss;
84         void *arg_ah;
85         struct rte_pipeline_table_entry *default_entry;
86         uint32_t entry_size;
87
88         uint32_t table_next_id;
89         uint32_t table_next_id_valid;
90
91         /* Handle to the low-level table object */
92         void *h_table;
93 };
94
95 #define RTE_PIPELINE_MAX_NAME_SZ                           124
96
97 struct rte_pipeline {
98         /* Input parameters */
99         char name[RTE_PIPELINE_MAX_NAME_SZ];
100         int socket_id;
101         uint32_t offset_port_id;
102
103         /* Internal tables */
104         struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
105         struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
106         struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
107
108         /* Occupancy of internal tables */
109         uint32_t num_ports_in;
110         uint32_t num_ports_out;
111         uint32_t num_tables;
112
113         /* List of enabled ports */
114         uint64_t enabled_port_in_mask;
115         struct rte_port_in *port_in_first;
116
117         /* Pipeline run structures */
118         struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
119         struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
120         uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
121         uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
122 } __rte_cache_aligned;
123
124 static inline uint32_t
125 rte_mask_get_next(uint64_t mask, uint32_t pos)
126 {
127         uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
128                         (mask >> ((pos + 1) & 0x3F));
129         return (__builtin_ctzll(mask_rot) - (63 - pos)) & 0x3F;
130 }
131
132 static inline uint32_t
133 rte_mask_get_prev(uint64_t mask, uint32_t pos)
134 {
135         uint64_t mask_rot = (mask >> (pos & 0x3F)) |
136                         (mask << ((64 - pos) & 0x3F));
137         return ((63 - __builtin_clzll(mask_rot)) + pos) & 0x3F;
138 }
139
140 static void
141 rte_pipeline_table_free(struct rte_table *table);
142
143 static void
144 rte_pipeline_port_in_free(struct rte_port_in *port);
145
146 static void
147 rte_pipeline_port_out_free(struct rte_port_out *port);
148
149 /*
150  * Pipeline
151  *
152  */
153 static int
154 rte_pipeline_check_params(struct rte_pipeline_params *params)
155 {
156         if (params == NULL) {
157                 RTE_LOG(ERR, PIPELINE,
158                         "%s: Incorrect value for parameter params\n", __func__);
159                 return -EINVAL;
160         }
161
162         /* name */
163         if (params->name == NULL) {
164                 RTE_LOG(ERR, PIPELINE,
165                         "%s: Incorrect value for parameter name\n", __func__);
166                 return -EINVAL;
167         }
168
169         /* socket */
170         if ((params->socket_id < 0) ||
171             (params->socket_id >= RTE_MAX_NUMA_NODES)) {
172                 RTE_LOG(ERR, PIPELINE,
173                         "%s: Incorrect value for parameter socket_id\n",
174                         __func__);
175                 return -EINVAL;
176         }
177
178         /* offset_port_id */
179         if (params->offset_port_id & 0x3) {
180                 RTE_LOG(ERR, PIPELINE,
181                         "%s: Incorrect value for parameter offset_port_id\n",
182                         __func__);
183                 return -EINVAL;
184         }
185
186         return 0;
187 }
188
189 struct rte_pipeline *
190 rte_pipeline_create(struct rte_pipeline_params *params)
191 {
192         struct rte_pipeline *p;
193         int status;
194
195         /* Check input parameters */
196         status = rte_pipeline_check_params(params);
197         if (status != 0) {
198                 RTE_LOG(ERR, PIPELINE,
199                         "%s: Pipeline params check failed (%d)\n",
200                         __func__, status);
201                 return NULL;
202         }
203
204         /* Allocate memory for the pipeline on requested socket */
205         p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
206                         RTE_CACHE_LINE_SIZE, params->socket_id);
207
208         if (p == NULL) {
209                 RTE_LOG(ERR, PIPELINE,
210                         "%s: Pipeline memory allocation failed\n", __func__);
211                 return NULL;
212         }
213
214         /* Save input parameters */
215         snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
216         p->socket_id = params->socket_id;
217         p->offset_port_id = params->offset_port_id;
218
219         /* Initialize pipeline internal data structure */
220         p->num_ports_in = 0;
221         p->num_ports_out = 0;
222         p->num_tables = 0;
223         p->enabled_port_in_mask = 0;
224         p->port_in_first = NULL;
225
226         return p;
227 }
228
229 int
230 rte_pipeline_free(struct rte_pipeline *p)
231 {
232         uint32_t i;
233
234         /* Check input parameters */
235         if (p == NULL) {
236                 RTE_LOG(ERR, PIPELINE,
237                         "%s: rte_pipeline parameter is NULL\n", __func__);
238                 return -EINVAL;
239         }
240
241         /* Free input ports */
242         for (i = 0; i < p->num_ports_in; i++) {
243                 struct rte_port_in *port = &p->ports_in[i];
244
245                 rte_pipeline_port_in_free(port);
246         }
247
248         /* Free tables */
249         for (i = 0; i < p->num_tables; i++) {
250                 struct rte_table *table = &p->tables[i];
251
252                 rte_pipeline_table_free(table);
253         }
254
255         /* Free output ports */
256         for (i = 0; i < p->num_ports_out; i++) {
257                 struct rte_port_out *port = &p->ports_out[i];
258
259                 rte_pipeline_port_out_free(port);
260         }
261
262         /* Free pipeline memory */
263         rte_free(p);
264
265         return 0;
266 }
267
268 /*
269  * Table
270  *
271  */
272 static int
273 rte_table_check_params(struct rte_pipeline *p,
274                 struct rte_pipeline_table_params *params,
275                 uint32_t *table_id)
276 {
277         if (p == NULL) {
278                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
279                         __func__);
280                 return -EINVAL;
281         }
282         if (params == NULL) {
283                 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
284                         __func__);
285                 return -EINVAL;
286         }
287         if (table_id == NULL) {
288                 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
289                         __func__);
290                 return -EINVAL;
291         }
292
293         /* ops */
294         if (params->ops == NULL) {
295                 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
296                         __func__);
297                 return -EINVAL;
298         }
299
300         if (params->ops->f_create == NULL) {
301                 RTE_LOG(ERR, PIPELINE,
302                         "%s: f_create function pointer is NULL\n", __func__);
303                 return -EINVAL;
304         }
305
306         if (params->ops->f_lookup == NULL) {
307                 RTE_LOG(ERR, PIPELINE,
308                         "%s: f_lookup function pointer is NULL\n", __func__);
309                 return -EINVAL;
310         }
311
312         /* De we have room for one more table? */
313         if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
314                 RTE_LOG(ERR, PIPELINE,
315                         "%s: Incorrect value for num_tables parameter\n",
316                         __func__);
317                 return -EINVAL;
318         }
319
320         return 0;
321 }
322
323 int
324 rte_pipeline_table_create(struct rte_pipeline *p,
325                 struct rte_pipeline_table_params *params,
326                 uint32_t *table_id)
327 {
328         struct rte_table *table;
329         struct rte_pipeline_table_entry *default_entry;
330         void *h_table;
331         uint32_t entry_size, id;
332         int status;
333
334         /* Check input arguments */
335         status = rte_table_check_params(p, params, table_id);
336         if (status != 0)
337                 return status;
338
339         id = p->num_tables;
340         table = &p->tables[id];
341
342         /* Allocate space for the default table entry */
343         entry_size = sizeof(struct rte_pipeline_table_entry) +
344                 params->action_data_size;
345         default_entry = (struct rte_pipeline_table_entry *) rte_zmalloc_socket(
346                 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
347         if (default_entry == NULL) {
348                 RTE_LOG(ERR, PIPELINE,
349                         "%s: Failed to allocate default entry\n", __func__);
350                 return -EINVAL;
351         }
352
353         /* Create the table */
354         h_table = params->ops->f_create(params->arg_create, p->socket_id,
355                 entry_size);
356         if (h_table == NULL) {
357                 rte_free(default_entry);
358                 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
359                 return -EINVAL;
360         }
361
362         /* Commit current table to the pipeline */
363         p->num_tables++;
364         *table_id = id;
365
366         /* Save input parameters */
367         memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
368         table->f_action_hit = params->f_action_hit;
369         table->f_action_miss = params->f_action_miss;
370         table->arg_ah = params->arg_ah;
371         table->entry_size = entry_size;
372
373         /* Clear the lookup miss actions (to be set later through API) */
374         table->default_entry = default_entry;
375         table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
376
377         /* Initialize table internal data structure */
378         table->h_table = h_table;
379         table->table_next_id = 0;
380         table->table_next_id_valid = 0;
381
382         return 0;
383 }
384
385 void
386 rte_pipeline_table_free(struct rte_table *table)
387 {
388         if (table->ops.f_free != NULL)
389                 table->ops.f_free(table->h_table);
390
391         rte_free(table->default_entry);
392 }
393
394 int
395 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
396         uint32_t table_id,
397         struct rte_pipeline_table_entry *default_entry,
398         struct rte_pipeline_table_entry **default_entry_ptr)
399 {
400         struct rte_table *table;
401
402         /* Check input arguments */
403         if (p == NULL) {
404                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
405                         __func__);
406                 return -EINVAL;
407         }
408
409         if (default_entry == NULL) {
410                 RTE_LOG(ERR, PIPELINE,
411                         "%s: default_entry parameter is NULL\n", __func__);
412                 return -EINVAL;
413         }
414
415         if (table_id >= p->num_tables) {
416                 RTE_LOG(ERR, PIPELINE,
417                         "%s: table_id %d out of range\n", __func__, table_id);
418                 return -EINVAL;
419         }
420
421         table = &p->tables[table_id];
422
423         if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
424                 table->table_next_id_valid &&
425                 (default_entry->table_id != table->table_next_id)) {
426                 RTE_LOG(ERR, PIPELINE,
427                         "%s: Tree-like topologies not allowed\n", __func__);
428                 return -EINVAL;
429         }
430
431         /* Set the lookup miss actions */
432         if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
433                 (table->table_next_id_valid == 0)) {
434                 table->table_next_id = default_entry->table_id;
435                 table->table_next_id_valid = 1;
436         }
437
438         memcpy(table->default_entry, default_entry, table->entry_size);
439
440         *default_entry_ptr = table->default_entry;
441         return 0;
442 }
443
444 int
445 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
446                 uint32_t table_id,
447                 struct rte_pipeline_table_entry *entry)
448 {
449         struct rte_table *table;
450
451         /* Check input arguments */
452         if (p == NULL) {
453                 RTE_LOG(ERR, PIPELINE,
454                         "%s: pipeline parameter is NULL\n", __func__);
455                 return -EINVAL;
456         }
457
458         if (table_id >= p->num_tables) {
459                 RTE_LOG(ERR, PIPELINE,
460                         "%s: table_id %d out of range\n", __func__, table_id);
461                 return -EINVAL;
462         }
463
464         table = &p->tables[table_id];
465
466         /* Save the current contents of the default entry */
467         if (entry)
468                 memcpy(entry, table->default_entry, table->entry_size);
469
470         /* Clear the lookup miss actions */
471         memset(table->default_entry, 0, table->entry_size);
472         table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
473
474         return 0;
475 }
476
477 int
478 rte_pipeline_table_entry_add(struct rte_pipeline *p,
479                 uint32_t table_id,
480                 void *key,
481                 struct rte_pipeline_table_entry *entry,
482                 int *key_found,
483                 struct rte_pipeline_table_entry **entry_ptr)
484 {
485         struct rte_table *table;
486
487         /* Check input arguments */
488         if (p == NULL) {
489                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
490                         __func__);
491                 return -EINVAL;
492         }
493
494         if (key == NULL) {
495                 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
496                 return -EINVAL;
497         }
498
499         if (entry == NULL) {
500                 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
501                         __func__);
502                 return -EINVAL;
503         }
504
505         if (table_id >= p->num_tables) {
506                 RTE_LOG(ERR, PIPELINE,
507                         "%s: table_id %d out of range\n", __func__, table_id);
508                 return -EINVAL;
509         }
510
511         table = &p->tables[table_id];
512
513         if (table->ops.f_add == NULL) {
514                 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
515                         __func__);
516                 return -EINVAL;
517         }
518
519         if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
520                 table->table_next_id_valid &&
521                 (entry->table_id != table->table_next_id)) {
522                 RTE_LOG(ERR, PIPELINE,
523                         "%s: Tree-like topologies not allowed\n", __func__);
524                 return -EINVAL;
525         }
526
527         /* Add entry */
528         if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
529                 (table->table_next_id_valid == 0)) {
530                 table->table_next_id = entry->table_id;
531                 table->table_next_id_valid = 1;
532         }
533
534         return (table->ops.f_add)(table->h_table, key, (void *) entry,
535                 key_found, (void **) entry_ptr);
536 }
537
538 int
539 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
540                 uint32_t table_id,
541                 void *key,
542                 int *key_found,
543                 struct rte_pipeline_table_entry *entry)
544 {
545         struct rte_table *table;
546
547         /* Check input arguments */
548         if (p == NULL) {
549                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
550                         __func__);
551                 return -EINVAL;
552         }
553
554         if (key == NULL) {
555                 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
556                         __func__);
557                 return -EINVAL;
558         }
559
560         if (table_id >= p->num_tables) {
561                 RTE_LOG(ERR, PIPELINE,
562                         "%s: table_id %d out of range\n", __func__, table_id);
563                 return -EINVAL;
564         }
565
566         table = &p->tables[table_id];
567
568         if (table->ops.f_delete == NULL) {
569                 RTE_LOG(ERR, PIPELINE,
570                         "%s: f_delete function pointer NULL\n", __func__);
571                 return -EINVAL;
572         }
573
574         return (table->ops.f_delete)(table->h_table, key, key_found, entry);
575 }
576
577 /*
578  * Port
579  *
580  */
581 static int
582 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
583                 struct rte_pipeline_port_in_params *params,
584                 uint32_t *port_id)
585 {
586         if (p == NULL) {
587                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
588                         __func__);
589                 return -EINVAL;
590         }
591         if (params == NULL) {
592                 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
593                 return -EINVAL;
594         }
595         if (port_id == NULL) {
596                 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
597                         __func__);
598                 return -EINVAL;
599         }
600
601         /* ops */
602         if (params->ops == NULL) {
603                 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
604                         __func__);
605                 return -EINVAL;
606         }
607
608         if (params->ops->f_create == NULL) {
609                 RTE_LOG(ERR, PIPELINE,
610                         "%s: f_create function pointer NULL\n", __func__);
611                 return -EINVAL;
612         }
613
614         if (params->ops->f_rx == NULL) {
615                 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
616                         __func__);
617                 return -EINVAL;
618         }
619
620         /* burst_size */
621         if ((params->burst_size == 0) ||
622                 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
623                 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
624                         __func__);
625                 return -EINVAL;
626         }
627
628         /* Do we have room for one more port? */
629         if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
630                 RTE_LOG(ERR, PIPELINE,
631                         "%s: invalid value for num_ports_in\n", __func__);
632                 return -EINVAL;
633         }
634
635         return 0;
636 }
637
638 static int
639 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
640                 struct rte_pipeline_port_out_params *params,
641                 uint32_t *port_id)
642 {
643         rte_pipeline_port_out_action_handler f_ah;
644         rte_pipeline_port_out_action_handler_bulk f_ah_bulk;
645
646         if (p == NULL) {
647                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
648                         __func__);
649                 return -EINVAL;
650         }
651
652         if (params == NULL) {
653                 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
654                 return -EINVAL;
655         }
656
657         if (port_id == NULL) {
658                 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
659                         __func__);
660                 return -EINVAL;
661         }
662
663         /* ops */
664         if (params->ops == NULL) {
665                 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
666                         __func__);
667                 return -EINVAL;
668         }
669
670         if (params->ops->f_create == NULL) {
671                 RTE_LOG(ERR, PIPELINE,
672                         "%s: f_create function pointer NULL\n", __func__);
673                 return -EINVAL;
674         }
675
676         if (params->ops->f_tx == NULL) {
677                 RTE_LOG(ERR, PIPELINE,
678                                 "%s: f_tx function pointer NULL\n", __func__);
679                 return -EINVAL;
680         }
681
682         if (params->ops->f_tx_bulk == NULL) {
683                 RTE_LOG(ERR, PIPELINE,
684                         "%s: f_tx_bulk function pointer NULL\n", __func__);
685                 return -EINVAL;
686         }
687
688         f_ah = params->f_action;
689         f_ah_bulk = params->f_action_bulk;
690         if (((f_ah != NULL) && (f_ah_bulk == NULL)) ||
691             ((f_ah == NULL) && (f_ah_bulk != NULL))) {
692                 RTE_LOG(ERR, PIPELINE, "%s: Action handlers have to be either"
693                         "both enabled or both disabled\n", __func__);
694                 return -EINVAL;
695         }
696
697         /* Do we have room for one more port? */
698         if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
699                 RTE_LOG(ERR, PIPELINE,
700                         "%s: invalid value for num_ports_out\n", __func__);
701                 return -EINVAL;
702         }
703
704         return 0;
705 }
706
707 int
708 rte_pipeline_port_in_create(struct rte_pipeline *p,
709                 struct rte_pipeline_port_in_params *params,
710                 uint32_t *port_id)
711 {
712         struct rte_port_in *port;
713         void *h_port;
714         uint32_t id;
715         int status;
716
717         /* Check input arguments */
718         status = rte_pipeline_port_in_check_params(p, params, port_id);
719         if (status != 0)
720                 return status;
721
722         id = p->num_ports_in;
723         port = &p->ports_in[id];
724
725         /* Create the port */
726         h_port = params->ops->f_create(params->arg_create, p->socket_id);
727         if (h_port == NULL) {
728                 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
729                 return -EINVAL;
730         }
731
732         /* Commit current table to the pipeline */
733         p->num_ports_in++;
734         *port_id = id;
735
736         /* Save input parameters */
737         memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
738         port->f_action = params->f_action;
739         port->arg_ah = params->arg_ah;
740         port->burst_size = params->burst_size;
741
742         /* Initialize port internal data structure */
743         port->table_id = RTE_TABLE_INVALID;
744         port->h_port = h_port;
745         port->next = NULL;
746
747         return 0;
748 }
749
750 void
751 rte_pipeline_port_in_free(struct rte_port_in *port)
752 {
753         if (port->ops.f_free != NULL)
754                 port->ops.f_free(port->h_port);
755 }
756
757 int
758 rte_pipeline_port_out_create(struct rte_pipeline *p,
759                 struct rte_pipeline_port_out_params *params,
760                 uint32_t *port_id)
761 {
762         struct rte_port_out *port;
763         void *h_port;
764         uint32_t id;
765         int status;
766
767         /* Check input arguments */
768         status = rte_pipeline_port_out_check_params(p, params, port_id);
769         if (status != 0)
770                 return status;
771
772         id = p->num_ports_out;
773         port = &p->ports_out[id];
774
775         /* Create the port */
776         h_port = params->ops->f_create(params->arg_create, p->socket_id);
777         if (h_port == NULL) {
778                 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
779                 return -EINVAL;
780         }
781
782         /* Commit current table to the pipeline */
783         p->num_ports_out++;
784         *port_id = id;
785
786         /* Save input parameters */
787         memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
788         port->f_action = params->f_action;
789         port->f_action_bulk = params->f_action_bulk;
790         port->arg_ah = params->arg_ah;
791
792         /* Initialize port internal data structure */
793         port->h_port = h_port;
794
795         return 0;
796 }
797
798 void
799 rte_pipeline_port_out_free(struct rte_port_out *port)
800 {
801         if (port->ops.f_free != NULL)
802                 port->ops.f_free(port->h_port);
803 }
804
805 int
806 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
807                 uint32_t port_id,
808                 uint32_t table_id)
809 {
810         struct rte_port_in *port;
811
812         /* Check input arguments */
813         if (p == NULL) {
814                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
815                         __func__);
816                 return -EINVAL;
817         }
818
819         if (port_id >= p->num_ports_in) {
820                 RTE_LOG(ERR, PIPELINE,
821                         "%s: port IN ID %u is out of range\n",
822                         __func__, port_id);
823                 return -EINVAL;
824         }
825
826         if (table_id >= p->num_tables) {
827                 RTE_LOG(ERR, PIPELINE,
828                         "%s: Table ID %u is out of range\n",
829                         __func__, table_id);
830                 return -EINVAL;
831         }
832
833         port = &p->ports_in[port_id];
834         port->table_id = table_id;
835
836         return 0;
837 }
838
839 int
840 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
841 {
842         struct rte_port_in *port, *port_prev, *port_next;
843         struct rte_port_in *port_first, *port_last;
844         uint64_t port_mask;
845         uint32_t port_prev_id, port_next_id, port_first_id, port_last_id;
846
847         /* Check input arguments */
848         if (p == NULL) {
849                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
850                         __func__);
851                 return -EINVAL;
852         }
853
854         if (port_id >= p->num_ports_in) {
855                 RTE_LOG(ERR, PIPELINE,
856                         "%s: port IN ID %u is out of range\n",
857                         __func__, port_id);
858                 return -EINVAL;
859         }
860
861         /* Return if current input port is already enabled */
862         port_mask = 1LLU << port_id;
863         if (p->enabled_port_in_mask & port_mask)
864                 return 0;
865
866         p->enabled_port_in_mask |= port_mask;
867
868         /* Add current input port to the pipeline chain of enabled ports */
869         port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
870         port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
871
872         port_prev = &p->ports_in[port_prev_id];
873         port_next = &p->ports_in[port_next_id];
874         port = &p->ports_in[port_id];
875
876         port_prev->next = port;
877         port->next = port_next;
878
879         /* Update the first and last input ports in the chain */
880         port_first_id = __builtin_ctzll(p->enabled_port_in_mask);
881         port_last_id = 63 - __builtin_clzll(p->enabled_port_in_mask);
882
883         port_first = &p->ports_in[port_first_id];
884         port_last = &p->ports_in[port_last_id];
885
886         p->port_in_first = port_first;
887         port_last->next = NULL;
888
889         return 0;
890 }
891
892 int
893 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
894 {
895         struct rte_port_in *port_prev, *port_next, *port_first, *port_last;
896         uint64_t port_mask;
897         uint32_t port_prev_id, port_next_id, port_first_id, port_last_id;
898
899         /* Check input arguments */
900         if (p == NULL) {
901                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
902                 __func__);
903                 return -EINVAL;
904         }
905
906         if (port_id >= p->num_ports_in) {
907                 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
908                         __func__, port_id);
909                 return -EINVAL;
910         }
911
912         /* Return if current input port is already disabled */
913         port_mask = 1LLU << port_id;
914         if ((p->enabled_port_in_mask & port_mask) == 0)
915                 return 0;
916
917         /* Return if no other enabled ports */
918         if (__builtin_popcountll(p->enabled_port_in_mask) == 1) {
919                 p->enabled_port_in_mask &= ~port_mask;
920                 p->port_in_first = NULL;
921
922                 return 0;
923         }
924
925         /* Add current input port to the pipeline chain of enabled ports */
926         port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
927         port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
928
929         port_prev = &p->ports_in[port_prev_id];
930         port_next = &p->ports_in[port_next_id];
931
932         port_prev->next = port_next;
933         p->enabled_port_in_mask &= ~port_mask;
934
935         /* Update the first and last input ports in the chain */
936         port_first_id = __builtin_ctzll(p->enabled_port_in_mask);
937         port_last_id = 63 - __builtin_clzll(p->enabled_port_in_mask);
938
939         port_first = &p->ports_in[port_first_id];
940         port_last = &p->ports_in[port_last_id];
941
942         p->port_in_first = port_first;
943         port_last->next = NULL;
944
945         return 0;
946 }
947
948 /*
949  * Pipeline run-time
950  *
951  */
952 int
953 rte_pipeline_check(struct rte_pipeline *p)
954 {
955         uint32_t port_in_id;
956
957         /* Check input arguments */
958         if (p == NULL) {
959                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
960                         __func__);
961                 return -EINVAL;
962         }
963
964         /* Check that pipeline has at least one input port, one table and one
965         output port */
966         if (p->num_ports_in == 0) {
967                 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
968                         __func__);
969                 return -EINVAL;
970         }
971         if (p->num_tables == 0) {
972                 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
973                         __func__);
974                 return -EINVAL;
975         }
976         if (p->num_ports_out == 0) {
977                 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
978                         __func__);
979                 return -EINVAL;
980         }
981
982         /* Check that all input ports are connected */
983         for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
984                 struct rte_port_in *port_in = &p->ports_in[port_in_id];
985
986                 if (port_in->table_id == RTE_TABLE_INVALID) {
987                         RTE_LOG(ERR, PIPELINE,
988                                 "%s: Port IN ID %u is not connected\n",
989                                 __func__, port_in_id);
990                         return -EINVAL;
991                 }
992         }
993
994         return 0;
995 }
996
997 static inline void
998 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
999 {
1000         p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1001         p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1002         p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
1003         p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1004
1005         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1006                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1007                 uint32_t i;
1008
1009                 for (i = 0; i < n_pkts; i++) {
1010                         uint64_t pkt_mask = 1LLU << i;
1011                         uint32_t pos = p->entries[i]->action;
1012
1013                         p->action_mask1[pos] |= pkt_mask;
1014                 }
1015         } else {
1016                 uint32_t i;
1017
1018                 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1019                         uint64_t pkt_mask = 1LLU << i;
1020                         uint32_t pos;
1021
1022                         if ((pkt_mask & pkts_mask) == 0)
1023                                 continue;
1024
1025                         pos = p->entries[i]->action;
1026                         p->action_mask1[pos] |= pkt_mask;
1027                 }
1028         }
1029 }
1030
1031 static inline void
1032 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1033                 uint64_t pkts_mask, uint32_t port_id)
1034 {
1035         struct rte_port_out *port_out = &p->ports_out[port_id];
1036
1037         /* Output port user actions */
1038         if (port_out->f_action_bulk != NULL) {
1039                 uint64_t mask = pkts_mask;
1040
1041                 port_out->f_action_bulk(p->pkts, &pkts_mask, port_out->arg_ah);
1042                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask ^  mask;
1043         }
1044
1045         /* Output port TX */
1046         if (pkts_mask != 0)
1047                 port_out->ops.f_tx_bulk(port_out->h_port, p->pkts, pkts_mask);
1048 }
1049
1050 static inline void
1051 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1052 {
1053         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1054                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1055                 uint32_t i;
1056
1057                 for (i = 0; i < n_pkts; i++) {
1058                         struct rte_mbuf *pkt = p->pkts[i];
1059                         uint32_t port_out_id = p->entries[i]->port_id;
1060                         struct rte_port_out *port_out =
1061                                 &p->ports_out[port_out_id];
1062
1063                         /* Output port user actions */
1064                         if (port_out->f_action == NULL) /* Output port TX */
1065                                 port_out->ops.f_tx(port_out->h_port, pkt);
1066                         else {
1067                                 uint64_t pkt_mask = 1LLU;
1068
1069                                 port_out->f_action(pkt, &pkt_mask,
1070                                         port_out->arg_ah);
1071                                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1072                                         (pkt_mask ^ 1LLU) << i;
1073
1074                                 /* Output port TX */
1075                                 if (pkt_mask != 0)
1076                                         port_out->ops.f_tx(port_out->h_port,
1077                                                 pkt);
1078                         }
1079                 }
1080         } else {
1081                 uint32_t i;
1082
1083                 for (i = 0;  i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1084                         uint64_t pkt_mask = 1LLU << i;
1085                         struct rte_mbuf *pkt;
1086                         struct rte_port_out *port_out;
1087                         uint32_t port_out_id;
1088
1089                         if ((pkt_mask & pkts_mask) == 0)
1090                                 continue;
1091
1092                         pkt = p->pkts[i];
1093                         port_out_id = p->entries[i]->port_id;
1094                         port_out = &p->ports_out[port_out_id];
1095
1096                         /* Output port user actions */
1097                         if (port_out->f_action == NULL) /* Output port TX */
1098                                 port_out->ops.f_tx(port_out->h_port, pkt);
1099                         else {
1100                                 pkt_mask = 1LLU;
1101
1102                                 port_out->f_action(pkt, &pkt_mask,
1103                                         port_out->arg_ah);
1104                                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1105                                         (pkt_mask ^ 1LLU) << i;
1106
1107                                 /* Output port TX */
1108                                 if (pkt_mask != 0)
1109                                         port_out->ops.f_tx(port_out->h_port,
1110                                                 pkt);
1111                         }
1112                 }
1113         }
1114 }
1115
1116 static inline void
1117 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1118         uint64_t pkts_mask)
1119 {
1120         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1121                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1122                 uint32_t i;
1123
1124                 for (i = 0; i < n_pkts; i++) {
1125                         struct rte_mbuf *pkt = p->pkts[i];
1126                         uint32_t port_out_id =
1127                                 RTE_MBUF_METADATA_UINT32(pkt,
1128                                         p->offset_port_id);
1129                         struct rte_port_out *port_out = &p->ports_out[
1130                                 port_out_id];
1131
1132                         /* Output port user actions */
1133                         if (port_out->f_action == NULL) /* Output port TX */
1134                                 port_out->ops.f_tx(port_out->h_port, pkt);
1135                         else {
1136                                 uint64_t pkt_mask = 1LLU;
1137
1138                                 port_out->f_action(pkt, &pkt_mask,
1139                                         port_out->arg_ah);
1140                                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1141                                         (pkt_mask ^ 1LLU) << i;
1142
1143                                 /* Output port TX */
1144                                 if (pkt_mask != 0)
1145                                         port_out->ops.f_tx(port_out->h_port,
1146                                                 pkt);
1147                         }
1148                 }
1149         } else {
1150                 uint32_t i;
1151
1152                 for (i = 0;  i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1153                         uint64_t pkt_mask = 1LLU << i;
1154                         struct rte_mbuf *pkt;
1155                         struct rte_port_out *port_out;
1156                         uint32_t port_out_id;
1157
1158                         if ((pkt_mask & pkts_mask) == 0)
1159                                 continue;
1160
1161                         pkt = p->pkts[i];
1162                         port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1163                                 p->offset_port_id);
1164                         port_out = &p->ports_out[port_out_id];
1165
1166                         /* Output port user actions */
1167                         if (port_out->f_action == NULL) /* Output port TX */
1168                                 port_out->ops.f_tx(port_out->h_port, pkt);
1169                         else {
1170                                 pkt_mask = 1LLU;
1171
1172                                 port_out->f_action(pkt, &pkt_mask,
1173                                         port_out->arg_ah);
1174                                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1175                                         (pkt_mask ^ 1LLU) << i;
1176
1177                                 /* Output port TX */
1178                                 if (pkt_mask != 0)
1179                                         port_out->ops.f_tx(port_out->h_port,
1180                                                 pkt);
1181                         }
1182                 }
1183         }
1184 }
1185
1186 static inline void
1187 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1188 {
1189         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1190                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1191                 uint32_t i;
1192
1193                 for (i = 0; i < n_pkts; i++)
1194                         rte_pktmbuf_free(p->pkts[i]);
1195         } else {
1196                 uint32_t i;
1197
1198                 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1199                         uint64_t pkt_mask = 1LLU << i;
1200
1201                         if ((pkt_mask & pkts_mask) == 0)
1202                                 continue;
1203
1204                         rte_pktmbuf_free(p->pkts[i]);
1205                 }
1206         }
1207 }
1208
1209 int
1210 rte_pipeline_run(struct rte_pipeline *p)
1211 {
1212         struct rte_port_in *port_in;
1213
1214         for (port_in = p->port_in_first; port_in != NULL;
1215                 port_in = port_in->next) {
1216                 uint64_t pkts_mask;
1217                 uint32_t n_pkts, table_id;
1218
1219                 /* Input port RX */
1220                 n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1221                         port_in->burst_size);
1222                 if (n_pkts == 0)
1223                         continue;
1224
1225                 pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1226                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1227                 p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1228                 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1229                 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1230
1231                 /* Input port user actions */
1232                 if (port_in->f_action != NULL) {
1233                         uint64_t mask = pkts_mask;
1234
1235                         port_in->f_action(p->pkts, n_pkts, &pkts_mask,
1236                                 port_in->arg_ah);
1237                         p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1238                                 pkts_mask ^ mask;
1239                 }
1240
1241                 /* Table */
1242                 for (table_id = port_in->table_id; pkts_mask != 0; ) {
1243                         struct rte_table *table;
1244                         uint64_t lookup_hit_mask, lookup_miss_mask;
1245
1246                         /* Lookup */
1247                         table = &p->tables[table_id];
1248                         table->ops.f_lookup(table->h_table, p->pkts, pkts_mask,
1249                                         &lookup_hit_mask, (void **) p->entries);
1250                         lookup_miss_mask = pkts_mask & (~lookup_hit_mask);
1251
1252                         /* Lookup miss */
1253                         if (lookup_miss_mask != 0) {
1254                                 struct rte_pipeline_table_entry *default_entry =
1255                                         table->default_entry;
1256
1257                                 /* Table user actions */
1258                                 if (table->f_action_miss != NULL) {
1259                                         uint64_t mask = lookup_miss_mask;
1260
1261                                         table->f_action_miss(p->pkts,
1262                                                 &lookup_miss_mask,
1263                                                 default_entry, table->arg_ah);
1264                                         p->action_mask0[
1265                                                 RTE_PIPELINE_ACTION_DROP] |=
1266                                                 lookup_miss_mask ^ mask;
1267                                 }
1268
1269                                 /* Table reserved actions */
1270                                 if ((default_entry->action ==
1271                                         RTE_PIPELINE_ACTION_PORT) &&
1272                                         (lookup_miss_mask != 0))
1273                                         rte_pipeline_action_handler_port_bulk(p,
1274                                                 lookup_miss_mask,
1275                                                 default_entry->port_id);
1276                                 else {
1277                                         uint32_t pos = default_entry->action;
1278
1279                                         p->action_mask0[pos] = lookup_miss_mask;
1280                                 }
1281                         }
1282
1283                         /* Lookup hit */
1284                         if (lookup_hit_mask != 0) {
1285                                 /* Table user actions */
1286                                 if (table->f_action_hit != NULL) {
1287                                         uint64_t mask = lookup_hit_mask;
1288
1289                                         table->f_action_hit(p->pkts,
1290                                                 &lookup_hit_mask,
1291                                                 p->entries, table->arg_ah);
1292                                         p->action_mask0[
1293                                                 RTE_PIPELINE_ACTION_DROP] |=
1294                                                 lookup_hit_mask ^ mask;
1295                                 }
1296
1297                                 /* Table reserved actions */
1298                                 rte_pipeline_compute_masks(p, lookup_hit_mask);
1299                                 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1300                                         p->action_mask1[
1301                                                 RTE_PIPELINE_ACTION_DROP];
1302                                 p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1303                                         p->action_mask1[
1304                                                 RTE_PIPELINE_ACTION_PORT];
1305                                 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1306                                         p->action_mask1[
1307                                                 RTE_PIPELINE_ACTION_PORT_META];
1308                                 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1309                                         p->action_mask1[
1310                                                 RTE_PIPELINE_ACTION_TABLE];
1311                         }
1312
1313                         /* Prepare for next iteration */
1314                         pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1315                         table_id = table->table_next_id;
1316                         p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1317                 }
1318
1319                 /* Table reserved action PORT */
1320                 rte_pipeline_action_handler_port(p,
1321                                 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1322
1323                 /* Table reserved action PORT META */
1324                 rte_pipeline_action_handler_port_meta(p,
1325                                 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1326
1327                 /* Table reserved action DROP */
1328                 rte_pipeline_action_handler_drop(p,
1329                                 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1330         }
1331
1332         return 0;
1333 }
1334
1335 int
1336 rte_pipeline_flush(struct rte_pipeline *p)
1337 {
1338         uint32_t port_id;
1339
1340         /* Check input arguments */
1341         if (p == NULL) {
1342                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1343                         __func__);
1344                 return -EINVAL;
1345         }
1346
1347         for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1348                 struct rte_port_out *port = &p->ports_out[port_id];
1349
1350                 if (port->ops.f_flush != NULL)
1351                         port->ops.f_flush(port->h_port);
1352         }
1353
1354         return 0;
1355 }
1356
1357 int
1358 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1359                 uint32_t port_id, struct rte_mbuf *pkt)
1360 {
1361         struct rte_port_out *port_out = &p->ports_out[port_id];
1362
1363         /* Output port user actions */
1364         if (port_out->f_action == NULL)
1365                 port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1366         else {
1367                 uint64_t pkt_mask = 1LLU;
1368
1369                 port_out->f_action(pkt, &pkt_mask, port_out->arg_ah);
1370
1371                 if (pkt_mask != 0) /* Output port TX */
1372                         port_out->ops.f_tx(port_out->h_port, pkt);
1373                 else
1374                         rte_pktmbuf_free(pkt);
1375         }
1376
1377         return 0;
1378 }