4 * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
37 #include <rte_common.h>
38 #include <rte_memory.h>
39 #include <rte_cycles.h>
40 #include <rte_prefetch.h>
41 #include <rte_branch_prediction.h>
43 #include <rte_malloc.h>
44 #include <rte_string_fns.h>
46 #include "rte_pipeline.h"
48 #define RTE_TABLE_INVALID UINT32_MAX
50 #ifdef RTE_PIPELINE_STATS_COLLECT
52 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask) \
53 ({ (p)->n_pkts_ah_drop = __builtin_popcountll(mask); })
55 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter) \
56 ({ (counter) += (p)->n_pkts_ah_drop; (p)->n_pkts_ah_drop = 0; })
58 #define RTE_PIPELINE_STATS_TABLE_DROP0(p) \
59 ({ (p)->pkts_drop_mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; })
61 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter) \
63 uint64_t mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; \
64 mask ^= (p)->pkts_drop_mask; \
65 (counter) += __builtin_popcountll(mask); \
70 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask)
71 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter)
72 #define RTE_PIPELINE_STATS_TABLE_DROP0(p)
73 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter)
78 /* Input parameters */
79 struct rte_port_in_ops ops;
80 rte_pipeline_port_in_action_handler f_action;
84 /* The table to which this port is connected */
87 /* Handle to low-level port */
90 /* List of enabled ports */
91 struct rte_port_in *next;
94 uint64_t n_pkts_dropped_by_ah;
98 /* Input parameters */
99 struct rte_port_out_ops ops;
100 rte_pipeline_port_out_action_handler f_action;
103 /* Handle to low-level port */
107 uint64_t n_pkts_dropped_by_ah;
111 /* Input parameters */
112 struct rte_table_ops ops;
113 rte_pipeline_table_action_handler_hit f_action_hit;
114 rte_pipeline_table_action_handler_miss f_action_miss;
116 struct rte_pipeline_table_entry *default_entry;
119 uint32_t table_next_id;
120 uint32_t table_next_id_valid;
122 /* Handle to the low-level table object */
126 uint64_t n_pkts_dropped_by_lkp_hit_ah;
127 uint64_t n_pkts_dropped_by_lkp_miss_ah;
128 uint64_t n_pkts_dropped_lkp_hit;
129 uint64_t n_pkts_dropped_lkp_miss;
132 #define RTE_PIPELINE_MAX_NAME_SZ 124
134 struct rte_pipeline {
135 /* Input parameters */
136 char name[RTE_PIPELINE_MAX_NAME_SZ];
138 uint32_t offset_port_id;
140 /* Internal tables */
141 struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
142 struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
143 struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
145 /* Occupancy of internal tables */
146 uint32_t num_ports_in;
147 uint32_t num_ports_out;
150 /* List of enabled ports */
151 uint64_t enabled_port_in_mask;
152 struct rte_port_in *port_in_next;
154 /* Pipeline run structures */
155 struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
156 struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
157 uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
158 uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
160 uint64_t n_pkts_ah_drop;
161 uint64_t pkts_drop_mask;
162 } __rte_cache_aligned;
164 static inline uint32_t
165 rte_mask_get_next(uint64_t mask, uint32_t pos)
167 uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
168 (mask >> ((pos + 1) & 0x3F));
169 return (__builtin_ctzll(mask_rot) - (63 - pos)) & 0x3F;
172 static inline uint32_t
173 rte_mask_get_prev(uint64_t mask, uint32_t pos)
175 uint64_t mask_rot = (mask >> (pos & 0x3F)) |
176 (mask << ((64 - pos) & 0x3F));
177 return ((63 - __builtin_clzll(mask_rot)) + pos) & 0x3F;
181 rte_pipeline_table_free(struct rte_table *table);
184 rte_pipeline_port_in_free(struct rte_port_in *port);
187 rte_pipeline_port_out_free(struct rte_port_out *port);
194 rte_pipeline_check_params(struct rte_pipeline_params *params)
196 if (params == NULL) {
197 RTE_LOG(ERR, PIPELINE,
198 "%s: Incorrect value for parameter params\n", __func__);
203 if (params->name == NULL) {
204 RTE_LOG(ERR, PIPELINE,
205 "%s: Incorrect value for parameter name\n", __func__);
210 if ((params->socket_id < 0) ||
211 (params->socket_id >= RTE_MAX_NUMA_NODES)) {
212 RTE_LOG(ERR, PIPELINE,
213 "%s: Incorrect value for parameter socket_id\n",
221 struct rte_pipeline *
222 rte_pipeline_create(struct rte_pipeline_params *params)
224 struct rte_pipeline *p;
227 /* Check input parameters */
228 status = rte_pipeline_check_params(params);
230 RTE_LOG(ERR, PIPELINE,
231 "%s: Pipeline params check failed (%d)\n",
236 /* Allocate memory for the pipeline on requested socket */
237 p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
238 RTE_CACHE_LINE_SIZE, params->socket_id);
241 RTE_LOG(ERR, PIPELINE,
242 "%s: Pipeline memory allocation failed\n", __func__);
246 /* Save input parameters */
247 snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
248 p->socket_id = params->socket_id;
249 p->offset_port_id = params->offset_port_id;
251 /* Initialize pipeline internal data structure */
253 p->num_ports_out = 0;
255 p->enabled_port_in_mask = 0;
256 p->port_in_next = NULL;
258 p->n_pkts_ah_drop = 0;
264 rte_pipeline_free(struct rte_pipeline *p)
268 /* Check input parameters */
270 RTE_LOG(ERR, PIPELINE,
271 "%s: rte_pipeline parameter is NULL\n", __func__);
275 /* Free input ports */
276 for (i = 0; i < p->num_ports_in; i++) {
277 struct rte_port_in *port = &p->ports_in[i];
279 rte_pipeline_port_in_free(port);
283 for (i = 0; i < p->num_tables; i++) {
284 struct rte_table *table = &p->tables[i];
286 rte_pipeline_table_free(table);
289 /* Free output ports */
290 for (i = 0; i < p->num_ports_out; i++) {
291 struct rte_port_out *port = &p->ports_out[i];
293 rte_pipeline_port_out_free(port);
296 /* Free pipeline memory */
307 rte_table_check_params(struct rte_pipeline *p,
308 struct rte_pipeline_table_params *params,
312 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
316 if (params == NULL) {
317 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
321 if (table_id == NULL) {
322 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
328 if (params->ops == NULL) {
329 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
334 if (params->ops->f_create == NULL) {
335 RTE_LOG(ERR, PIPELINE,
336 "%s: f_create function pointer is NULL\n", __func__);
340 if (params->ops->f_lookup == NULL) {
341 RTE_LOG(ERR, PIPELINE,
342 "%s: f_lookup function pointer is NULL\n", __func__);
346 /* De we have room for one more table? */
347 if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
348 RTE_LOG(ERR, PIPELINE,
349 "%s: Incorrect value for num_tables parameter\n",
358 rte_pipeline_table_create(struct rte_pipeline *p,
359 struct rte_pipeline_table_params *params,
362 struct rte_table *table;
363 struct rte_pipeline_table_entry *default_entry;
365 uint32_t entry_size, id;
368 /* Check input arguments */
369 status = rte_table_check_params(p, params, table_id);
374 table = &p->tables[id];
376 /* Allocate space for the default table entry */
377 entry_size = sizeof(struct rte_pipeline_table_entry) +
378 params->action_data_size;
379 default_entry = (struct rte_pipeline_table_entry *) rte_zmalloc_socket(
380 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
381 if (default_entry == NULL) {
382 RTE_LOG(ERR, PIPELINE,
383 "%s: Failed to allocate default entry\n", __func__);
387 /* Create the table */
388 h_table = params->ops->f_create(params->arg_create, p->socket_id,
390 if (h_table == NULL) {
391 rte_free(default_entry);
392 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
396 /* Commit current table to the pipeline */
400 /* Save input parameters */
401 memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
402 table->f_action_hit = params->f_action_hit;
403 table->f_action_miss = params->f_action_miss;
404 table->arg_ah = params->arg_ah;
405 table->entry_size = entry_size;
407 /* Clear the lookup miss actions (to be set later through API) */
408 table->default_entry = default_entry;
409 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
411 /* Initialize table internal data structure */
412 table->h_table = h_table;
413 table->table_next_id = 0;
414 table->table_next_id_valid = 0;
420 rte_pipeline_table_free(struct rte_table *table)
422 if (table->ops.f_free != NULL)
423 table->ops.f_free(table->h_table);
425 rte_free(table->default_entry);
429 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
431 struct rte_pipeline_table_entry *default_entry,
432 struct rte_pipeline_table_entry **default_entry_ptr)
434 struct rte_table *table;
436 /* Check input arguments */
438 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
443 if (default_entry == NULL) {
444 RTE_LOG(ERR, PIPELINE,
445 "%s: default_entry parameter is NULL\n", __func__);
449 if (table_id >= p->num_tables) {
450 RTE_LOG(ERR, PIPELINE,
451 "%s: table_id %d out of range\n", __func__, table_id);
455 table = &p->tables[table_id];
457 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
458 table->table_next_id_valid &&
459 (default_entry->table_id != table->table_next_id)) {
460 RTE_LOG(ERR, PIPELINE,
461 "%s: Tree-like topologies not allowed\n", __func__);
465 /* Set the lookup miss actions */
466 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
467 (table->table_next_id_valid == 0)) {
468 table->table_next_id = default_entry->table_id;
469 table->table_next_id_valid = 1;
472 memcpy(table->default_entry, default_entry, table->entry_size);
474 *default_entry_ptr = table->default_entry;
479 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
481 struct rte_pipeline_table_entry *entry)
483 struct rte_table *table;
485 /* Check input arguments */
487 RTE_LOG(ERR, PIPELINE,
488 "%s: pipeline parameter is NULL\n", __func__);
492 if (table_id >= p->num_tables) {
493 RTE_LOG(ERR, PIPELINE,
494 "%s: table_id %d out of range\n", __func__, table_id);
498 table = &p->tables[table_id];
500 /* Save the current contents of the default entry */
502 memcpy(entry, table->default_entry, table->entry_size);
504 /* Clear the lookup miss actions */
505 memset(table->default_entry, 0, table->entry_size);
506 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
512 rte_pipeline_table_entry_add(struct rte_pipeline *p,
515 struct rte_pipeline_table_entry *entry,
517 struct rte_pipeline_table_entry **entry_ptr)
519 struct rte_table *table;
521 /* Check input arguments */
523 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
529 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
534 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
539 if (table_id >= p->num_tables) {
540 RTE_LOG(ERR, PIPELINE,
541 "%s: table_id %d out of range\n", __func__, table_id);
545 table = &p->tables[table_id];
547 if (table->ops.f_add == NULL) {
548 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
553 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
554 table->table_next_id_valid &&
555 (entry->table_id != table->table_next_id)) {
556 RTE_LOG(ERR, PIPELINE,
557 "%s: Tree-like topologies not allowed\n", __func__);
562 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
563 (table->table_next_id_valid == 0)) {
564 table->table_next_id = entry->table_id;
565 table->table_next_id_valid = 1;
568 return (table->ops.f_add)(table->h_table, key, (void *) entry,
569 key_found, (void **) entry_ptr);
573 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
577 struct rte_pipeline_table_entry *entry)
579 struct rte_table *table;
581 /* Check input arguments */
583 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
589 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
594 if (table_id >= p->num_tables) {
595 RTE_LOG(ERR, PIPELINE,
596 "%s: table_id %d out of range\n", __func__, table_id);
600 table = &p->tables[table_id];
602 if (table->ops.f_delete == NULL) {
603 RTE_LOG(ERR, PIPELINE,
604 "%s: f_delete function pointer NULL\n", __func__);
608 return (table->ops.f_delete)(table->h_table, key, key_found, entry);
611 int rte_pipeline_table_entry_add_bulk(struct rte_pipeline *p,
614 struct rte_pipeline_table_entry **entries,
617 struct rte_pipeline_table_entry **entries_ptr)
619 struct rte_table *table;
622 /* Check input arguments */
624 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
630 RTE_LOG(ERR, PIPELINE, "%s: keys parameter is NULL\n", __func__);
634 if (entries == NULL) {
635 RTE_LOG(ERR, PIPELINE, "%s: entries parameter is NULL\n",
640 if (table_id >= p->num_tables) {
641 RTE_LOG(ERR, PIPELINE,
642 "%s: table_id %d out of range\n", __func__, table_id);
646 table = &p->tables[table_id];
648 if (table->ops.f_add_bulk == NULL) {
649 RTE_LOG(ERR, PIPELINE, "%s: f_add_bulk function pointer NULL\n",
654 for (i = 0; i < n_keys; i++) {
655 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
656 table->table_next_id_valid &&
657 (entries[i]->table_id != table->table_next_id)) {
658 RTE_LOG(ERR, PIPELINE,
659 "%s: Tree-like topologies not allowed\n", __func__);
665 for (i = 0; i < n_keys; i++) {
666 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
667 (table->table_next_id_valid == 0)) {
668 table->table_next_id = entries[i]->table_id;
669 table->table_next_id_valid = 1;
673 return (table->ops.f_add_bulk)(table->h_table, keys, (void **) entries,
674 n_keys, key_found, (void **) entries_ptr);
677 int rte_pipeline_table_entry_delete_bulk(struct rte_pipeline *p,
682 struct rte_pipeline_table_entry **entries)
684 struct rte_table *table;
686 /* Check input arguments */
688 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
694 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
699 if (table_id >= p->num_tables) {
700 RTE_LOG(ERR, PIPELINE,
701 "%s: table_id %d out of range\n", __func__, table_id);
705 table = &p->tables[table_id];
707 if (table->ops.f_delete_bulk == NULL) {
708 RTE_LOG(ERR, PIPELINE,
709 "%s: f_delete function pointer NULL\n", __func__);
713 return (table->ops.f_delete_bulk)(table->h_table, keys, n_keys, key_found,
722 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
723 struct rte_pipeline_port_in_params *params,
727 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
731 if (params == NULL) {
732 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
735 if (port_id == NULL) {
736 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
742 if (params->ops == NULL) {
743 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
748 if (params->ops->f_create == NULL) {
749 RTE_LOG(ERR, PIPELINE,
750 "%s: f_create function pointer NULL\n", __func__);
754 if (params->ops->f_rx == NULL) {
755 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
761 if ((params->burst_size == 0) ||
762 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
763 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
768 /* Do we have room for one more port? */
769 if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
770 RTE_LOG(ERR, PIPELINE,
771 "%s: invalid value for num_ports_in\n", __func__);
779 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
780 struct rte_pipeline_port_out_params *params,
784 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
789 if (params == NULL) {
790 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
794 if (port_id == NULL) {
795 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
801 if (params->ops == NULL) {
802 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
807 if (params->ops->f_create == NULL) {
808 RTE_LOG(ERR, PIPELINE,
809 "%s: f_create function pointer NULL\n", __func__);
813 if (params->ops->f_tx == NULL) {
814 RTE_LOG(ERR, PIPELINE,
815 "%s: f_tx function pointer NULL\n", __func__);
819 if (params->ops->f_tx_bulk == NULL) {
820 RTE_LOG(ERR, PIPELINE,
821 "%s: f_tx_bulk function pointer NULL\n", __func__);
825 /* Do we have room for one more port? */
826 if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
827 RTE_LOG(ERR, PIPELINE,
828 "%s: invalid value for num_ports_out\n", __func__);
836 rte_pipeline_port_in_create(struct rte_pipeline *p,
837 struct rte_pipeline_port_in_params *params,
840 struct rte_port_in *port;
845 /* Check input arguments */
846 status = rte_pipeline_port_in_check_params(p, params, port_id);
850 id = p->num_ports_in;
851 port = &p->ports_in[id];
853 /* Create the port */
854 h_port = params->ops->f_create(params->arg_create, p->socket_id);
855 if (h_port == NULL) {
856 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
860 /* Commit current table to the pipeline */
864 /* Save input parameters */
865 memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
866 port->f_action = params->f_action;
867 port->arg_ah = params->arg_ah;
868 port->burst_size = params->burst_size;
870 /* Initialize port internal data structure */
871 port->table_id = RTE_TABLE_INVALID;
872 port->h_port = h_port;
879 rte_pipeline_port_in_free(struct rte_port_in *port)
881 if (port->ops.f_free != NULL)
882 port->ops.f_free(port->h_port);
886 rte_pipeline_port_out_create(struct rte_pipeline *p,
887 struct rte_pipeline_port_out_params *params,
890 struct rte_port_out *port;
895 /* Check input arguments */
896 status = rte_pipeline_port_out_check_params(p, params, port_id);
900 id = p->num_ports_out;
901 port = &p->ports_out[id];
903 /* Create the port */
904 h_port = params->ops->f_create(params->arg_create, p->socket_id);
905 if (h_port == NULL) {
906 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
910 /* Commit current table to the pipeline */
914 /* Save input parameters */
915 memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
916 port->f_action = params->f_action;
917 port->arg_ah = params->arg_ah;
919 /* Initialize port internal data structure */
920 port->h_port = h_port;
926 rte_pipeline_port_out_free(struct rte_port_out *port)
928 if (port->ops.f_free != NULL)
929 port->ops.f_free(port->h_port);
933 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
937 struct rte_port_in *port;
939 /* Check input arguments */
941 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
946 if (port_id >= p->num_ports_in) {
947 RTE_LOG(ERR, PIPELINE,
948 "%s: port IN ID %u is out of range\n",
953 if (table_id >= p->num_tables) {
954 RTE_LOG(ERR, PIPELINE,
955 "%s: Table ID %u is out of range\n",
960 port = &p->ports_in[port_id];
961 port->table_id = table_id;
967 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
969 struct rte_port_in *port, *port_prev, *port_next;
971 uint32_t port_prev_id, port_next_id;
973 /* Check input arguments */
975 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
980 if (port_id >= p->num_ports_in) {
981 RTE_LOG(ERR, PIPELINE,
982 "%s: port IN ID %u is out of range\n",
987 port = &p->ports_in[port_id];
989 /* Return if current input port is already enabled */
990 port_mask = 1LLU << port_id;
991 if (p->enabled_port_in_mask & port_mask)
994 p->enabled_port_in_mask |= port_mask;
996 /* Add current input port to the pipeline chain of enabled ports */
997 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
998 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1000 port_prev = &p->ports_in[port_prev_id];
1001 port_next = &p->ports_in[port_next_id];
1003 port_prev->next = port;
1004 port->next = port_next;
1006 /* Check if list of enabled ports was previously empty */
1007 if (p->enabled_port_in_mask == port_mask)
1008 p->port_in_next = port;
1014 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
1016 struct rte_port_in *port, *port_prev, *port_next;
1018 uint32_t port_prev_id, port_next_id;
1020 /* Check input arguments */
1022 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1027 if (port_id >= p->num_ports_in) {
1028 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
1033 port = &p->ports_in[port_id];
1035 /* Return if current input port is already disabled */
1036 port_mask = 1LLU << port_id;
1037 if ((p->enabled_port_in_mask & port_mask) == 0)
1040 p->enabled_port_in_mask &= ~port_mask;
1042 /* Return if no other enabled ports */
1043 if (p->enabled_port_in_mask == 0) {
1044 p->port_in_next = NULL;
1049 /* Add current input port to the pipeline chain of enabled ports */
1050 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
1051 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1053 port_prev = &p->ports_in[port_prev_id];
1054 port_next = &p->ports_in[port_next_id];
1056 port_prev->next = port_next;
1058 /* Check if the port which has just been disabled is next to serve */
1059 if (port == p->port_in_next)
1060 p->port_in_next = port_next;
1070 rte_pipeline_check(struct rte_pipeline *p)
1072 uint32_t port_in_id;
1074 /* Check input arguments */
1076 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1081 /* Check that pipeline has at least one input port, one table and one
1083 if (p->num_ports_in == 0) {
1084 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
1088 if (p->num_tables == 0) {
1089 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
1093 if (p->num_ports_out == 0) {
1094 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
1099 /* Check that all input ports are connected */
1100 for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
1101 struct rte_port_in *port_in = &p->ports_in[port_in_id];
1103 if (port_in->table_id == RTE_TABLE_INVALID) {
1104 RTE_LOG(ERR, PIPELINE,
1105 "%s: Port IN ID %u is not connected\n",
1106 __func__, port_in_id);
1115 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
1117 p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1118 p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1119 p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
1120 p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1122 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1123 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1126 for (i = 0; i < n_pkts; i++) {
1127 uint64_t pkt_mask = 1LLU << i;
1128 uint32_t pos = p->entries[i]->action;
1130 p->action_mask1[pos] |= pkt_mask;
1135 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1136 uint64_t pkt_mask = 1LLU << i;
1139 if ((pkt_mask & pkts_mask) == 0)
1142 pos = p->entries[i]->action;
1143 p->action_mask1[pos] |= pkt_mask;
1149 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1150 uint64_t pkts_mask, uint32_t port_id)
1152 struct rte_port_out *port_out = &p->ports_out[port_id];
1154 p->pkts_mask = pkts_mask;
1156 /* Output port user actions */
1157 if (port_out->f_action != NULL) {
1158 port_out->f_action(p, p->pkts, pkts_mask, port_out->arg_ah);
1160 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1161 port_out->n_pkts_dropped_by_ah);
1164 /* Output port TX */
1165 if (p->pkts_mask != 0)
1166 port_out->ops.f_tx_bulk(port_out->h_port,
1172 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1174 p->pkts_mask = pkts_mask;
1176 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1177 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1180 for (i = 0; i < n_pkts; i++) {
1181 struct rte_mbuf *pkt = p->pkts[i];
1182 uint32_t port_out_id = p->entries[i]->port_id;
1183 struct rte_port_out *port_out =
1184 &p->ports_out[port_out_id];
1186 /* Output port user actions */
1187 if (port_out->f_action == NULL) /* Output port TX */
1188 port_out->ops.f_tx(port_out->h_port, pkt);
1190 uint64_t pkt_mask = 1LLU << i;
1192 port_out->f_action(p,
1197 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1198 port_out->n_pkts_dropped_by_ah);
1200 /* Output port TX */
1201 if (pkt_mask & p->pkts_mask)
1202 port_out->ops.f_tx(port_out->h_port,
1209 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1210 uint64_t pkt_mask = 1LLU << i;
1211 struct rte_mbuf *pkt;
1212 struct rte_port_out *port_out;
1213 uint32_t port_out_id;
1215 if ((pkt_mask & pkts_mask) == 0)
1219 port_out_id = p->entries[i]->port_id;
1220 port_out = &p->ports_out[port_out_id];
1222 /* Output port user actions */
1223 if (port_out->f_action == NULL) /* Output port TX */
1224 port_out->ops.f_tx(port_out->h_port, pkt);
1226 port_out->f_action(p,
1231 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1232 port_out->n_pkts_dropped_by_ah);
1234 /* Output port TX */
1235 if (pkt_mask & p->pkts_mask)
1236 port_out->ops.f_tx(port_out->h_port,
1244 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1247 p->pkts_mask = pkts_mask;
1249 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1250 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1253 for (i = 0; i < n_pkts; i++) {
1254 struct rte_mbuf *pkt = p->pkts[i];
1255 uint32_t port_out_id =
1256 RTE_MBUF_METADATA_UINT32(pkt,
1258 struct rte_port_out *port_out = &p->ports_out[
1261 /* Output port user actions */
1262 if (port_out->f_action == NULL) /* Output port TX */
1263 port_out->ops.f_tx(port_out->h_port, pkt);
1265 uint64_t pkt_mask = 1LLU << i;
1267 port_out->f_action(p,
1272 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1273 port_out->n_pkts_dropped_by_ah);
1275 /* Output port TX */
1276 if (pkt_mask & p->pkts_mask)
1277 port_out->ops.f_tx(port_out->h_port,
1284 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1285 uint64_t pkt_mask = 1LLU << i;
1286 struct rte_mbuf *pkt;
1287 struct rte_port_out *port_out;
1288 uint32_t port_out_id;
1290 if ((pkt_mask & pkts_mask) == 0)
1294 port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1296 port_out = &p->ports_out[port_out_id];
1298 /* Output port user actions */
1299 if (port_out->f_action == NULL) /* Output port TX */
1300 port_out->ops.f_tx(port_out->h_port, pkt);
1302 port_out->f_action(p,
1307 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1308 port_out->n_pkts_dropped_by_ah);
1310 /* Output port TX */
1311 if (pkt_mask & p->pkts_mask)
1312 port_out->ops.f_tx(port_out->h_port,
1320 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1322 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1323 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1326 for (i = 0; i < n_pkts; i++)
1327 rte_pktmbuf_free(p->pkts[i]);
1331 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1332 uint64_t pkt_mask = 1LLU << i;
1334 if ((pkt_mask & pkts_mask) == 0)
1337 rte_pktmbuf_free(p->pkts[i]);
1343 rte_pipeline_run(struct rte_pipeline *p)
1345 struct rte_port_in *port_in = p->port_in_next;
1346 uint32_t n_pkts, table_id;
1348 if (port_in == NULL)
1352 n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1353 port_in->burst_size);
1355 p->port_in_next = port_in->next;
1359 p->pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1360 p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1361 p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1362 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1363 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1365 /* Input port user actions */
1366 if (port_in->f_action != NULL) {
1367 port_in->f_action(p, p->pkts, n_pkts, port_in->arg_ah);
1369 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1370 port_in->n_pkts_dropped_by_ah);
1374 for (table_id = port_in->table_id; p->pkts_mask != 0; ) {
1375 struct rte_table *table;
1376 uint64_t lookup_hit_mask, lookup_miss_mask;
1379 table = &p->tables[table_id];
1380 table->ops.f_lookup(table->h_table, p->pkts, p->pkts_mask,
1381 &lookup_hit_mask, (void **) p->entries);
1382 lookup_miss_mask = p->pkts_mask & (~lookup_hit_mask);
1385 if (lookup_miss_mask != 0) {
1386 struct rte_pipeline_table_entry *default_entry =
1387 table->default_entry;
1389 p->pkts_mask = lookup_miss_mask;
1391 /* Table user actions */
1392 if (table->f_action_miss != NULL) {
1393 table->f_action_miss(p,
1399 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1400 table->n_pkts_dropped_by_lkp_miss_ah);
1403 /* Table reserved actions */
1404 if ((default_entry->action == RTE_PIPELINE_ACTION_PORT) &&
1405 (p->pkts_mask != 0))
1406 rte_pipeline_action_handler_port_bulk(p,
1408 default_entry->port_id);
1410 uint32_t pos = default_entry->action;
1412 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1414 p->action_mask0[pos] |= p->pkts_mask;
1416 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1417 table->n_pkts_dropped_lkp_miss);
1422 if (lookup_hit_mask != 0) {
1423 p->pkts_mask = lookup_hit_mask;
1425 /* Table user actions */
1426 if (table->f_action_hit != NULL) {
1427 table->f_action_hit(p,
1433 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1434 table->n_pkts_dropped_by_lkp_hit_ah);
1437 /* Table reserved actions */
1438 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1439 rte_pipeline_compute_masks(p, p->pkts_mask);
1440 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1442 RTE_PIPELINE_ACTION_DROP];
1443 p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1445 RTE_PIPELINE_ACTION_PORT];
1446 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1448 RTE_PIPELINE_ACTION_PORT_META];
1449 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1451 RTE_PIPELINE_ACTION_TABLE];
1453 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1454 table->n_pkts_dropped_lkp_hit);
1457 /* Prepare for next iteration */
1458 p->pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1459 table_id = table->table_next_id;
1460 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1463 /* Table reserved action PORT */
1464 rte_pipeline_action_handler_port(p,
1465 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1467 /* Table reserved action PORT META */
1468 rte_pipeline_action_handler_port_meta(p,
1469 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1471 /* Table reserved action DROP */
1472 rte_pipeline_action_handler_drop(p,
1473 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1475 /* Pick candidate for next port IN to serve */
1476 p->port_in_next = port_in->next;
1478 return (int) n_pkts;
1482 rte_pipeline_flush(struct rte_pipeline *p)
1486 /* Check input arguments */
1488 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1493 for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1494 struct rte_port_out *port = &p->ports_out[port_id];
1496 if (port->ops.f_flush != NULL)
1497 port->ops.f_flush(port->h_port);
1504 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1505 uint32_t port_id, struct rte_mbuf *pkt)
1507 struct rte_port_out *port_out = &p->ports_out[port_id];
1509 port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1514 int rte_pipeline_ah_packet_hijack(struct rte_pipeline *p,
1517 pkts_mask &= p->pkts_mask;
1518 p->pkts_mask &= ~pkts_mask;
1523 int rte_pipeline_ah_packet_drop(struct rte_pipeline *p,
1526 pkts_mask &= p->pkts_mask;
1527 p->pkts_mask &= ~pkts_mask;
1528 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask;
1530 RTE_PIPELINE_STATS_AH_DROP_WRITE(p, pkts_mask);
1534 int rte_pipeline_port_in_stats_read(struct rte_pipeline *p, uint32_t port_id,
1535 struct rte_pipeline_port_in_stats *stats, int clear)
1537 struct rte_port_in *port;
1541 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1546 if (port_id >= p->num_ports_in) {
1547 RTE_LOG(ERR, PIPELINE,
1548 "%s: port IN ID %u is out of range\n",
1553 port = &p->ports_in[port_id];
1555 if (port->ops.f_stats != NULL) {
1556 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1559 } else if (stats != NULL)
1560 memset(&stats->stats, 0, sizeof(stats->stats));
1563 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1566 port->n_pkts_dropped_by_ah = 0;
1571 int rte_pipeline_port_out_stats_read(struct rte_pipeline *p, uint32_t port_id,
1572 struct rte_pipeline_port_out_stats *stats, int clear)
1574 struct rte_port_out *port;
1578 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n", __func__);
1582 if (port_id >= p->num_ports_out) {
1583 RTE_LOG(ERR, PIPELINE,
1584 "%s: port OUT ID %u is out of range\n", __func__, port_id);
1588 port = &p->ports_out[port_id];
1589 if (port->ops.f_stats != NULL) {
1590 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1593 } else if (stats != NULL)
1594 memset(&stats->stats, 0, sizeof(stats->stats));
1597 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1600 port->n_pkts_dropped_by_ah = 0;
1605 int rte_pipeline_table_stats_read(struct rte_pipeline *p, uint32_t table_id,
1606 struct rte_pipeline_table_stats *stats, int clear)
1608 struct rte_table *table;
1612 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1617 if (table_id >= p->num_tables) {
1618 RTE_LOG(ERR, PIPELINE,
1619 "%s: table %u is out of range\n", __func__, table_id);
1623 table = &p->tables[table_id];
1624 if (table->ops.f_stats != NULL) {
1625 retval = table->ops.f_stats(table->h_table, &stats->stats, clear);
1628 } else if (stats != NULL)
1629 memset(&stats->stats, 0, sizeof(stats->stats));
1631 if (stats != NULL) {
1632 stats->n_pkts_dropped_by_lkp_hit_ah =
1633 table->n_pkts_dropped_by_lkp_hit_ah;
1634 stats->n_pkts_dropped_by_lkp_miss_ah =
1635 table->n_pkts_dropped_by_lkp_miss_ah;
1636 stats->n_pkts_dropped_lkp_hit = table->n_pkts_dropped_lkp_hit;
1637 stats->n_pkts_dropped_lkp_miss = table->n_pkts_dropped_lkp_miss;
1641 table->n_pkts_dropped_by_lkp_hit_ah = 0;
1642 table->n_pkts_dropped_by_lkp_miss_ah = 0;
1643 table->n_pkts_dropped_lkp_hit = 0;
1644 table->n_pkts_dropped_lkp_miss = 0;