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",
179 if (params->offset_port_id & 0x3) {
180 RTE_LOG(ERR, PIPELINE,
181 "%s: Incorrect value for parameter offset_port_id\n",
189 struct rte_pipeline *
190 rte_pipeline_create(struct rte_pipeline_params *params)
192 struct rte_pipeline *p;
195 /* Check input parameters */
196 status = rte_pipeline_check_params(params);
198 RTE_LOG(ERR, PIPELINE,
199 "%s: Pipeline params check failed (%d)\n",
204 /* Allocate memory for the pipeline on requested socket */
205 p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
206 RTE_CACHE_LINE_SIZE, params->socket_id);
209 RTE_LOG(ERR, PIPELINE,
210 "%s: Pipeline memory allocation failed\n", __func__);
214 /* Save input parameters */
215 snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
216 p->socket_id = params->socket_id;
217 p->offset_port_id = params->offset_port_id;
219 /* Initialize pipeline internal data structure */
221 p->num_ports_out = 0;
223 p->enabled_port_in_mask = 0;
224 p->port_in_first = NULL;
230 rte_pipeline_free(struct rte_pipeline *p)
234 /* Check input parameters */
236 RTE_LOG(ERR, PIPELINE,
237 "%s: rte_pipeline parameter is NULL\n", __func__);
241 /* Free input ports */
242 for (i = 0; i < p->num_ports_in; i++) {
243 struct rte_port_in *port = &p->ports_in[i];
245 rte_pipeline_port_in_free(port);
249 for (i = 0; i < p->num_tables; i++) {
250 struct rte_table *table = &p->tables[i];
252 rte_pipeline_table_free(table);
255 /* Free output ports */
256 for (i = 0; i < p->num_ports_out; i++) {
257 struct rte_port_out *port = &p->ports_out[i];
259 rte_pipeline_port_out_free(port);
262 /* Free pipeline memory */
273 rte_table_check_params(struct rte_pipeline *p,
274 struct rte_pipeline_table_params *params,
278 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
282 if (params == NULL) {
283 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
287 if (table_id == NULL) {
288 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
294 if (params->ops == NULL) {
295 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
300 if (params->ops->f_create == NULL) {
301 RTE_LOG(ERR, PIPELINE,
302 "%s: f_create function pointer is NULL\n", __func__);
306 if (params->ops->f_lookup == NULL) {
307 RTE_LOG(ERR, PIPELINE,
308 "%s: f_lookup function pointer is NULL\n", __func__);
312 /* De we have room for one more table? */
313 if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
314 RTE_LOG(ERR, PIPELINE,
315 "%s: Incorrect value for num_tables parameter\n",
324 rte_pipeline_table_create(struct rte_pipeline *p,
325 struct rte_pipeline_table_params *params,
328 struct rte_table *table;
329 struct rte_pipeline_table_entry *default_entry;
331 uint32_t entry_size, id;
334 /* Check input arguments */
335 status = rte_table_check_params(p, params, table_id);
340 table = &p->tables[id];
342 /* Allocate space for the default table entry */
343 entry_size = sizeof(struct rte_pipeline_table_entry) +
344 params->action_data_size;
345 default_entry = (struct rte_pipeline_table_entry *) rte_zmalloc_socket(
346 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
347 if (default_entry == NULL) {
348 RTE_LOG(ERR, PIPELINE,
349 "%s: Failed to allocate default entry\n", __func__);
353 /* Create the table */
354 h_table = params->ops->f_create(params->arg_create, p->socket_id,
356 if (h_table == NULL) {
357 rte_free(default_entry);
358 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
362 /* Commit current table to the pipeline */
366 /* Save input parameters */
367 memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
368 table->f_action_hit = params->f_action_hit;
369 table->f_action_miss = params->f_action_miss;
370 table->arg_ah = params->arg_ah;
371 table->entry_size = entry_size;
373 /* Clear the lookup miss actions (to be set later through API) */
374 table->default_entry = default_entry;
375 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
377 /* Initialize table internal data structure */
378 table->h_table = h_table;
379 table->table_next_id = 0;
380 table->table_next_id_valid = 0;
386 rte_pipeline_table_free(struct rte_table *table)
388 if (table->ops.f_free != NULL)
389 table->ops.f_free(table->h_table);
391 rte_free(table->default_entry);
395 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
397 struct rte_pipeline_table_entry *default_entry,
398 struct rte_pipeline_table_entry **default_entry_ptr)
400 struct rte_table *table;
402 /* Check input arguments */
404 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
409 if (default_entry == NULL) {
410 RTE_LOG(ERR, PIPELINE,
411 "%s: default_entry parameter is NULL\n", __func__);
415 if (table_id >= p->num_tables) {
416 RTE_LOG(ERR, PIPELINE,
417 "%s: table_id %d out of range\n", __func__, table_id);
421 table = &p->tables[table_id];
423 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
424 table->table_next_id_valid &&
425 (default_entry->table_id != table->table_next_id)) {
426 RTE_LOG(ERR, PIPELINE,
427 "%s: Tree-like topologies not allowed\n", __func__);
431 /* Set the lookup miss actions */
432 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
433 (table->table_next_id_valid == 0)) {
434 table->table_next_id = default_entry->table_id;
435 table->table_next_id_valid = 1;
438 memcpy(table->default_entry, default_entry, table->entry_size);
440 *default_entry_ptr = table->default_entry;
445 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
447 struct rte_pipeline_table_entry *entry)
449 struct rte_table *table;
451 /* Check input arguments */
453 RTE_LOG(ERR, PIPELINE,
454 "%s: pipeline parameter is NULL\n", __func__);
458 if (table_id >= p->num_tables) {
459 RTE_LOG(ERR, PIPELINE,
460 "%s: table_id %d out of range\n", __func__, table_id);
464 table = &p->tables[table_id];
466 /* Save the current contents of the default entry */
468 memcpy(entry, table->default_entry, table->entry_size);
470 /* Clear the lookup miss actions */
471 memset(table->default_entry, 0, table->entry_size);
472 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
478 rte_pipeline_table_entry_add(struct rte_pipeline *p,
481 struct rte_pipeline_table_entry *entry,
483 struct rte_pipeline_table_entry **entry_ptr)
485 struct rte_table *table;
487 /* Check input arguments */
489 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
495 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
500 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
505 if (table_id >= p->num_tables) {
506 RTE_LOG(ERR, PIPELINE,
507 "%s: table_id %d out of range\n", __func__, table_id);
511 table = &p->tables[table_id];
513 if (table->ops.f_add == NULL) {
514 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
519 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
520 table->table_next_id_valid &&
521 (entry->table_id != table->table_next_id)) {
522 RTE_LOG(ERR, PIPELINE,
523 "%s: Tree-like topologies not allowed\n", __func__);
528 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
529 (table->table_next_id_valid == 0)) {
530 table->table_next_id = entry->table_id;
531 table->table_next_id_valid = 1;
534 return (table->ops.f_add)(table->h_table, key, (void *) entry,
535 key_found, (void **) entry_ptr);
539 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
543 struct rte_pipeline_table_entry *entry)
545 struct rte_table *table;
547 /* Check input arguments */
549 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
555 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
560 if (table_id >= p->num_tables) {
561 RTE_LOG(ERR, PIPELINE,
562 "%s: table_id %d out of range\n", __func__, table_id);
566 table = &p->tables[table_id];
568 if (table->ops.f_delete == NULL) {
569 RTE_LOG(ERR, PIPELINE,
570 "%s: f_delete function pointer NULL\n", __func__);
574 return (table->ops.f_delete)(table->h_table, key, key_found, entry);
582 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
583 struct rte_pipeline_port_in_params *params,
587 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
591 if (params == NULL) {
592 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
595 if (port_id == NULL) {
596 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
602 if (params->ops == NULL) {
603 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
608 if (params->ops->f_create == NULL) {
609 RTE_LOG(ERR, PIPELINE,
610 "%s: f_create function pointer NULL\n", __func__);
614 if (params->ops->f_rx == NULL) {
615 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
621 if ((params->burst_size == 0) ||
622 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
623 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
628 /* Do we have room for one more port? */
629 if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
630 RTE_LOG(ERR, PIPELINE,
631 "%s: invalid value for num_ports_in\n", __func__);
639 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
640 struct rte_pipeline_port_out_params *params,
643 rte_pipeline_port_out_action_handler f_ah;
644 rte_pipeline_port_out_action_handler_bulk f_ah_bulk;
647 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
652 if (params == NULL) {
653 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
657 if (port_id == NULL) {
658 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
664 if (params->ops == NULL) {
665 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
670 if (params->ops->f_create == NULL) {
671 RTE_LOG(ERR, PIPELINE,
672 "%s: f_create function pointer NULL\n", __func__);
676 if (params->ops->f_tx == NULL) {
677 RTE_LOG(ERR, PIPELINE,
678 "%s: f_tx function pointer NULL\n", __func__);
682 if (params->ops->f_tx_bulk == NULL) {
683 RTE_LOG(ERR, PIPELINE,
684 "%s: f_tx_bulk function pointer NULL\n", __func__);
688 f_ah = params->f_action;
689 f_ah_bulk = params->f_action_bulk;
690 if (((f_ah != NULL) && (f_ah_bulk == NULL)) ||
691 ((f_ah == NULL) && (f_ah_bulk != NULL))) {
692 RTE_LOG(ERR, PIPELINE, "%s: Action handlers have to be either"
693 "both enabled or both disabled\n", __func__);
697 /* Do we have room for one more port? */
698 if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
699 RTE_LOG(ERR, PIPELINE,
700 "%s: invalid value for num_ports_out\n", __func__);
708 rte_pipeline_port_in_create(struct rte_pipeline *p,
709 struct rte_pipeline_port_in_params *params,
712 struct rte_port_in *port;
717 /* Check input arguments */
718 status = rte_pipeline_port_in_check_params(p, params, port_id);
722 id = p->num_ports_in;
723 port = &p->ports_in[id];
725 /* Create the port */
726 h_port = params->ops->f_create(params->arg_create, p->socket_id);
727 if (h_port == NULL) {
728 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
732 /* Commit current table to the pipeline */
736 /* Save input parameters */
737 memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
738 port->f_action = params->f_action;
739 port->arg_ah = params->arg_ah;
740 port->burst_size = params->burst_size;
742 /* Initialize port internal data structure */
743 port->table_id = RTE_TABLE_INVALID;
744 port->h_port = h_port;
751 rte_pipeline_port_in_free(struct rte_port_in *port)
753 if (port->ops.f_free != NULL)
754 port->ops.f_free(port->h_port);
758 rte_pipeline_port_out_create(struct rte_pipeline *p,
759 struct rte_pipeline_port_out_params *params,
762 struct rte_port_out *port;
767 /* Check input arguments */
768 status = rte_pipeline_port_out_check_params(p, params, port_id);
772 id = p->num_ports_out;
773 port = &p->ports_out[id];
775 /* Create the port */
776 h_port = params->ops->f_create(params->arg_create, p->socket_id);
777 if (h_port == NULL) {
778 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
782 /* Commit current table to the pipeline */
786 /* Save input parameters */
787 memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
788 port->f_action = params->f_action;
789 port->f_action_bulk = params->f_action_bulk;
790 port->arg_ah = params->arg_ah;
792 /* Initialize port internal data structure */
793 port->h_port = h_port;
799 rte_pipeline_port_out_free(struct rte_port_out *port)
801 if (port->ops.f_free != NULL)
802 port->ops.f_free(port->h_port);
806 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
810 struct rte_port_in *port;
812 /* Check input arguments */
814 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
819 if (port_id >= p->num_ports_in) {
820 RTE_LOG(ERR, PIPELINE,
821 "%s: port IN ID %u is out of range\n",
826 if (table_id >= p->num_tables) {
827 RTE_LOG(ERR, PIPELINE,
828 "%s: Table ID %u is out of range\n",
833 port = &p->ports_in[port_id];
834 port->table_id = table_id;
840 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
842 struct rte_port_in *port, *port_prev, *port_next;
843 struct rte_port_in *port_first, *port_last;
845 uint32_t port_prev_id, port_next_id, port_first_id, port_last_id;
847 /* Check input arguments */
849 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
854 if (port_id >= p->num_ports_in) {
855 RTE_LOG(ERR, PIPELINE,
856 "%s: port IN ID %u is out of range\n",
861 /* Return if current input port is already enabled */
862 port_mask = 1LLU << port_id;
863 if (p->enabled_port_in_mask & port_mask)
866 p->enabled_port_in_mask |= port_mask;
868 /* Add current input port to the pipeline chain of enabled ports */
869 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
870 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
872 port_prev = &p->ports_in[port_prev_id];
873 port_next = &p->ports_in[port_next_id];
874 port = &p->ports_in[port_id];
876 port_prev->next = port;
877 port->next = port_next;
879 /* Update the first and last input ports in the chain */
880 port_first_id = __builtin_ctzll(p->enabled_port_in_mask);
881 port_last_id = 63 - __builtin_clzll(p->enabled_port_in_mask);
883 port_first = &p->ports_in[port_first_id];
884 port_last = &p->ports_in[port_last_id];
886 p->port_in_first = port_first;
887 port_last->next = NULL;
893 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
895 struct rte_port_in *port_prev, *port_next, *port_first, *port_last;
897 uint32_t port_prev_id, port_next_id, port_first_id, port_last_id;
899 /* Check input arguments */
901 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
906 if (port_id >= p->num_ports_in) {
907 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
912 /* Return if current input port is already disabled */
913 port_mask = 1LLU << port_id;
914 if ((p->enabled_port_in_mask & port_mask) == 0)
917 /* Return if no other enabled ports */
918 if (__builtin_popcountll(p->enabled_port_in_mask) == 1) {
919 p->enabled_port_in_mask &= ~port_mask;
920 p->port_in_first = NULL;
925 /* Add current input port to the pipeline chain of enabled ports */
926 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
927 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
929 port_prev = &p->ports_in[port_prev_id];
930 port_next = &p->ports_in[port_next_id];
932 port_prev->next = port_next;
933 p->enabled_port_in_mask &= ~port_mask;
935 /* Update the first and last input ports in the chain */
936 port_first_id = __builtin_ctzll(p->enabled_port_in_mask);
937 port_last_id = 63 - __builtin_clzll(p->enabled_port_in_mask);
939 port_first = &p->ports_in[port_first_id];
940 port_last = &p->ports_in[port_last_id];
942 p->port_in_first = port_first;
943 port_last->next = NULL;
953 rte_pipeline_check(struct rte_pipeline *p)
957 /* Check input arguments */
959 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
964 /* Check that pipeline has at least one input port, one table and one
966 if (p->num_ports_in == 0) {
967 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
971 if (p->num_tables == 0) {
972 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
976 if (p->num_ports_out == 0) {
977 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
982 /* Check that all input ports are connected */
983 for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
984 struct rte_port_in *port_in = &p->ports_in[port_in_id];
986 if (port_in->table_id == RTE_TABLE_INVALID) {
987 RTE_LOG(ERR, PIPELINE,
988 "%s: Port IN ID %u is not connected\n",
989 __func__, port_in_id);
998 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
1000 p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1001 p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1002 p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1004 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1005 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1008 for (i = 0; i < n_pkts; i++) {
1009 uint64_t pkt_mask = 1LLU << i;
1010 uint32_t pos = p->entries[i]->action;
1012 p->action_mask1[pos] |= pkt_mask;
1017 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1018 uint64_t pkt_mask = 1LLU << i;
1021 if ((pkt_mask & pkts_mask) == 0)
1024 pos = p->entries[i]->action;
1025 p->action_mask1[pos] |= pkt_mask;
1031 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1032 uint64_t pkts_mask, uint32_t port_id)
1034 struct rte_port_out *port_out = &p->ports_out[port_id];
1036 /* Output port user actions */
1037 if (port_out->f_action_bulk != NULL) {
1038 uint64_t mask = pkts_mask;
1040 port_out->f_action_bulk(p->pkts, &pkts_mask, port_out->arg_ah);
1041 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask ^ mask;
1044 /* Output port TX */
1046 port_out->ops.f_tx_bulk(port_out->h_port, p->pkts, pkts_mask);
1050 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1052 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1053 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1056 for (i = 0; i < n_pkts; i++) {
1057 struct rte_mbuf *pkt = p->pkts[i];
1058 uint32_t port_out_id = p->entries[i]->port_id;
1059 struct rte_port_out *port_out =
1060 &p->ports_out[port_out_id];
1062 /* Output port user actions */
1063 if (port_out->f_action == NULL) /* Output port TX */
1064 port_out->ops.f_tx(port_out->h_port, pkt);
1066 uint64_t pkt_mask = 1LLU;
1068 port_out->f_action(pkt, &pkt_mask,
1070 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1071 (pkt_mask ^ 1LLU) << i;
1073 /* Output port TX */
1075 port_out->ops.f_tx(port_out->h_port,
1082 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1083 uint64_t pkt_mask = 1LLU << i;
1084 struct rte_mbuf *pkt;
1085 struct rte_port_out *port_out;
1086 uint32_t port_out_id;
1088 if ((pkt_mask & pkts_mask) == 0)
1092 port_out_id = p->entries[i]->port_id;
1093 port_out = &p->ports_out[port_out_id];
1095 /* Output port user actions */
1096 if (port_out->f_action == NULL) /* Output port TX */
1097 port_out->ops.f_tx(port_out->h_port, pkt);
1101 port_out->f_action(pkt, &pkt_mask,
1103 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1104 (pkt_mask ^ 1LLU) << i;
1106 /* Output port TX */
1108 port_out->ops.f_tx(port_out->h_port,
1116 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1119 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1120 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1123 for (i = 0; i < n_pkts; i++) {
1124 struct rte_mbuf *pkt = p->pkts[i];
1125 uint32_t port_out_id =
1126 RTE_MBUF_METADATA_UINT32(pkt,
1128 struct rte_port_out *port_out = &p->ports_out[
1131 /* Output port user actions */
1132 if (port_out->f_action == NULL) /* Output port TX */
1133 port_out->ops.f_tx(port_out->h_port, pkt);
1135 uint64_t pkt_mask = 1LLU;
1137 port_out->f_action(pkt, &pkt_mask,
1139 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1140 (pkt_mask ^ 1LLU) << i;
1142 /* Output port TX */
1144 port_out->ops.f_tx(port_out->h_port,
1151 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1152 uint64_t pkt_mask = 1LLU << i;
1153 struct rte_mbuf *pkt;
1154 struct rte_port_out *port_out;
1155 uint32_t port_out_id;
1157 if ((pkt_mask & pkts_mask) == 0)
1161 port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1163 port_out = &p->ports_out[port_out_id];
1165 /* Output port user actions */
1166 if (port_out->f_action == NULL) /* Output port TX */
1167 port_out->ops.f_tx(port_out->h_port, pkt);
1171 port_out->f_action(pkt, &pkt_mask,
1173 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1174 (pkt_mask ^ 1LLU) << i;
1176 /* Output port TX */
1178 port_out->ops.f_tx(port_out->h_port,
1186 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1188 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1189 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1192 for (i = 0; i < n_pkts; i++)
1193 rte_pktmbuf_free(p->pkts[i]);
1197 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1198 uint64_t pkt_mask = 1LLU << i;
1200 if ((pkt_mask & pkts_mask) == 0)
1203 rte_pktmbuf_free(p->pkts[i]);
1209 rte_pipeline_run(struct rte_pipeline *p)
1211 struct rte_port_in *port_in;
1213 for (port_in = p->port_in_first; port_in != NULL;
1214 port_in = port_in->next) {
1216 uint32_t n_pkts, table_id;
1219 n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1220 port_in->burst_size);
1224 pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1225 p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1226 p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1227 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1229 /* Input port user actions */
1230 if (port_in->f_action != NULL) {
1231 uint64_t mask = pkts_mask;
1233 port_in->f_action(p->pkts, n_pkts, &pkts_mask,
1235 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1240 for (table_id = port_in->table_id; pkts_mask != 0; ) {
1241 struct rte_table *table;
1242 uint64_t lookup_hit_mask, lookup_miss_mask;
1245 table = &p->tables[table_id];
1246 table->ops.f_lookup(table->h_table, p->pkts, pkts_mask,
1247 &lookup_hit_mask, (void **) p->entries);
1248 lookup_miss_mask = pkts_mask & (~lookup_hit_mask);
1251 if (lookup_miss_mask != 0) {
1252 struct rte_pipeline_table_entry *default_entry =
1253 table->default_entry;
1255 /* Table user actions */
1256 if (table->f_action_miss != NULL) {
1257 uint64_t mask = lookup_miss_mask;
1259 table->f_action_miss(p->pkts,
1261 default_entry, table->arg_ah);
1263 RTE_PIPELINE_ACTION_DROP] |=
1264 lookup_miss_mask ^ mask;
1267 /* Table reserved actions */
1268 if ((default_entry->action ==
1269 RTE_PIPELINE_ACTION_PORT) &&
1270 (lookup_miss_mask != 0))
1271 rte_pipeline_action_handler_port_bulk(p,
1273 default_entry->port_id);
1275 uint32_t pos = default_entry->action;
1277 p->action_mask0[pos] = lookup_miss_mask;
1282 if (lookup_hit_mask != 0) {
1283 /* Table user actions */
1284 if (table->f_action_hit != NULL) {
1285 uint64_t mask = lookup_hit_mask;
1287 table->f_action_hit(p->pkts,
1289 p->entries, table->arg_ah);
1291 RTE_PIPELINE_ACTION_DROP] |=
1292 lookup_hit_mask ^ mask;
1295 /* Table reserved actions */
1296 rte_pipeline_compute_masks(p, lookup_hit_mask);
1297 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1299 RTE_PIPELINE_ACTION_DROP];
1300 p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1302 RTE_PIPELINE_ACTION_PORT];
1303 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1305 RTE_PIPELINE_ACTION_TABLE];
1308 /* Prepare for next iteration */
1309 pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1310 table_id = table->table_next_id;
1311 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1314 /* Table reserved action PORT */
1315 rte_pipeline_action_handler_port(p,
1316 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1318 /* Table reserved action PORT META */
1319 rte_pipeline_action_handler_port_meta(p,
1320 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1322 /* Table reserved action DROP */
1323 rte_pipeline_action_handler_drop(p,
1324 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1331 rte_pipeline_flush(struct rte_pipeline *p)
1335 /* Check input arguments */
1337 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1342 for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1343 struct rte_port_out *port = &p->ports_out[port_id];
1345 if (port->ops.f_flush != NULL)
1346 port->ops.f_flush(port->h_port);
1353 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1354 uint32_t port_id, struct rte_mbuf *pkt)
1356 struct rte_port_out *port_out = &p->ports_out[port_id];
1358 /* Output port user actions */
1359 if (port_out->f_action == NULL)
1360 port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1362 uint64_t pkt_mask = 1LLU;
1364 port_out->f_action(pkt, &pkt_mask, port_out->arg_ah);
1366 if (pkt_mask != 0) /* Output port TX */
1367 port_out->ops.f_tx(port_out->h_port, pkt);
1369 rte_pktmbuf_free(pkt);