4 * Copyright(c) 2010-2014 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_memzone.h>
40 #include <rte_cycles.h>
41 #include <rte_prefetch.h>
42 #include <rte_branch_prediction.h>
44 #include <rte_malloc.h>
45 #include <rte_string_fns.h>
47 #include "rte_pipeline.h"
49 #define RTE_TABLE_INVALID UINT32_MAX
52 /* Input parameters */
53 struct rte_port_in_ops ops;
54 rte_pipeline_port_in_action_handler f_action;
58 /* The table to which this port is connected */
61 /* Handle to low-level port */
64 /* List of enabled ports */
65 struct rte_port_in *next;
69 /* Input parameters */
70 struct rte_port_out_ops ops;
71 rte_pipeline_port_out_action_handler f_action;
72 rte_pipeline_port_out_action_handler_bulk f_action_bulk;
75 /* Handle to low-level port */
80 /* Input parameters */
81 struct rte_table_ops ops;
82 rte_pipeline_table_action_handler_hit f_action_hit;
83 rte_pipeline_table_action_handler_miss f_action_miss;
85 struct rte_pipeline_table_entry *default_entry;
88 uint32_t table_next_id;
89 uint32_t table_next_id_valid;
91 /* Handle to the low-level table object */
95 #define RTE_PIPELINE_MAX_NAME_SZ 124
98 /* Input parameters */
99 char name[RTE_PIPELINE_MAX_NAME_SZ];
101 uint32_t offset_port_id;
103 /* Internal tables */
104 struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
105 struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
106 struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
108 /* Occupancy of internal tables */
109 uint32_t num_ports_in;
110 uint32_t num_ports_out;
113 /* List of enabled ports */
114 uint64_t enabled_port_in_mask;
115 struct rte_port_in *port_in_first;
117 /* Pipeline run structures */
118 struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
119 struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
120 uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
121 uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
122 } __rte_cache_aligned;
124 static inline uint32_t
125 rte_mask_get_next(uint64_t mask, uint32_t pos)
127 uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
128 (mask >> ((pos + 1) & 0x3F));
129 return (__builtin_ctzll(mask_rot) - (63 - pos)) & 0x3F;
132 static inline uint32_t
133 rte_mask_get_prev(uint64_t mask, uint32_t pos)
135 uint64_t mask_rot = (mask >> (pos & 0x3F)) |
136 (mask << ((64 - pos) & 0x3F));
137 return ((63 - __builtin_clzll(mask_rot)) + pos) & 0x3F;
141 rte_pipeline_table_free(struct rte_table *table);
144 rte_pipeline_port_in_free(struct rte_port_in *port);
147 rte_pipeline_port_out_free(struct rte_port_out *port);
154 rte_pipeline_check_params(struct rte_pipeline_params *params)
156 if (params == NULL) {
157 RTE_LOG(ERR, PIPELINE,
158 "%s: Incorrect value for parameter params\n", __func__);
163 if (params->name == NULL) {
164 RTE_LOG(ERR, PIPELINE,
165 "%s: Incorrect value for parameter name\n", __func__);
170 if ((params->socket_id < 0) ||
171 (params->socket_id >= RTE_MAX_NUMA_NODES)) {
172 RTE_LOG(ERR, PIPELINE,
173 "%s: Incorrect value for parameter socket_id\n",
181 struct rte_pipeline *
182 rte_pipeline_create(struct rte_pipeline_params *params)
184 struct rte_pipeline *p;
187 /* Check input parameters */
188 status = rte_pipeline_check_params(params);
190 RTE_LOG(ERR, PIPELINE,
191 "%s: Pipeline params check failed (%d)\n",
196 /* Allocate memory for the pipeline on requested socket */
197 p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
198 RTE_CACHE_LINE_SIZE, params->socket_id);
201 RTE_LOG(ERR, PIPELINE,
202 "%s: Pipeline memory allocation failed\n", __func__);
206 /* Save input parameters */
207 snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
208 p->socket_id = params->socket_id;
209 p->offset_port_id = params->offset_port_id;
211 /* Initialize pipeline internal data structure */
213 p->num_ports_out = 0;
215 p->enabled_port_in_mask = 0;
216 p->port_in_first = NULL;
222 rte_pipeline_free(struct rte_pipeline *p)
226 /* Check input parameters */
228 RTE_LOG(ERR, PIPELINE,
229 "%s: rte_pipeline parameter is NULL\n", __func__);
233 /* Free input ports */
234 for (i = 0; i < p->num_ports_in; i++) {
235 struct rte_port_in *port = &p->ports_in[i];
237 rte_pipeline_port_in_free(port);
241 for (i = 0; i < p->num_tables; i++) {
242 struct rte_table *table = &p->tables[i];
244 rte_pipeline_table_free(table);
247 /* Free output ports */
248 for (i = 0; i < p->num_ports_out; i++) {
249 struct rte_port_out *port = &p->ports_out[i];
251 rte_pipeline_port_out_free(port);
254 /* Free pipeline memory */
265 rte_table_check_params(struct rte_pipeline *p,
266 struct rte_pipeline_table_params *params,
270 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
274 if (params == NULL) {
275 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
279 if (table_id == NULL) {
280 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
286 if (params->ops == NULL) {
287 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
292 if (params->ops->f_create == NULL) {
293 RTE_LOG(ERR, PIPELINE,
294 "%s: f_create function pointer is NULL\n", __func__);
298 if (params->ops->f_lookup == NULL) {
299 RTE_LOG(ERR, PIPELINE,
300 "%s: f_lookup function pointer is NULL\n", __func__);
304 /* De we have room for one more table? */
305 if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
306 RTE_LOG(ERR, PIPELINE,
307 "%s: Incorrect value for num_tables parameter\n",
316 rte_pipeline_table_create(struct rte_pipeline *p,
317 struct rte_pipeline_table_params *params,
320 struct rte_table *table;
321 struct rte_pipeline_table_entry *default_entry;
323 uint32_t entry_size, id;
326 /* Check input arguments */
327 status = rte_table_check_params(p, params, table_id);
332 table = &p->tables[id];
334 /* Allocate space for the default table entry */
335 entry_size = sizeof(struct rte_pipeline_table_entry) +
336 params->action_data_size;
337 default_entry = (struct rte_pipeline_table_entry *) rte_zmalloc_socket(
338 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
339 if (default_entry == NULL) {
340 RTE_LOG(ERR, PIPELINE,
341 "%s: Failed to allocate default entry\n", __func__);
345 /* Create the table */
346 h_table = params->ops->f_create(params->arg_create, p->socket_id,
348 if (h_table == NULL) {
349 rte_free(default_entry);
350 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
354 /* Commit current table to the pipeline */
358 /* Save input parameters */
359 memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
360 table->f_action_hit = params->f_action_hit;
361 table->f_action_miss = params->f_action_miss;
362 table->arg_ah = params->arg_ah;
363 table->entry_size = entry_size;
365 /* Clear the lookup miss actions (to be set later through API) */
366 table->default_entry = default_entry;
367 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
369 /* Initialize table internal data structure */
370 table->h_table = h_table;
371 table->table_next_id = 0;
372 table->table_next_id_valid = 0;
378 rte_pipeline_table_free(struct rte_table *table)
380 if (table->ops.f_free != NULL)
381 table->ops.f_free(table->h_table);
383 rte_free(table->default_entry);
387 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
389 struct rte_pipeline_table_entry *default_entry,
390 struct rte_pipeline_table_entry **default_entry_ptr)
392 struct rte_table *table;
394 /* Check input arguments */
396 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
401 if (default_entry == NULL) {
402 RTE_LOG(ERR, PIPELINE,
403 "%s: default_entry parameter is NULL\n", __func__);
407 if (table_id >= p->num_tables) {
408 RTE_LOG(ERR, PIPELINE,
409 "%s: table_id %d out of range\n", __func__, table_id);
413 table = &p->tables[table_id];
415 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
416 table->table_next_id_valid &&
417 (default_entry->table_id != table->table_next_id)) {
418 RTE_LOG(ERR, PIPELINE,
419 "%s: Tree-like topologies not allowed\n", __func__);
423 /* Set the lookup miss actions */
424 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
425 (table->table_next_id_valid == 0)) {
426 table->table_next_id = default_entry->table_id;
427 table->table_next_id_valid = 1;
430 memcpy(table->default_entry, default_entry, table->entry_size);
432 *default_entry_ptr = table->default_entry;
437 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
439 struct rte_pipeline_table_entry *entry)
441 struct rte_table *table;
443 /* Check input arguments */
445 RTE_LOG(ERR, PIPELINE,
446 "%s: pipeline parameter is NULL\n", __func__);
450 if (table_id >= p->num_tables) {
451 RTE_LOG(ERR, PIPELINE,
452 "%s: table_id %d out of range\n", __func__, table_id);
456 table = &p->tables[table_id];
458 /* Save the current contents of the default entry */
460 memcpy(entry, table->default_entry, table->entry_size);
462 /* Clear the lookup miss actions */
463 memset(table->default_entry, 0, table->entry_size);
464 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
470 rte_pipeline_table_entry_add(struct rte_pipeline *p,
473 struct rte_pipeline_table_entry *entry,
475 struct rte_pipeline_table_entry **entry_ptr)
477 struct rte_table *table;
479 /* Check input arguments */
481 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
487 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
492 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
497 if (table_id >= p->num_tables) {
498 RTE_LOG(ERR, PIPELINE,
499 "%s: table_id %d out of range\n", __func__, table_id);
503 table = &p->tables[table_id];
505 if (table->ops.f_add == NULL) {
506 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
511 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
512 table->table_next_id_valid &&
513 (entry->table_id != table->table_next_id)) {
514 RTE_LOG(ERR, PIPELINE,
515 "%s: Tree-like topologies not allowed\n", __func__);
520 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
521 (table->table_next_id_valid == 0)) {
522 table->table_next_id = entry->table_id;
523 table->table_next_id_valid = 1;
526 return (table->ops.f_add)(table->h_table, key, (void *) entry,
527 key_found, (void **) entry_ptr);
531 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
535 struct rte_pipeline_table_entry *entry)
537 struct rte_table *table;
539 /* Check input arguments */
541 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
547 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
552 if (table_id >= p->num_tables) {
553 RTE_LOG(ERR, PIPELINE,
554 "%s: table_id %d out of range\n", __func__, table_id);
558 table = &p->tables[table_id];
560 if (table->ops.f_delete == NULL) {
561 RTE_LOG(ERR, PIPELINE,
562 "%s: f_delete function pointer NULL\n", __func__);
566 return (table->ops.f_delete)(table->h_table, key, key_found, entry);
574 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
575 struct rte_pipeline_port_in_params *params,
579 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
583 if (params == NULL) {
584 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
587 if (port_id == NULL) {
588 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
594 if (params->ops == NULL) {
595 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
600 if (params->ops->f_create == NULL) {
601 RTE_LOG(ERR, PIPELINE,
602 "%s: f_create function pointer NULL\n", __func__);
606 if (params->ops->f_rx == NULL) {
607 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
613 if ((params->burst_size == 0) ||
614 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
615 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
620 /* Do we have room for one more port? */
621 if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
622 RTE_LOG(ERR, PIPELINE,
623 "%s: invalid value for num_ports_in\n", __func__);
631 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
632 struct rte_pipeline_port_out_params *params,
635 rte_pipeline_port_out_action_handler f_ah;
636 rte_pipeline_port_out_action_handler_bulk f_ah_bulk;
639 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
644 if (params == NULL) {
645 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
649 if (port_id == NULL) {
650 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
656 if (params->ops == NULL) {
657 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
662 if (params->ops->f_create == NULL) {
663 RTE_LOG(ERR, PIPELINE,
664 "%s: f_create function pointer NULL\n", __func__);
668 if (params->ops->f_tx == NULL) {
669 RTE_LOG(ERR, PIPELINE,
670 "%s: f_tx function pointer NULL\n", __func__);
674 if (params->ops->f_tx_bulk == NULL) {
675 RTE_LOG(ERR, PIPELINE,
676 "%s: f_tx_bulk function pointer NULL\n", __func__);
680 f_ah = params->f_action;
681 f_ah_bulk = params->f_action_bulk;
682 if (((f_ah != NULL) && (f_ah_bulk == NULL)) ||
683 ((f_ah == NULL) && (f_ah_bulk != NULL))) {
684 RTE_LOG(ERR, PIPELINE, "%s: Action handlers have to be either"
685 "both enabled or both disabled\n", __func__);
689 /* Do we have room for one more port? */
690 if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
691 RTE_LOG(ERR, PIPELINE,
692 "%s: invalid value for num_ports_out\n", __func__);
700 rte_pipeline_port_in_create(struct rte_pipeline *p,
701 struct rte_pipeline_port_in_params *params,
704 struct rte_port_in *port;
709 /* Check input arguments */
710 status = rte_pipeline_port_in_check_params(p, params, port_id);
714 id = p->num_ports_in;
715 port = &p->ports_in[id];
717 /* Create the port */
718 h_port = params->ops->f_create(params->arg_create, p->socket_id);
719 if (h_port == NULL) {
720 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
724 /* Commit current table to the pipeline */
728 /* Save input parameters */
729 memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
730 port->f_action = params->f_action;
731 port->arg_ah = params->arg_ah;
732 port->burst_size = params->burst_size;
734 /* Initialize port internal data structure */
735 port->table_id = RTE_TABLE_INVALID;
736 port->h_port = h_port;
743 rte_pipeline_port_in_free(struct rte_port_in *port)
745 if (port->ops.f_free != NULL)
746 port->ops.f_free(port->h_port);
750 rte_pipeline_port_out_create(struct rte_pipeline *p,
751 struct rte_pipeline_port_out_params *params,
754 struct rte_port_out *port;
759 /* Check input arguments */
760 status = rte_pipeline_port_out_check_params(p, params, port_id);
764 id = p->num_ports_out;
765 port = &p->ports_out[id];
767 /* Create the port */
768 h_port = params->ops->f_create(params->arg_create, p->socket_id);
769 if (h_port == NULL) {
770 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
774 /* Commit current table to the pipeline */
778 /* Save input parameters */
779 memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
780 port->f_action = params->f_action;
781 port->f_action_bulk = params->f_action_bulk;
782 port->arg_ah = params->arg_ah;
784 /* Initialize port internal data structure */
785 port->h_port = h_port;
791 rte_pipeline_port_out_free(struct rte_port_out *port)
793 if (port->ops.f_free != NULL)
794 port->ops.f_free(port->h_port);
798 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
802 struct rte_port_in *port;
804 /* Check input arguments */
806 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
811 if (port_id >= p->num_ports_in) {
812 RTE_LOG(ERR, PIPELINE,
813 "%s: port IN ID %u is out of range\n",
818 if (table_id >= p->num_tables) {
819 RTE_LOG(ERR, PIPELINE,
820 "%s: Table ID %u is out of range\n",
825 port = &p->ports_in[port_id];
826 port->table_id = table_id;
832 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
834 struct rte_port_in *port, *port_prev, *port_next;
835 struct rte_port_in *port_first, *port_last;
837 uint32_t port_prev_id, port_next_id, port_first_id, port_last_id;
839 /* Check input arguments */
841 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
846 if (port_id >= p->num_ports_in) {
847 RTE_LOG(ERR, PIPELINE,
848 "%s: port IN ID %u is out of range\n",
853 /* Return if current input port is already enabled */
854 port_mask = 1LLU << port_id;
855 if (p->enabled_port_in_mask & port_mask)
858 p->enabled_port_in_mask |= port_mask;
860 /* Add current input port to the pipeline chain of enabled ports */
861 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
862 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
864 port_prev = &p->ports_in[port_prev_id];
865 port_next = &p->ports_in[port_next_id];
866 port = &p->ports_in[port_id];
868 port_prev->next = port;
869 port->next = port_next;
871 /* Update the first and last input ports in the chain */
872 port_first_id = __builtin_ctzll(p->enabled_port_in_mask);
873 port_last_id = 63 - __builtin_clzll(p->enabled_port_in_mask);
875 port_first = &p->ports_in[port_first_id];
876 port_last = &p->ports_in[port_last_id];
878 p->port_in_first = port_first;
879 port_last->next = NULL;
885 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
887 struct rte_port_in *port_prev, *port_next, *port_first, *port_last;
889 uint32_t port_prev_id, port_next_id, port_first_id, port_last_id;
891 /* Check input arguments */
893 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
898 if (port_id >= p->num_ports_in) {
899 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
904 /* Return if current input port is already disabled */
905 port_mask = 1LLU << port_id;
906 if ((p->enabled_port_in_mask & port_mask) == 0)
909 /* Return if no other enabled ports */
910 if (__builtin_popcountll(p->enabled_port_in_mask) == 1) {
911 p->enabled_port_in_mask &= ~port_mask;
912 p->port_in_first = NULL;
917 /* Add current input port to the pipeline chain of enabled ports */
918 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
919 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
921 port_prev = &p->ports_in[port_prev_id];
922 port_next = &p->ports_in[port_next_id];
924 port_prev->next = port_next;
925 p->enabled_port_in_mask &= ~port_mask;
927 /* Update the first and last input ports in the chain */
928 port_first_id = __builtin_ctzll(p->enabled_port_in_mask);
929 port_last_id = 63 - __builtin_clzll(p->enabled_port_in_mask);
931 port_first = &p->ports_in[port_first_id];
932 port_last = &p->ports_in[port_last_id];
934 p->port_in_first = port_first;
935 port_last->next = NULL;
945 rte_pipeline_check(struct rte_pipeline *p)
949 /* Check input arguments */
951 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
956 /* Check that pipeline has at least one input port, one table and one
958 if (p->num_ports_in == 0) {
959 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
963 if (p->num_tables == 0) {
964 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
968 if (p->num_ports_out == 0) {
969 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
974 /* Check that all input ports are connected */
975 for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
976 struct rte_port_in *port_in = &p->ports_in[port_in_id];
978 if (port_in->table_id == RTE_TABLE_INVALID) {
979 RTE_LOG(ERR, PIPELINE,
980 "%s: Port IN ID %u is not connected\n",
981 __func__, port_in_id);
990 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
992 p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
993 p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
994 p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
995 p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
997 if ((pkts_mask & (pkts_mask + 1)) == 0) {
998 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1001 for (i = 0; i < n_pkts; i++) {
1002 uint64_t pkt_mask = 1LLU << i;
1003 uint32_t pos = p->entries[i]->action;
1005 p->action_mask1[pos] |= pkt_mask;
1010 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1011 uint64_t pkt_mask = 1LLU << i;
1014 if ((pkt_mask & pkts_mask) == 0)
1017 pos = p->entries[i]->action;
1018 p->action_mask1[pos] |= pkt_mask;
1024 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1025 uint64_t pkts_mask, uint32_t port_id)
1027 struct rte_port_out *port_out = &p->ports_out[port_id];
1029 /* Output port user actions */
1030 if (port_out->f_action_bulk != NULL) {
1031 uint64_t mask = pkts_mask;
1033 port_out->f_action_bulk(p->pkts, &pkts_mask, port_out->arg_ah);
1034 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask ^ mask;
1037 /* Output port TX */
1039 port_out->ops.f_tx_bulk(port_out->h_port, p->pkts, pkts_mask);
1043 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1045 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1046 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1049 for (i = 0; i < n_pkts; i++) {
1050 struct rte_mbuf *pkt = p->pkts[i];
1051 uint32_t port_out_id = p->entries[i]->port_id;
1052 struct rte_port_out *port_out =
1053 &p->ports_out[port_out_id];
1055 /* Output port user actions */
1056 if (port_out->f_action == NULL) /* Output port TX */
1057 port_out->ops.f_tx(port_out->h_port, pkt);
1059 uint64_t pkt_mask = 1LLU;
1061 port_out->f_action(pkt, &pkt_mask,
1063 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1064 (pkt_mask ^ 1LLU) << i;
1066 /* Output port TX */
1068 port_out->ops.f_tx(port_out->h_port,
1075 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1076 uint64_t pkt_mask = 1LLU << i;
1077 struct rte_mbuf *pkt;
1078 struct rte_port_out *port_out;
1079 uint32_t port_out_id;
1081 if ((pkt_mask & pkts_mask) == 0)
1085 port_out_id = p->entries[i]->port_id;
1086 port_out = &p->ports_out[port_out_id];
1088 /* Output port user actions */
1089 if (port_out->f_action == NULL) /* Output port TX */
1090 port_out->ops.f_tx(port_out->h_port, pkt);
1094 port_out->f_action(pkt, &pkt_mask,
1096 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1097 (pkt_mask ^ 1LLU) << i;
1099 /* Output port TX */
1101 port_out->ops.f_tx(port_out->h_port,
1109 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1112 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1113 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1116 for (i = 0; i < n_pkts; i++) {
1117 struct rte_mbuf *pkt = p->pkts[i];
1118 uint32_t port_out_id =
1119 RTE_MBUF_METADATA_UINT32(pkt,
1121 struct rte_port_out *port_out = &p->ports_out[
1124 /* Output port user actions */
1125 if (port_out->f_action == NULL) /* Output port TX */
1126 port_out->ops.f_tx(port_out->h_port, pkt);
1128 uint64_t pkt_mask = 1LLU;
1130 port_out->f_action(pkt, &pkt_mask,
1132 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1133 (pkt_mask ^ 1LLU) << i;
1135 /* Output port TX */
1137 port_out->ops.f_tx(port_out->h_port,
1144 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1145 uint64_t pkt_mask = 1LLU << i;
1146 struct rte_mbuf *pkt;
1147 struct rte_port_out *port_out;
1148 uint32_t port_out_id;
1150 if ((pkt_mask & pkts_mask) == 0)
1154 port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1156 port_out = &p->ports_out[port_out_id];
1158 /* Output port user actions */
1159 if (port_out->f_action == NULL) /* Output port TX */
1160 port_out->ops.f_tx(port_out->h_port, pkt);
1164 port_out->f_action(pkt, &pkt_mask,
1166 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1167 (pkt_mask ^ 1LLU) << i;
1169 /* Output port TX */
1171 port_out->ops.f_tx(port_out->h_port,
1179 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1181 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1182 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1185 for (i = 0; i < n_pkts; i++)
1186 rte_pktmbuf_free(p->pkts[i]);
1190 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1191 uint64_t pkt_mask = 1LLU << i;
1193 if ((pkt_mask & pkts_mask) == 0)
1196 rte_pktmbuf_free(p->pkts[i]);
1202 rte_pipeline_run(struct rte_pipeline *p)
1204 struct rte_port_in *port_in;
1206 for (port_in = p->port_in_first; port_in != NULL;
1207 port_in = port_in->next) {
1209 uint32_t n_pkts, table_id;
1212 n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1213 port_in->burst_size);
1217 pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1218 p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1219 p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1220 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1221 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1223 /* Input port user actions */
1224 if (port_in->f_action != NULL) {
1225 uint64_t mask = pkts_mask;
1227 port_in->f_action(p->pkts, n_pkts, &pkts_mask,
1229 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1234 for (table_id = port_in->table_id; pkts_mask != 0; ) {
1235 struct rte_table *table;
1236 uint64_t lookup_hit_mask, lookup_miss_mask;
1239 table = &p->tables[table_id];
1240 table->ops.f_lookup(table->h_table, p->pkts, pkts_mask,
1241 &lookup_hit_mask, (void **) p->entries);
1242 lookup_miss_mask = pkts_mask & (~lookup_hit_mask);
1245 if (lookup_miss_mask != 0) {
1246 struct rte_pipeline_table_entry *default_entry =
1247 table->default_entry;
1249 /* Table user actions */
1250 if (table->f_action_miss != NULL) {
1251 uint64_t mask = lookup_miss_mask;
1253 table->f_action_miss(p->pkts,
1255 default_entry, table->arg_ah);
1257 RTE_PIPELINE_ACTION_DROP] |=
1258 lookup_miss_mask ^ mask;
1261 /* Table reserved actions */
1262 if ((default_entry->action ==
1263 RTE_PIPELINE_ACTION_PORT) &&
1264 (lookup_miss_mask != 0))
1265 rte_pipeline_action_handler_port_bulk(p,
1267 default_entry->port_id);
1269 uint32_t pos = default_entry->action;
1271 p->action_mask0[pos] = lookup_miss_mask;
1276 if (lookup_hit_mask != 0) {
1277 /* Table user actions */
1278 if (table->f_action_hit != NULL) {
1279 uint64_t mask = lookup_hit_mask;
1281 table->f_action_hit(p->pkts,
1283 p->entries, table->arg_ah);
1285 RTE_PIPELINE_ACTION_DROP] |=
1286 lookup_hit_mask ^ mask;
1289 /* Table reserved actions */
1290 rte_pipeline_compute_masks(p, lookup_hit_mask);
1291 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1293 RTE_PIPELINE_ACTION_DROP];
1294 p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1296 RTE_PIPELINE_ACTION_PORT];
1297 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1299 RTE_PIPELINE_ACTION_PORT_META];
1300 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1302 RTE_PIPELINE_ACTION_TABLE];
1305 /* Prepare for next iteration */
1306 pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1307 table_id = table->table_next_id;
1308 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1311 /* Table reserved action PORT */
1312 rte_pipeline_action_handler_port(p,
1313 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1315 /* Table reserved action PORT META */
1316 rte_pipeline_action_handler_port_meta(p,
1317 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1319 /* Table reserved action DROP */
1320 rte_pipeline_action_handler_drop(p,
1321 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1328 rte_pipeline_flush(struct rte_pipeline *p)
1332 /* Check input arguments */
1334 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1339 for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1340 struct rte_port_out *port = &p->ports_out[port_id];
1342 if (port->ops.f_flush != NULL)
1343 port->ops.f_flush(port->h_port);
1350 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1351 uint32_t port_id, struct rte_mbuf *pkt)
1353 struct rte_port_out *port_out = &p->ports_out[port_id];
1355 /* Output port user actions */
1356 if (port_out->f_action == NULL)
1357 port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1359 uint64_t pkt_mask = 1LLU;
1361 port_out->f_action(pkt, &pkt_mask, port_out->arg_ah);
1363 if (pkt_mask != 0) /* Output port TX */
1364 port_out->ops.f_tx(port_out->h_port, pkt);
1366 rte_pktmbuf_free(pkt);