New upstream version 18.11-rc1
[deb_dpdk.git] / lib / librte_pipeline / rte_pipeline.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <stdio.h>
7
8 #include <rte_common.h>
9 #include <rte_memory.h>
10 #include <rte_cycles.h>
11 #include <rte_prefetch.h>
12 #include <rte_branch_prediction.h>
13 #include <rte_mbuf.h>
14 #include <rte_malloc.h>
15 #include <rte_string_fns.h>
16
17 #include "rte_pipeline.h"
18
19 #define RTE_TABLE_INVALID                                 UINT32_MAX
20
21 #ifdef RTE_PIPELINE_STATS_COLLECT
22
23 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask)                       \
24         ({ (p)->n_pkts_ah_drop = __builtin_popcountll(mask); })
25
26 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter)                     \
27         ({ (counter) += (p)->n_pkts_ah_drop; (p)->n_pkts_ah_drop = 0; })
28
29 #define RTE_PIPELINE_STATS_TABLE_DROP0(p)                               \
30         ({ (p)->pkts_drop_mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; })
31
32 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter)                      \
33 ({                                                                      \
34         uint64_t mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP];    \
35         mask ^= (p)->pkts_drop_mask;                                    \
36         (counter) += __builtin_popcountll(mask);                        \
37 })
38
39 #else
40
41 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask)
42 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter)
43 #define RTE_PIPELINE_STATS_TABLE_DROP0(p)
44 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter)
45
46 #endif
47
48 struct rte_port_in {
49         /* Input parameters */
50         struct rte_port_in_ops ops;
51         rte_pipeline_port_in_action_handler f_action;
52         void *arg_ah;
53         uint32_t burst_size;
54
55         /* The table to which this port is connected */
56         uint32_t table_id;
57
58         /* Handle to low-level port */
59         void *h_port;
60
61         /* List of enabled ports */
62         struct rte_port_in *next;
63
64         /* Statistics */
65         uint64_t n_pkts_dropped_by_ah;
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         void *arg_ah;
73
74         /* Handle to low-level port */
75         void *h_port;
76
77         /* Statistics */
78         uint64_t n_pkts_dropped_by_ah;
79 };
80
81 struct rte_table {
82         /* Input parameters */
83         struct rte_table_ops ops;
84         rte_pipeline_table_action_handler_hit f_action_hit;
85         rte_pipeline_table_action_handler_miss f_action_miss;
86         void *arg_ah;
87         struct rte_pipeline_table_entry *default_entry;
88         uint32_t entry_size;
89
90         uint32_t table_next_id;
91         uint32_t table_next_id_valid;
92
93         /* Handle to the low-level table object */
94         void *h_table;
95
96         /* Statistics */
97         uint64_t n_pkts_dropped_by_lkp_hit_ah;
98         uint64_t n_pkts_dropped_by_lkp_miss_ah;
99         uint64_t n_pkts_dropped_lkp_hit;
100         uint64_t n_pkts_dropped_lkp_miss;
101 };
102
103 #define RTE_PIPELINE_MAX_NAME_SZ                           124
104
105 struct rte_pipeline {
106         /* Input parameters */
107         char name[RTE_PIPELINE_MAX_NAME_SZ];
108         int socket_id;
109         uint32_t offset_port_id;
110
111         /* Internal tables */
112         struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
113         struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
114         struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
115
116         /* Occupancy of internal tables */
117         uint32_t num_ports_in;
118         uint32_t num_ports_out;
119         uint32_t num_tables;
120
121         /* List of enabled ports */
122         uint64_t enabled_port_in_mask;
123         struct rte_port_in *port_in_next;
124
125         /* Pipeline run structures */
126         struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
127         struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
128         uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
129         uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
130         uint64_t pkts_mask;
131         uint64_t n_pkts_ah_drop;
132         uint64_t pkts_drop_mask;
133 } __rte_cache_aligned;
134
135 static inline uint32_t
136 rte_mask_get_next(uint64_t mask, uint32_t pos)
137 {
138         uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
139                         (mask >> ((pos + 1) & 0x3F));
140         return (__builtin_ctzll(mask_rot) - (63 - pos)) & 0x3F;
141 }
142
143 static inline uint32_t
144 rte_mask_get_prev(uint64_t mask, uint32_t pos)
145 {
146         uint64_t mask_rot = (mask >> (pos & 0x3F)) |
147                         (mask << ((64 - pos) & 0x3F));
148         return ((63 - __builtin_clzll(mask_rot)) + pos) & 0x3F;
149 }
150
151 static void
152 rte_pipeline_table_free(struct rte_table *table);
153
154 static void
155 rte_pipeline_port_in_free(struct rte_port_in *port);
156
157 static void
158 rte_pipeline_port_out_free(struct rte_port_out *port);
159
160 /*
161  * Pipeline
162  *
163  */
164 static int
165 rte_pipeline_check_params(struct rte_pipeline_params *params)
166 {
167         if (params == NULL) {
168                 RTE_LOG(ERR, PIPELINE,
169                         "%s: Incorrect value for parameter params\n", __func__);
170                 return -EINVAL;
171         }
172
173         /* name */
174         if (params->name == NULL) {
175                 RTE_LOG(ERR, PIPELINE,
176                         "%s: Incorrect value for parameter name\n", __func__);
177                 return -EINVAL;
178         }
179
180         /* socket */
181         if (params->socket_id < 0) {
182                 RTE_LOG(ERR, PIPELINE,
183                         "%s: Incorrect value for parameter socket_id\n",
184                         __func__);
185                 return -EINVAL;
186         }
187
188         return 0;
189 }
190
191 struct rte_pipeline *
192 rte_pipeline_create(struct rte_pipeline_params *params)
193 {
194         struct rte_pipeline *p;
195         int status;
196
197         /* Check input parameters */
198         status = rte_pipeline_check_params(params);
199         if (status != 0) {
200                 RTE_LOG(ERR, PIPELINE,
201                         "%s: Pipeline params check failed (%d)\n",
202                         __func__, status);
203                 return NULL;
204         }
205
206         /* Allocate memory for the pipeline on requested socket */
207         p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
208                         RTE_CACHE_LINE_SIZE, params->socket_id);
209
210         if (p == NULL) {
211                 RTE_LOG(ERR, PIPELINE,
212                         "%s: Pipeline memory allocation failed\n", __func__);
213                 return NULL;
214         }
215
216         /* Save input parameters */
217         snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
218         p->socket_id = params->socket_id;
219         p->offset_port_id = params->offset_port_id;
220
221         /* Initialize pipeline internal data structure */
222         p->num_ports_in = 0;
223         p->num_ports_out = 0;
224         p->num_tables = 0;
225         p->enabled_port_in_mask = 0;
226         p->port_in_next = NULL;
227         p->pkts_mask = 0;
228         p->n_pkts_ah_drop = 0;
229
230         return p;
231 }
232
233 int
234 rte_pipeline_free(struct rte_pipeline *p)
235 {
236         uint32_t i;
237
238         /* Check input parameters */
239         if (p == NULL) {
240                 RTE_LOG(ERR, PIPELINE,
241                         "%s: rte_pipeline parameter is NULL\n", __func__);
242                 return -EINVAL;
243         }
244
245         /* Free input ports */
246         for (i = 0; i < p->num_ports_in; i++) {
247                 struct rte_port_in *port = &p->ports_in[i];
248
249                 rte_pipeline_port_in_free(port);
250         }
251
252         /* Free tables */
253         for (i = 0; i < p->num_tables; i++) {
254                 struct rte_table *table = &p->tables[i];
255
256                 rte_pipeline_table_free(table);
257         }
258
259         /* Free output ports */
260         for (i = 0; i < p->num_ports_out; i++) {
261                 struct rte_port_out *port = &p->ports_out[i];
262
263                 rte_pipeline_port_out_free(port);
264         }
265
266         /* Free pipeline memory */
267         rte_free(p);
268
269         return 0;
270 }
271
272 /*
273  * Table
274  *
275  */
276 static int
277 rte_table_check_params(struct rte_pipeline *p,
278                 struct rte_pipeline_table_params *params,
279                 uint32_t *table_id)
280 {
281         if (p == NULL) {
282                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
283                         __func__);
284                 return -EINVAL;
285         }
286         if (params == NULL) {
287                 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
288                         __func__);
289                 return -EINVAL;
290         }
291         if (table_id == NULL) {
292                 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
293                         __func__);
294                 return -EINVAL;
295         }
296
297         /* ops */
298         if (params->ops == NULL) {
299                 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
300                         __func__);
301                 return -EINVAL;
302         }
303
304         if (params->ops->f_create == NULL) {
305                 RTE_LOG(ERR, PIPELINE,
306                         "%s: f_create function pointer is NULL\n", __func__);
307                 return -EINVAL;
308         }
309
310         if (params->ops->f_lookup == NULL) {
311                 RTE_LOG(ERR, PIPELINE,
312                         "%s: f_lookup function pointer is NULL\n", __func__);
313                 return -EINVAL;
314         }
315
316         /* De we have room for one more table? */
317         if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
318                 RTE_LOG(ERR, PIPELINE,
319                         "%s: Incorrect value for num_tables parameter\n",
320                         __func__);
321                 return -EINVAL;
322         }
323
324         return 0;
325 }
326
327 int
328 rte_pipeline_table_create(struct rte_pipeline *p,
329                 struct rte_pipeline_table_params *params,
330                 uint32_t *table_id)
331 {
332         struct rte_table *table;
333         struct rte_pipeline_table_entry *default_entry;
334         void *h_table;
335         uint32_t entry_size, id;
336         int status;
337
338         /* Check input arguments */
339         status = rte_table_check_params(p, params, table_id);
340         if (status != 0)
341                 return status;
342
343         id = p->num_tables;
344         table = &p->tables[id];
345
346         /* Allocate space for the default table entry */
347         entry_size = sizeof(struct rte_pipeline_table_entry) +
348                 params->action_data_size;
349         default_entry = rte_zmalloc_socket(
350                 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
351         if (default_entry == NULL) {
352                 RTE_LOG(ERR, PIPELINE,
353                         "%s: Failed to allocate default entry\n", __func__);
354                 return -EINVAL;
355         }
356
357         /* Create the table */
358         h_table = params->ops->f_create(params->arg_create, p->socket_id,
359                 entry_size);
360         if (h_table == NULL) {
361                 rte_free(default_entry);
362                 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
363                 return -EINVAL;
364         }
365
366         /* Commit current table to the pipeline */
367         p->num_tables++;
368         *table_id = id;
369
370         /* Save input parameters */
371         memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
372         table->f_action_hit = params->f_action_hit;
373         table->f_action_miss = params->f_action_miss;
374         table->arg_ah = params->arg_ah;
375         table->entry_size = entry_size;
376
377         /* Clear the lookup miss actions (to be set later through API) */
378         table->default_entry = default_entry;
379         table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
380
381         /* Initialize table internal data structure */
382         table->h_table = h_table;
383         table->table_next_id = 0;
384         table->table_next_id_valid = 0;
385
386         return 0;
387 }
388
389 void
390 rte_pipeline_table_free(struct rte_table *table)
391 {
392         if (table->ops.f_free != NULL)
393                 table->ops.f_free(table->h_table);
394
395         rte_free(table->default_entry);
396 }
397
398 int
399 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
400         uint32_t table_id,
401         struct rte_pipeline_table_entry *default_entry,
402         struct rte_pipeline_table_entry **default_entry_ptr)
403 {
404         struct rte_table *table;
405
406         /* Check input arguments */
407         if (p == NULL) {
408                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
409                         __func__);
410                 return -EINVAL;
411         }
412
413         if (default_entry == NULL) {
414                 RTE_LOG(ERR, PIPELINE,
415                         "%s: default_entry parameter is NULL\n", __func__);
416                 return -EINVAL;
417         }
418
419         if (table_id >= p->num_tables) {
420                 RTE_LOG(ERR, PIPELINE,
421                         "%s: table_id %d out of range\n", __func__, table_id);
422                 return -EINVAL;
423         }
424
425         table = &p->tables[table_id];
426
427         if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
428                 table->table_next_id_valid &&
429                 (default_entry->table_id != table->table_next_id)) {
430                 RTE_LOG(ERR, PIPELINE,
431                         "%s: Tree-like topologies not allowed\n", __func__);
432                 return -EINVAL;
433         }
434
435         /* Set the lookup miss actions */
436         if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
437                 (table->table_next_id_valid == 0)) {
438                 table->table_next_id = default_entry->table_id;
439                 table->table_next_id_valid = 1;
440         }
441
442         memcpy(table->default_entry, default_entry, table->entry_size);
443
444         *default_entry_ptr = table->default_entry;
445         return 0;
446 }
447
448 int
449 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
450                 uint32_t table_id,
451                 struct rte_pipeline_table_entry *entry)
452 {
453         struct rte_table *table;
454
455         /* Check input arguments */
456         if (p == NULL) {
457                 RTE_LOG(ERR, PIPELINE,
458                         "%s: pipeline parameter is NULL\n", __func__);
459                 return -EINVAL;
460         }
461
462         if (table_id >= p->num_tables) {
463                 RTE_LOG(ERR, PIPELINE,
464                         "%s: table_id %d out of range\n", __func__, table_id);
465                 return -EINVAL;
466         }
467
468         table = &p->tables[table_id];
469
470         /* Save the current contents of the default entry */
471         if (entry)
472                 memcpy(entry, table->default_entry, table->entry_size);
473
474         /* Clear the lookup miss actions */
475         memset(table->default_entry, 0, table->entry_size);
476         table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
477
478         return 0;
479 }
480
481 int
482 rte_pipeline_table_entry_add(struct rte_pipeline *p,
483                 uint32_t table_id,
484                 void *key,
485                 struct rte_pipeline_table_entry *entry,
486                 int *key_found,
487                 struct rte_pipeline_table_entry **entry_ptr)
488 {
489         struct rte_table *table;
490
491         /* Check input arguments */
492         if (p == NULL) {
493                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
494                         __func__);
495                 return -EINVAL;
496         }
497
498         if (key == NULL) {
499                 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
500                 return -EINVAL;
501         }
502
503         if (entry == NULL) {
504                 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
505                         __func__);
506                 return -EINVAL;
507         }
508
509         if (table_id >= p->num_tables) {
510                 RTE_LOG(ERR, PIPELINE,
511                         "%s: table_id %d out of range\n", __func__, table_id);
512                 return -EINVAL;
513         }
514
515         table = &p->tables[table_id];
516
517         if (table->ops.f_add == NULL) {
518                 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
519                         __func__);
520                 return -EINVAL;
521         }
522
523         if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
524                 table->table_next_id_valid &&
525                 (entry->table_id != table->table_next_id)) {
526                 RTE_LOG(ERR, PIPELINE,
527                         "%s: Tree-like topologies not allowed\n", __func__);
528                 return -EINVAL;
529         }
530
531         /* Add entry */
532         if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
533                 (table->table_next_id_valid == 0)) {
534                 table->table_next_id = entry->table_id;
535                 table->table_next_id_valid = 1;
536         }
537
538         return (table->ops.f_add)(table->h_table, key, (void *) entry,
539                 key_found, (void **) entry_ptr);
540 }
541
542 int
543 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
544                 uint32_t table_id,
545                 void *key,
546                 int *key_found,
547                 struct rte_pipeline_table_entry *entry)
548 {
549         struct rte_table *table;
550
551         /* Check input arguments */
552         if (p == NULL) {
553                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
554                         __func__);
555                 return -EINVAL;
556         }
557
558         if (key == NULL) {
559                 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
560                         __func__);
561                 return -EINVAL;
562         }
563
564         if (table_id >= p->num_tables) {
565                 RTE_LOG(ERR, PIPELINE,
566                         "%s: table_id %d out of range\n", __func__, table_id);
567                 return -EINVAL;
568         }
569
570         table = &p->tables[table_id];
571
572         if (table->ops.f_delete == NULL) {
573                 RTE_LOG(ERR, PIPELINE,
574                         "%s: f_delete function pointer NULL\n", __func__);
575                 return -EINVAL;
576         }
577
578         return (table->ops.f_delete)(table->h_table, key, key_found, entry);
579 }
580
581 int rte_pipeline_table_entry_add_bulk(struct rte_pipeline *p,
582         uint32_t table_id,
583         void **keys,
584         struct rte_pipeline_table_entry **entries,
585         uint32_t n_keys,
586         int *key_found,
587         struct rte_pipeline_table_entry **entries_ptr)
588 {
589         struct rte_table *table;
590         uint32_t i;
591
592         /* Check input arguments */
593         if (p == NULL) {
594                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
595                         __func__);
596                 return -EINVAL;
597         }
598
599         if (keys == NULL) {
600                 RTE_LOG(ERR, PIPELINE, "%s: keys parameter is NULL\n", __func__);
601                 return -EINVAL;
602         }
603
604         if (entries == NULL) {
605                 RTE_LOG(ERR, PIPELINE, "%s: entries parameter is NULL\n",
606                         __func__);
607                 return -EINVAL;
608         }
609
610         if (table_id >= p->num_tables) {
611                 RTE_LOG(ERR, PIPELINE,
612                         "%s: table_id %d out of range\n", __func__, table_id);
613                 return -EINVAL;
614         }
615
616         table = &p->tables[table_id];
617
618         if (table->ops.f_add_bulk == NULL) {
619                 RTE_LOG(ERR, PIPELINE, "%s: f_add_bulk function pointer NULL\n",
620                         __func__);
621                 return -EINVAL;
622         }
623
624         for (i = 0; i < n_keys; i++) {
625                 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
626                         table->table_next_id_valid &&
627                         (entries[i]->table_id != table->table_next_id)) {
628                         RTE_LOG(ERR, PIPELINE,
629                                 "%s: Tree-like topologies not allowed\n", __func__);
630                         return -EINVAL;
631                 }
632         }
633
634         /* Add entry */
635         for (i = 0; i < n_keys; i++) {
636                 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
637                         (table->table_next_id_valid == 0)) {
638                         table->table_next_id = entries[i]->table_id;
639                         table->table_next_id_valid = 1;
640                 }
641         }
642
643         return (table->ops.f_add_bulk)(table->h_table, keys, (void **) entries,
644                 n_keys, key_found, (void **) entries_ptr);
645 }
646
647 int rte_pipeline_table_entry_delete_bulk(struct rte_pipeline *p,
648         uint32_t table_id,
649         void **keys,
650         uint32_t n_keys,
651         int *key_found,
652         struct rte_pipeline_table_entry **entries)
653 {
654         struct rte_table *table;
655
656         /* Check input arguments */
657         if (p == NULL) {
658                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
659                         __func__);
660                 return -EINVAL;
661         }
662
663         if (keys == NULL) {
664                 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
665                         __func__);
666                 return -EINVAL;
667         }
668
669         if (table_id >= p->num_tables) {
670                 RTE_LOG(ERR, PIPELINE,
671                         "%s: table_id %d out of range\n", __func__, table_id);
672                 return -EINVAL;
673         }
674
675         table = &p->tables[table_id];
676
677         if (table->ops.f_delete_bulk == NULL) {
678                 RTE_LOG(ERR, PIPELINE,
679                         "%s: f_delete function pointer NULL\n", __func__);
680                 return -EINVAL;
681         }
682
683         return (table->ops.f_delete_bulk)(table->h_table, keys, n_keys, key_found,
684                         (void **) entries);
685 }
686
687 /*
688  * Port
689  *
690  */
691 static int
692 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
693                 struct rte_pipeline_port_in_params *params,
694                 uint32_t *port_id)
695 {
696         if (p == NULL) {
697                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
698                         __func__);
699                 return -EINVAL;
700         }
701         if (params == NULL) {
702                 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
703                 return -EINVAL;
704         }
705         if (port_id == NULL) {
706                 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
707                         __func__);
708                 return -EINVAL;
709         }
710
711         /* ops */
712         if (params->ops == NULL) {
713                 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
714                         __func__);
715                 return -EINVAL;
716         }
717
718         if (params->ops->f_create == NULL) {
719                 RTE_LOG(ERR, PIPELINE,
720                         "%s: f_create function pointer NULL\n", __func__);
721                 return -EINVAL;
722         }
723
724         if (params->ops->f_rx == NULL) {
725                 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
726                         __func__);
727                 return -EINVAL;
728         }
729
730         /* burst_size */
731         if ((params->burst_size == 0) ||
732                 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
733                 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
734                         __func__);
735                 return -EINVAL;
736         }
737
738         /* Do we have room for one more port? */
739         if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
740                 RTE_LOG(ERR, PIPELINE,
741                         "%s: invalid value for num_ports_in\n", __func__);
742                 return -EINVAL;
743         }
744
745         return 0;
746 }
747
748 static int
749 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
750                 struct rte_pipeline_port_out_params *params,
751                 uint32_t *port_id)
752 {
753         if (p == NULL) {
754                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
755                         __func__);
756                 return -EINVAL;
757         }
758
759         if (params == NULL) {
760                 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
761                 return -EINVAL;
762         }
763
764         if (port_id == NULL) {
765                 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
766                         __func__);
767                 return -EINVAL;
768         }
769
770         /* ops */
771         if (params->ops == NULL) {
772                 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
773                         __func__);
774                 return -EINVAL;
775         }
776
777         if (params->ops->f_create == NULL) {
778                 RTE_LOG(ERR, PIPELINE,
779                         "%s: f_create function pointer NULL\n", __func__);
780                 return -EINVAL;
781         }
782
783         if (params->ops->f_tx == NULL) {
784                 RTE_LOG(ERR, PIPELINE,
785                         "%s: f_tx function pointer NULL\n", __func__);
786                 return -EINVAL;
787         }
788
789         if (params->ops->f_tx_bulk == NULL) {
790                 RTE_LOG(ERR, PIPELINE,
791                         "%s: f_tx_bulk function pointer NULL\n", __func__);
792                 return -EINVAL;
793         }
794
795         /* Do we have room for one more port? */
796         if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
797                 RTE_LOG(ERR, PIPELINE,
798                         "%s: invalid value for num_ports_out\n", __func__);
799                 return -EINVAL;
800         }
801
802         return 0;
803 }
804
805 int
806 rte_pipeline_port_in_create(struct rte_pipeline *p,
807                 struct rte_pipeline_port_in_params *params,
808                 uint32_t *port_id)
809 {
810         struct rte_port_in *port;
811         void *h_port;
812         uint32_t id;
813         int status;
814
815         /* Check input arguments */
816         status = rte_pipeline_port_in_check_params(p, params, port_id);
817         if (status != 0)
818                 return status;
819
820         id = p->num_ports_in;
821         port = &p->ports_in[id];
822
823         /* Create the port */
824         h_port = params->ops->f_create(params->arg_create, p->socket_id);
825         if (h_port == NULL) {
826                 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
827                 return -EINVAL;
828         }
829
830         /* Commit current table to the pipeline */
831         p->num_ports_in++;
832         *port_id = id;
833
834         /* Save input parameters */
835         memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
836         port->f_action = params->f_action;
837         port->arg_ah = params->arg_ah;
838         port->burst_size = params->burst_size;
839
840         /* Initialize port internal data structure */
841         port->table_id = RTE_TABLE_INVALID;
842         port->h_port = h_port;
843         port->next = NULL;
844
845         return 0;
846 }
847
848 void
849 rte_pipeline_port_in_free(struct rte_port_in *port)
850 {
851         if (port->ops.f_free != NULL)
852                 port->ops.f_free(port->h_port);
853 }
854
855 int
856 rte_pipeline_port_out_create(struct rte_pipeline *p,
857                 struct rte_pipeline_port_out_params *params,
858                 uint32_t *port_id)
859 {
860         struct rte_port_out *port;
861         void *h_port;
862         uint32_t id;
863         int status;
864
865         /* Check input arguments */
866         status = rte_pipeline_port_out_check_params(p, params, port_id);
867         if (status != 0)
868                 return status;
869
870         id = p->num_ports_out;
871         port = &p->ports_out[id];
872
873         /* Create the port */
874         h_port = params->ops->f_create(params->arg_create, p->socket_id);
875         if (h_port == NULL) {
876                 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
877                 return -EINVAL;
878         }
879
880         /* Commit current table to the pipeline */
881         p->num_ports_out++;
882         *port_id = id;
883
884         /* Save input parameters */
885         memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
886         port->f_action = params->f_action;
887         port->arg_ah = params->arg_ah;
888
889         /* Initialize port internal data structure */
890         port->h_port = h_port;
891
892         return 0;
893 }
894
895 void
896 rte_pipeline_port_out_free(struct rte_port_out *port)
897 {
898         if (port->ops.f_free != NULL)
899                 port->ops.f_free(port->h_port);
900 }
901
902 int
903 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
904                 uint32_t port_id,
905                 uint32_t table_id)
906 {
907         struct rte_port_in *port;
908
909         /* Check input arguments */
910         if (p == NULL) {
911                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
912                         __func__);
913                 return -EINVAL;
914         }
915
916         if (port_id >= p->num_ports_in) {
917                 RTE_LOG(ERR, PIPELINE,
918                         "%s: port IN ID %u is out of range\n",
919                         __func__, port_id);
920                 return -EINVAL;
921         }
922
923         if (table_id >= p->num_tables) {
924                 RTE_LOG(ERR, PIPELINE,
925                         "%s: Table ID %u is out of range\n",
926                         __func__, table_id);
927                 return -EINVAL;
928         }
929
930         port = &p->ports_in[port_id];
931         port->table_id = table_id;
932
933         return 0;
934 }
935
936 int
937 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
938 {
939         struct rte_port_in *port, *port_prev, *port_next;
940         uint64_t port_mask;
941         uint32_t port_prev_id, port_next_id;
942
943         /* Check input arguments */
944         if (p == NULL) {
945                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
946                         __func__);
947                 return -EINVAL;
948         }
949
950         if (port_id >= p->num_ports_in) {
951                 RTE_LOG(ERR, PIPELINE,
952                         "%s: port IN ID %u is out of range\n",
953                         __func__, port_id);
954                 return -EINVAL;
955         }
956
957         port = &p->ports_in[port_id];
958
959         /* Return if current input port is already enabled */
960         port_mask = 1LLU << port_id;
961         if (p->enabled_port_in_mask & port_mask)
962                 return 0;
963
964         p->enabled_port_in_mask |= port_mask;
965
966         /* Add current input port to the pipeline chain of enabled ports */
967         port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
968         port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
969
970         port_prev = &p->ports_in[port_prev_id];
971         port_next = &p->ports_in[port_next_id];
972
973         port_prev->next = port;
974         port->next = port_next;
975
976         /* Check if list of enabled ports was previously empty */
977         if (p->enabled_port_in_mask == port_mask)
978                 p->port_in_next = port;
979
980         return 0;
981 }
982
983 int
984 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
985 {
986         struct rte_port_in *port, *port_prev, *port_next;
987         uint64_t port_mask;
988         uint32_t port_prev_id, port_next_id;
989
990         /* Check input arguments */
991         if (p == NULL) {
992                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
993                 __func__);
994                 return -EINVAL;
995         }
996
997         if (port_id >= p->num_ports_in) {
998                 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
999                         __func__, port_id);
1000                 return -EINVAL;
1001         }
1002
1003         port = &p->ports_in[port_id];
1004
1005         /* Return if current input port is already disabled */
1006         port_mask = 1LLU << port_id;
1007         if ((p->enabled_port_in_mask & port_mask) == 0)
1008                 return 0;
1009
1010         p->enabled_port_in_mask &= ~port_mask;
1011
1012         /* Return if no other enabled ports */
1013         if (p->enabled_port_in_mask == 0) {
1014                 p->port_in_next = NULL;
1015
1016                 return 0;
1017         }
1018
1019         /* Add current input port to the pipeline chain of enabled ports */
1020         port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
1021         port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1022
1023         port_prev = &p->ports_in[port_prev_id];
1024         port_next = &p->ports_in[port_next_id];
1025
1026         port_prev->next = port_next;
1027
1028         /* Check if the port which has just been disabled is next to serve */
1029         if (port == p->port_in_next)
1030                 p->port_in_next = port_next;
1031
1032         return 0;
1033 }
1034
1035 /*
1036  * Pipeline run-time
1037  *
1038  */
1039 int
1040 rte_pipeline_check(struct rte_pipeline *p)
1041 {
1042         uint32_t port_in_id;
1043
1044         /* Check input arguments */
1045         if (p == NULL) {
1046                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1047                         __func__);
1048                 return -EINVAL;
1049         }
1050
1051         /* Check that pipeline has at least one input port, one table and one
1052         output port */
1053         if (p->num_ports_in == 0) {
1054                 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
1055                         __func__);
1056                 return -EINVAL;
1057         }
1058         if (p->num_tables == 0) {
1059                 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
1060                         __func__);
1061                 return -EINVAL;
1062         }
1063         if (p->num_ports_out == 0) {
1064                 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
1065                         __func__);
1066                 return -EINVAL;
1067         }
1068
1069         /* Check that all input ports are connected */
1070         for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
1071                 struct rte_port_in *port_in = &p->ports_in[port_in_id];
1072
1073                 if (port_in->table_id == RTE_TABLE_INVALID) {
1074                         RTE_LOG(ERR, PIPELINE,
1075                                 "%s: Port IN ID %u is not connected\n",
1076                                 __func__, port_in_id);
1077                         return -EINVAL;
1078                 }
1079         }
1080
1081         return 0;
1082 }
1083
1084 static inline void
1085 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
1086 {
1087         p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1088         p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1089         p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
1090         p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1091
1092         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1093                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1094                 uint32_t i;
1095
1096                 for (i = 0; i < n_pkts; i++) {
1097                         uint64_t pkt_mask = 1LLU << i;
1098                         uint32_t pos = p->entries[i]->action;
1099
1100                         p->action_mask1[pos] |= pkt_mask;
1101                 }
1102         } else {
1103                 uint32_t i;
1104
1105                 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1106                         uint64_t pkt_mask = 1LLU << i;
1107                         uint32_t pos;
1108
1109                         if ((pkt_mask & pkts_mask) == 0)
1110                                 continue;
1111
1112                         pos = p->entries[i]->action;
1113                         p->action_mask1[pos] |= pkt_mask;
1114                 }
1115         }
1116 }
1117
1118 static inline void
1119 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1120         uint64_t pkts_mask, uint32_t port_id)
1121 {
1122         struct rte_port_out *port_out = &p->ports_out[port_id];
1123
1124         p->pkts_mask = pkts_mask;
1125
1126         /* Output port user actions */
1127         if (port_out->f_action != NULL) {
1128                 port_out->f_action(p, p->pkts, pkts_mask, port_out->arg_ah);
1129
1130                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1131                         port_out->n_pkts_dropped_by_ah);
1132         }
1133
1134         /* Output port TX */
1135         if (p->pkts_mask != 0)
1136                 port_out->ops.f_tx_bulk(port_out->h_port,
1137                         p->pkts,
1138                         p->pkts_mask);
1139 }
1140
1141 static inline void
1142 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1143 {
1144         p->pkts_mask = pkts_mask;
1145
1146         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1147                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1148                 uint32_t i;
1149
1150                 for (i = 0; i < n_pkts; i++) {
1151                         struct rte_mbuf *pkt = p->pkts[i];
1152                         uint32_t port_out_id = p->entries[i]->port_id;
1153                         struct rte_port_out *port_out =
1154                                 &p->ports_out[port_out_id];
1155
1156                         /* Output port user actions */
1157                         if (port_out->f_action == NULL) /* Output port TX */
1158                                 port_out->ops.f_tx(port_out->h_port, pkt);
1159                         else {
1160                                 uint64_t pkt_mask = 1LLU << i;
1161
1162                                 port_out->f_action(p,
1163                                         p->pkts,
1164                                         pkt_mask,
1165                                         port_out->arg_ah);
1166
1167                                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1168                                         port_out->n_pkts_dropped_by_ah);
1169
1170                                 /* Output port TX */
1171                                 if (pkt_mask & p->pkts_mask)
1172                                         port_out->ops.f_tx(port_out->h_port,
1173                                                 pkt);
1174                         }
1175                 }
1176         } else {
1177                 uint32_t i;
1178
1179                 for (i = 0;  i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1180                         uint64_t pkt_mask = 1LLU << i;
1181                         struct rte_mbuf *pkt;
1182                         struct rte_port_out *port_out;
1183                         uint32_t port_out_id;
1184
1185                         if ((pkt_mask & pkts_mask) == 0)
1186                                 continue;
1187
1188                         pkt = p->pkts[i];
1189                         port_out_id = p->entries[i]->port_id;
1190                         port_out = &p->ports_out[port_out_id];
1191
1192                         /* Output port user actions */
1193                         if (port_out->f_action == NULL) /* Output port TX */
1194                                 port_out->ops.f_tx(port_out->h_port, pkt);
1195                         else {
1196                                 port_out->f_action(p,
1197                                         p->pkts,
1198                                         pkt_mask,
1199                                         port_out->arg_ah);
1200
1201                                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1202                                         port_out->n_pkts_dropped_by_ah);
1203
1204                                 /* Output port TX */
1205                                 if (pkt_mask & p->pkts_mask)
1206                                         port_out->ops.f_tx(port_out->h_port,
1207                                                 pkt);
1208                         }
1209                 }
1210         }
1211 }
1212
1213 static inline void
1214 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1215         uint64_t pkts_mask)
1216 {
1217         p->pkts_mask = pkts_mask;
1218
1219         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1220                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1221                 uint32_t i;
1222
1223                 for (i = 0; i < n_pkts; i++) {
1224                         struct rte_mbuf *pkt = p->pkts[i];
1225                         uint32_t port_out_id =
1226                                 RTE_MBUF_METADATA_UINT32(pkt,
1227                                         p->offset_port_id);
1228                         struct rte_port_out *port_out = &p->ports_out[
1229                                 port_out_id];
1230
1231                         /* Output port user actions */
1232                         if (port_out->f_action == NULL) /* Output port TX */
1233                                 port_out->ops.f_tx(port_out->h_port, pkt);
1234                         else {
1235                                 uint64_t pkt_mask = 1LLU << i;
1236
1237                                 port_out->f_action(p,
1238                                         p->pkts,
1239                                         pkt_mask,
1240                                         port_out->arg_ah);
1241
1242                                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1243                                         port_out->n_pkts_dropped_by_ah);
1244
1245                                 /* Output port TX */
1246                                 if (pkt_mask & p->pkts_mask)
1247                                         port_out->ops.f_tx(port_out->h_port,
1248                                                 pkt);
1249                         }
1250                 }
1251         } else {
1252                 uint32_t i;
1253
1254                 for (i = 0;  i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1255                         uint64_t pkt_mask = 1LLU << i;
1256                         struct rte_mbuf *pkt;
1257                         struct rte_port_out *port_out;
1258                         uint32_t port_out_id;
1259
1260                         if ((pkt_mask & pkts_mask) == 0)
1261                                 continue;
1262
1263                         pkt = p->pkts[i];
1264                         port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1265                                 p->offset_port_id);
1266                         port_out = &p->ports_out[port_out_id];
1267
1268                         /* Output port user actions */
1269                         if (port_out->f_action == NULL) /* Output port TX */
1270                                 port_out->ops.f_tx(port_out->h_port, pkt);
1271                         else {
1272                                 port_out->f_action(p,
1273                                         p->pkts,
1274                                         pkt_mask,
1275                                         port_out->arg_ah);
1276
1277                                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1278                                         port_out->n_pkts_dropped_by_ah);
1279
1280                                 /* Output port TX */
1281                                 if (pkt_mask & p->pkts_mask)
1282                                         port_out->ops.f_tx(port_out->h_port,
1283                                                 pkt);
1284                         }
1285                 }
1286         }
1287 }
1288
1289 static inline void
1290 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1291 {
1292         if ((pkts_mask & (pkts_mask + 1)) == 0) {
1293                 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1294                 uint32_t i;
1295
1296                 for (i = 0; i < n_pkts; i++)
1297                         rte_pktmbuf_free(p->pkts[i]);
1298         } else {
1299                 uint32_t i;
1300
1301                 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1302                         uint64_t pkt_mask = 1LLU << i;
1303
1304                         if ((pkt_mask & pkts_mask) == 0)
1305                                 continue;
1306
1307                         rte_pktmbuf_free(p->pkts[i]);
1308                 }
1309         }
1310 }
1311
1312 int
1313 rte_pipeline_run(struct rte_pipeline *p)
1314 {
1315         struct rte_port_in *port_in = p->port_in_next;
1316         uint32_t n_pkts, table_id;
1317
1318         if (port_in == NULL)
1319                 return 0;
1320
1321         /* Input port RX */
1322         n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1323                 port_in->burst_size);
1324         if (n_pkts == 0) {
1325                 p->port_in_next = port_in->next;
1326                 return 0;
1327         }
1328
1329         p->pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1330         p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1331         p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1332         p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1333         p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1334
1335         /* Input port user actions */
1336         if (port_in->f_action != NULL) {
1337                 port_in->f_action(p, p->pkts, n_pkts, port_in->arg_ah);
1338
1339                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1340                         port_in->n_pkts_dropped_by_ah);
1341         }
1342
1343         /* Table */
1344         for (table_id = port_in->table_id; p->pkts_mask != 0; ) {
1345                 struct rte_table *table;
1346                 uint64_t lookup_hit_mask, lookup_miss_mask;
1347
1348                 /* Lookup */
1349                 table = &p->tables[table_id];
1350                 table->ops.f_lookup(table->h_table, p->pkts, p->pkts_mask,
1351                         &lookup_hit_mask, (void **) p->entries);
1352                 lookup_miss_mask = p->pkts_mask & (~lookup_hit_mask);
1353
1354                 /* Lookup miss */
1355                 if (lookup_miss_mask != 0) {
1356                         struct rte_pipeline_table_entry *default_entry =
1357                                 table->default_entry;
1358
1359                         p->pkts_mask = lookup_miss_mask;
1360
1361                         /* Table user actions */
1362                         if (table->f_action_miss != NULL) {
1363                                 table->f_action_miss(p,
1364                                         p->pkts,
1365                                         lookup_miss_mask,
1366                                         default_entry,
1367                                         table->arg_ah);
1368
1369                                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1370                                         table->n_pkts_dropped_by_lkp_miss_ah);
1371                         }
1372
1373                         /* Table reserved actions */
1374                         if ((default_entry->action == RTE_PIPELINE_ACTION_PORT) &&
1375                                 (p->pkts_mask != 0))
1376                                 rte_pipeline_action_handler_port_bulk(p,
1377                                         p->pkts_mask,
1378                                         default_entry->port_id);
1379                         else {
1380                                 uint32_t pos = default_entry->action;
1381
1382                                 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1383
1384                                 p->action_mask0[pos] |= p->pkts_mask;
1385
1386                                 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1387                                         table->n_pkts_dropped_lkp_miss);
1388                         }
1389                 }
1390
1391                 /* Lookup hit */
1392                 if (lookup_hit_mask != 0) {
1393                         p->pkts_mask = lookup_hit_mask;
1394
1395                         /* Table user actions */
1396                         if (table->f_action_hit != NULL) {
1397                                 table->f_action_hit(p,
1398                                         p->pkts,
1399                                         lookup_hit_mask,
1400                                         p->entries,
1401                                         table->arg_ah);
1402
1403                                 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1404                                         table->n_pkts_dropped_by_lkp_hit_ah);
1405                         }
1406
1407                         /* Table reserved actions */
1408                         RTE_PIPELINE_STATS_TABLE_DROP0(p);
1409                         rte_pipeline_compute_masks(p, p->pkts_mask);
1410                         p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1411                                 p->action_mask1[
1412                                         RTE_PIPELINE_ACTION_DROP];
1413                         p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1414                                 p->action_mask1[
1415                                         RTE_PIPELINE_ACTION_PORT];
1416                         p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1417                                 p->action_mask1[
1418                                         RTE_PIPELINE_ACTION_PORT_META];
1419                         p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1420                                 p->action_mask1[
1421                                         RTE_PIPELINE_ACTION_TABLE];
1422
1423                         RTE_PIPELINE_STATS_TABLE_DROP1(p,
1424                                 table->n_pkts_dropped_lkp_hit);
1425                 }
1426
1427                 /* Prepare for next iteration */
1428                 p->pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1429                 table_id = table->table_next_id;
1430                 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1431         }
1432
1433         /* Table reserved action PORT */
1434         rte_pipeline_action_handler_port(p,
1435                 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1436
1437         /* Table reserved action PORT META */
1438         rte_pipeline_action_handler_port_meta(p,
1439                 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1440
1441         /* Table reserved action DROP */
1442         rte_pipeline_action_handler_drop(p,
1443                 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1444
1445         /* Pick candidate for next port IN to serve */
1446         p->port_in_next = port_in->next;
1447
1448         return (int) n_pkts;
1449 }
1450
1451 int
1452 rte_pipeline_flush(struct rte_pipeline *p)
1453 {
1454         uint32_t port_id;
1455
1456         /* Check input arguments */
1457         if (p == NULL) {
1458                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1459                         __func__);
1460                 return -EINVAL;
1461         }
1462
1463         for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1464                 struct rte_port_out *port = &p->ports_out[port_id];
1465
1466                 if (port->ops.f_flush != NULL)
1467                         port->ops.f_flush(port->h_port);
1468         }
1469
1470         return 0;
1471 }
1472
1473 int
1474 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1475         uint32_t port_id, struct rte_mbuf *pkt)
1476 {
1477         struct rte_port_out *port_out = &p->ports_out[port_id];
1478
1479         port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1480
1481         return 0;
1482 }
1483
1484 int rte_pipeline_ah_packet_hijack(struct rte_pipeline *p,
1485         uint64_t pkts_mask)
1486 {
1487         pkts_mask &= p->pkts_mask;
1488         p->pkts_mask &= ~pkts_mask;
1489
1490         return 0;
1491 }
1492
1493 int rte_pipeline_ah_packet_drop(struct rte_pipeline *p,
1494         uint64_t pkts_mask)
1495 {
1496         pkts_mask &= p->pkts_mask;
1497         p->pkts_mask &= ~pkts_mask;
1498         p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask;
1499
1500         RTE_PIPELINE_STATS_AH_DROP_WRITE(p, pkts_mask);
1501         return 0;
1502 }
1503
1504 int rte_pipeline_port_in_stats_read(struct rte_pipeline *p, uint32_t port_id,
1505         struct rte_pipeline_port_in_stats *stats, int clear)
1506 {
1507         struct rte_port_in *port;
1508         int retval;
1509
1510         if (p == NULL) {
1511                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1512                         __func__);
1513                 return -EINVAL;
1514         }
1515
1516         if (port_id >= p->num_ports_in) {
1517                 RTE_LOG(ERR, PIPELINE,
1518                         "%s: port IN ID %u is out of range\n",
1519                         __func__, port_id);
1520                 return -EINVAL;
1521         }
1522
1523         port = &p->ports_in[port_id];
1524
1525         if (port->ops.f_stats != NULL) {
1526                 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1527                 if (retval)
1528                         return retval;
1529         } else if (stats != NULL)
1530                 memset(&stats->stats, 0, sizeof(stats->stats));
1531
1532         if (stats != NULL)
1533                 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1534
1535         if (clear != 0)
1536                 port->n_pkts_dropped_by_ah = 0;
1537
1538         return 0;
1539 }
1540
1541 int rte_pipeline_port_out_stats_read(struct rte_pipeline *p, uint32_t port_id,
1542         struct rte_pipeline_port_out_stats *stats, int clear)
1543 {
1544         struct rte_port_out *port;
1545         int retval;
1546
1547         if (p == NULL) {
1548                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n", __func__);
1549                 return -EINVAL;
1550         }
1551
1552         if (port_id >= p->num_ports_out) {
1553                 RTE_LOG(ERR, PIPELINE,
1554                         "%s: port OUT ID %u is out of range\n", __func__, port_id);
1555                 return -EINVAL;
1556         }
1557
1558         port = &p->ports_out[port_id];
1559         if (port->ops.f_stats != NULL) {
1560                 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1561                 if (retval != 0)
1562                         return retval;
1563         } else if (stats != NULL)
1564                 memset(&stats->stats, 0, sizeof(stats->stats));
1565
1566         if (stats != NULL)
1567                 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1568
1569         if (clear != 0)
1570                 port->n_pkts_dropped_by_ah = 0;
1571
1572         return 0;
1573 }
1574
1575 int rte_pipeline_table_stats_read(struct rte_pipeline *p, uint32_t table_id,
1576         struct rte_pipeline_table_stats *stats, int clear)
1577 {
1578         struct rte_table *table;
1579         int retval;
1580
1581         if (p == NULL) {
1582                 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1583                         __func__);
1584                 return -EINVAL;
1585         }
1586
1587         if (table_id >= p->num_tables) {
1588                 RTE_LOG(ERR, PIPELINE,
1589                                 "%s: table %u is out of range\n", __func__, table_id);
1590                 return -EINVAL;
1591         }
1592
1593         table = &p->tables[table_id];
1594         if (table->ops.f_stats != NULL) {
1595                 retval = table->ops.f_stats(table->h_table, &stats->stats, clear);
1596                 if (retval != 0)
1597                         return retval;
1598         } else if (stats != NULL)
1599                 memset(&stats->stats, 0, sizeof(stats->stats));
1600
1601         if (stats != NULL) {
1602                 stats->n_pkts_dropped_by_lkp_hit_ah =
1603                         table->n_pkts_dropped_by_lkp_hit_ah;
1604                 stats->n_pkts_dropped_by_lkp_miss_ah =
1605                         table->n_pkts_dropped_by_lkp_miss_ah;
1606                 stats->n_pkts_dropped_lkp_hit = table->n_pkts_dropped_lkp_hit;
1607                 stats->n_pkts_dropped_lkp_miss = table->n_pkts_dropped_lkp_miss;
1608         }
1609
1610         if (clear != 0) {
1611                 table->n_pkts_dropped_by_lkp_hit_ah = 0;
1612                 table->n_pkts_dropped_by_lkp_miss_ah = 0;
1613                 table->n_pkts_dropped_lkp_hit = 0;
1614                 table->n_pkts_dropped_lkp_miss = 0;
1615         }
1616
1617         return 0;
1618 }