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_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
51 #ifdef RTE_PIPELINE_STATS_COLLECT
53 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask) \
54 ({ (p)->n_pkts_ah_drop = __builtin_popcountll(mask); })
56 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter) \
57 ({ (counter) += (p)->n_pkts_ah_drop; (p)->n_pkts_ah_drop = 0; })
59 #define RTE_PIPELINE_STATS_TABLE_DROP0(p) \
60 ({ (p)->pkts_drop_mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; })
62 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter) \
64 uint64_t mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; \
65 mask ^= (p)->pkts_drop_mask; \
66 (counter) += __builtin_popcountll(mask); \
71 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask)
72 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter)
73 #define RTE_PIPELINE_STATS_TABLE_DROP0(p)
74 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter)
79 /* Input parameters */
80 struct rte_port_in_ops ops;
81 rte_pipeline_port_in_action_handler f_action;
85 /* The table to which this port is connected */
88 /* Handle to low-level port */
91 /* List of enabled ports */
92 struct rte_port_in *next;
95 uint64_t n_pkts_dropped_by_ah;
99 /* Input parameters */
100 struct rte_port_out_ops ops;
101 rte_pipeline_port_out_action_handler f_action;
104 /* Handle to low-level port */
108 uint64_t n_pkts_dropped_by_ah;
112 /* Input parameters */
113 struct rte_table_ops ops;
114 rte_pipeline_table_action_handler_hit f_action_hit;
115 rte_pipeline_table_action_handler_miss f_action_miss;
117 struct rte_pipeline_table_entry *default_entry;
120 uint32_t table_next_id;
121 uint32_t table_next_id_valid;
123 /* Handle to the low-level table object */
127 uint64_t n_pkts_dropped_by_lkp_hit_ah;
128 uint64_t n_pkts_dropped_by_lkp_miss_ah;
129 uint64_t n_pkts_dropped_lkp_hit;
130 uint64_t n_pkts_dropped_lkp_miss;
133 #define RTE_PIPELINE_MAX_NAME_SZ 124
135 struct rte_pipeline {
136 /* Input parameters */
137 char name[RTE_PIPELINE_MAX_NAME_SZ];
139 uint32_t offset_port_id;
141 /* Internal tables */
142 struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
143 struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
144 struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
146 /* Occupancy of internal tables */
147 uint32_t num_ports_in;
148 uint32_t num_ports_out;
151 /* List of enabled ports */
152 uint64_t enabled_port_in_mask;
153 struct rte_port_in *port_in_next;
155 /* Pipeline run structures */
156 struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
157 struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
158 uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
159 uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
161 uint64_t n_pkts_ah_drop;
162 uint64_t pkts_drop_mask;
163 } __rte_cache_aligned;
165 static inline uint32_t
166 rte_mask_get_next(uint64_t mask, uint32_t pos)
168 uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
169 (mask >> ((pos + 1) & 0x3F));
170 return (__builtin_ctzll(mask_rot) - (63 - pos)) & 0x3F;
173 static inline uint32_t
174 rte_mask_get_prev(uint64_t mask, uint32_t pos)
176 uint64_t mask_rot = (mask >> (pos & 0x3F)) |
177 (mask << ((64 - pos) & 0x3F));
178 return ((63 - __builtin_clzll(mask_rot)) + pos) & 0x3F;
182 rte_pipeline_table_free(struct rte_table *table);
185 rte_pipeline_port_in_free(struct rte_port_in *port);
188 rte_pipeline_port_out_free(struct rte_port_out *port);
195 rte_pipeline_check_params(struct rte_pipeline_params *params)
197 if (params == NULL) {
198 RTE_LOG(ERR, PIPELINE,
199 "%s: Incorrect value for parameter params\n", __func__);
204 if (params->name == NULL) {
205 RTE_LOG(ERR, PIPELINE,
206 "%s: Incorrect value for parameter name\n", __func__);
211 if ((params->socket_id < 0) ||
212 (params->socket_id >= RTE_MAX_NUMA_NODES)) {
213 RTE_LOG(ERR, PIPELINE,
214 "%s: Incorrect value for parameter socket_id\n",
222 struct rte_pipeline *
223 rte_pipeline_create(struct rte_pipeline_params *params)
225 struct rte_pipeline *p;
228 /* Check input parameters */
229 status = rte_pipeline_check_params(params);
231 RTE_LOG(ERR, PIPELINE,
232 "%s: Pipeline params check failed (%d)\n",
237 /* Allocate memory for the pipeline on requested socket */
238 p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
239 RTE_CACHE_LINE_SIZE, params->socket_id);
242 RTE_LOG(ERR, PIPELINE,
243 "%s: Pipeline memory allocation failed\n", __func__);
247 /* Save input parameters */
248 snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
249 p->socket_id = params->socket_id;
250 p->offset_port_id = params->offset_port_id;
252 /* Initialize pipeline internal data structure */
254 p->num_ports_out = 0;
256 p->enabled_port_in_mask = 0;
257 p->port_in_next = NULL;
259 p->n_pkts_ah_drop = 0;
265 rte_pipeline_free(struct rte_pipeline *p)
269 /* Check input parameters */
271 RTE_LOG(ERR, PIPELINE,
272 "%s: rte_pipeline parameter is NULL\n", __func__);
276 /* Free input ports */
277 for (i = 0; i < p->num_ports_in; i++) {
278 struct rte_port_in *port = &p->ports_in[i];
280 rte_pipeline_port_in_free(port);
284 for (i = 0; i < p->num_tables; i++) {
285 struct rte_table *table = &p->tables[i];
287 rte_pipeline_table_free(table);
290 /* Free output ports */
291 for (i = 0; i < p->num_ports_out; i++) {
292 struct rte_port_out *port = &p->ports_out[i];
294 rte_pipeline_port_out_free(port);
297 /* Free pipeline memory */
308 rte_table_check_params(struct rte_pipeline *p,
309 struct rte_pipeline_table_params *params,
313 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
317 if (params == NULL) {
318 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
322 if (table_id == NULL) {
323 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
329 if (params->ops == NULL) {
330 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
335 if (params->ops->f_create == NULL) {
336 RTE_LOG(ERR, PIPELINE,
337 "%s: f_create function pointer is NULL\n", __func__);
341 if (params->ops->f_lookup == NULL) {
342 RTE_LOG(ERR, PIPELINE,
343 "%s: f_lookup function pointer is NULL\n", __func__);
347 /* De we have room for one more table? */
348 if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
349 RTE_LOG(ERR, PIPELINE,
350 "%s: Incorrect value for num_tables parameter\n",
359 rte_pipeline_table_create(struct rte_pipeline *p,
360 struct rte_pipeline_table_params *params,
363 struct rte_table *table;
364 struct rte_pipeline_table_entry *default_entry;
366 uint32_t entry_size, id;
369 /* Check input arguments */
370 status = rte_table_check_params(p, params, table_id);
375 table = &p->tables[id];
377 /* Allocate space for the default table entry */
378 entry_size = sizeof(struct rte_pipeline_table_entry) +
379 params->action_data_size;
380 default_entry = (struct rte_pipeline_table_entry *) rte_zmalloc_socket(
381 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
382 if (default_entry == NULL) {
383 RTE_LOG(ERR, PIPELINE,
384 "%s: Failed to allocate default entry\n", __func__);
388 /* Create the table */
389 h_table = params->ops->f_create(params->arg_create, p->socket_id,
391 if (h_table == NULL) {
392 rte_free(default_entry);
393 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
397 /* Commit current table to the pipeline */
401 /* Save input parameters */
402 memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
403 table->f_action_hit = params->f_action_hit;
404 table->f_action_miss = params->f_action_miss;
405 table->arg_ah = params->arg_ah;
406 table->entry_size = entry_size;
408 /* Clear the lookup miss actions (to be set later through API) */
409 table->default_entry = default_entry;
410 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
412 /* Initialize table internal data structure */
413 table->h_table = h_table;
414 table->table_next_id = 0;
415 table->table_next_id_valid = 0;
421 rte_pipeline_table_free(struct rte_table *table)
423 if (table->ops.f_free != NULL)
424 table->ops.f_free(table->h_table);
426 rte_free(table->default_entry);
430 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
432 struct rte_pipeline_table_entry *default_entry,
433 struct rte_pipeline_table_entry **default_entry_ptr)
435 struct rte_table *table;
437 /* Check input arguments */
439 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
444 if (default_entry == NULL) {
445 RTE_LOG(ERR, PIPELINE,
446 "%s: default_entry 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 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
459 table->table_next_id_valid &&
460 (default_entry->table_id != table->table_next_id)) {
461 RTE_LOG(ERR, PIPELINE,
462 "%s: Tree-like topologies not allowed\n", __func__);
466 /* Set the lookup miss actions */
467 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
468 (table->table_next_id_valid == 0)) {
469 table->table_next_id = default_entry->table_id;
470 table->table_next_id_valid = 1;
473 memcpy(table->default_entry, default_entry, table->entry_size);
475 *default_entry_ptr = table->default_entry;
480 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
482 struct rte_pipeline_table_entry *entry)
484 struct rte_table *table;
486 /* Check input arguments */
488 RTE_LOG(ERR, PIPELINE,
489 "%s: pipeline parameter is NULL\n", __func__);
493 if (table_id >= p->num_tables) {
494 RTE_LOG(ERR, PIPELINE,
495 "%s: table_id %d out of range\n", __func__, table_id);
499 table = &p->tables[table_id];
501 /* Save the current contents of the default entry */
503 memcpy(entry, table->default_entry, table->entry_size);
505 /* Clear the lookup miss actions */
506 memset(table->default_entry, 0, table->entry_size);
507 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
513 rte_pipeline_table_entry_add(struct rte_pipeline *p,
516 struct rte_pipeline_table_entry *entry,
518 struct rte_pipeline_table_entry **entry_ptr)
520 struct rte_table *table;
522 /* Check input arguments */
524 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
530 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
535 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
540 if (table_id >= p->num_tables) {
541 RTE_LOG(ERR, PIPELINE,
542 "%s: table_id %d out of range\n", __func__, table_id);
546 table = &p->tables[table_id];
548 if (table->ops.f_add == NULL) {
549 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
554 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
555 table->table_next_id_valid &&
556 (entry->table_id != table->table_next_id)) {
557 RTE_LOG(ERR, PIPELINE,
558 "%s: Tree-like topologies not allowed\n", __func__);
563 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
564 (table->table_next_id_valid == 0)) {
565 table->table_next_id = entry->table_id;
566 table->table_next_id_valid = 1;
569 return (table->ops.f_add)(table->h_table, key, (void *) entry,
570 key_found, (void **) entry_ptr);
574 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
578 struct rte_pipeline_table_entry *entry)
580 struct rte_table *table;
582 /* Check input arguments */
584 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
590 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
595 if (table_id >= p->num_tables) {
596 RTE_LOG(ERR, PIPELINE,
597 "%s: table_id %d out of range\n", __func__, table_id);
601 table = &p->tables[table_id];
603 if (table->ops.f_delete == NULL) {
604 RTE_LOG(ERR, PIPELINE,
605 "%s: f_delete function pointer NULL\n", __func__);
609 return (table->ops.f_delete)(table->h_table, key, key_found, entry);
612 int rte_pipeline_table_entry_add_bulk(struct rte_pipeline *p,
615 struct rte_pipeline_table_entry **entries,
618 struct rte_pipeline_table_entry **entries_ptr)
620 struct rte_table *table;
623 /* Check input arguments */
625 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
631 RTE_LOG(ERR, PIPELINE, "%s: keys parameter is NULL\n", __func__);
635 if (entries == NULL) {
636 RTE_LOG(ERR, PIPELINE, "%s: entries parameter is NULL\n",
641 if (table_id >= p->num_tables) {
642 RTE_LOG(ERR, PIPELINE,
643 "%s: table_id %d out of range\n", __func__, table_id);
647 table = &p->tables[table_id];
649 if (table->ops.f_add_bulk == NULL) {
650 RTE_LOG(ERR, PIPELINE, "%s: f_add_bulk function pointer NULL\n",
655 for (i = 0; i < n_keys; i++) {
656 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
657 table->table_next_id_valid &&
658 (entries[i]->table_id != table->table_next_id)) {
659 RTE_LOG(ERR, PIPELINE,
660 "%s: Tree-like topologies not allowed\n", __func__);
666 for (i = 0; i < n_keys; i++) {
667 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
668 (table->table_next_id_valid == 0)) {
669 table->table_next_id = entries[i]->table_id;
670 table->table_next_id_valid = 1;
674 return (table->ops.f_add_bulk)(table->h_table, keys, (void **) entries,
675 n_keys, key_found, (void **) entries_ptr);
678 int rte_pipeline_table_entry_delete_bulk(struct rte_pipeline *p,
683 struct rte_pipeline_table_entry **entries)
685 struct rte_table *table;
687 /* Check input arguments */
689 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
695 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
700 if (table_id >= p->num_tables) {
701 RTE_LOG(ERR, PIPELINE,
702 "%s: table_id %d out of range\n", __func__, table_id);
706 table = &p->tables[table_id];
708 if (table->ops.f_delete_bulk == NULL) {
709 RTE_LOG(ERR, PIPELINE,
710 "%s: f_delete function pointer NULL\n", __func__);
714 return (table->ops.f_delete_bulk)(table->h_table, keys, n_keys, key_found,
723 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
724 struct rte_pipeline_port_in_params *params,
728 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
732 if (params == NULL) {
733 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
736 if (port_id == NULL) {
737 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
743 if (params->ops == NULL) {
744 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
749 if (params->ops->f_create == NULL) {
750 RTE_LOG(ERR, PIPELINE,
751 "%s: f_create function pointer NULL\n", __func__);
755 if (params->ops->f_rx == NULL) {
756 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
762 if ((params->burst_size == 0) ||
763 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
764 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
769 /* Do we have room for one more port? */
770 if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
771 RTE_LOG(ERR, PIPELINE,
772 "%s: invalid value for num_ports_in\n", __func__);
780 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
781 struct rte_pipeline_port_out_params *params,
785 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
790 if (params == NULL) {
791 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
795 if (port_id == NULL) {
796 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
802 if (params->ops == NULL) {
803 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
808 if (params->ops->f_create == NULL) {
809 RTE_LOG(ERR, PIPELINE,
810 "%s: f_create function pointer NULL\n", __func__);
814 if (params->ops->f_tx == NULL) {
815 RTE_LOG(ERR, PIPELINE,
816 "%s: f_tx function pointer NULL\n", __func__);
820 if (params->ops->f_tx_bulk == NULL) {
821 RTE_LOG(ERR, PIPELINE,
822 "%s: f_tx_bulk function pointer NULL\n", __func__);
826 /* Do we have room for one more port? */
827 if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
828 RTE_LOG(ERR, PIPELINE,
829 "%s: invalid value for num_ports_out\n", __func__);
837 rte_pipeline_port_in_create(struct rte_pipeline *p,
838 struct rte_pipeline_port_in_params *params,
841 struct rte_port_in *port;
846 /* Check input arguments */
847 status = rte_pipeline_port_in_check_params(p, params, port_id);
851 id = p->num_ports_in;
852 port = &p->ports_in[id];
854 /* Create the port */
855 h_port = params->ops->f_create(params->arg_create, p->socket_id);
856 if (h_port == NULL) {
857 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
861 /* Commit current table to the pipeline */
865 /* Save input parameters */
866 memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
867 port->f_action = params->f_action;
868 port->arg_ah = params->arg_ah;
869 port->burst_size = params->burst_size;
871 /* Initialize port internal data structure */
872 port->table_id = RTE_TABLE_INVALID;
873 port->h_port = h_port;
880 rte_pipeline_port_in_free(struct rte_port_in *port)
882 if (port->ops.f_free != NULL)
883 port->ops.f_free(port->h_port);
887 rte_pipeline_port_out_create(struct rte_pipeline *p,
888 struct rte_pipeline_port_out_params *params,
891 struct rte_port_out *port;
896 /* Check input arguments */
897 status = rte_pipeline_port_out_check_params(p, params, port_id);
901 id = p->num_ports_out;
902 port = &p->ports_out[id];
904 /* Create the port */
905 h_port = params->ops->f_create(params->arg_create, p->socket_id);
906 if (h_port == NULL) {
907 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
911 /* Commit current table to the pipeline */
915 /* Save input parameters */
916 memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
917 port->f_action = params->f_action;
918 port->arg_ah = params->arg_ah;
920 /* Initialize port internal data structure */
921 port->h_port = h_port;
927 rte_pipeline_port_out_free(struct rte_port_out *port)
929 if (port->ops.f_free != NULL)
930 port->ops.f_free(port->h_port);
934 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
938 struct rte_port_in *port;
940 /* Check input arguments */
942 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
947 if (port_id >= p->num_ports_in) {
948 RTE_LOG(ERR, PIPELINE,
949 "%s: port IN ID %u is out of range\n",
954 if (table_id >= p->num_tables) {
955 RTE_LOG(ERR, PIPELINE,
956 "%s: Table ID %u is out of range\n",
961 port = &p->ports_in[port_id];
962 port->table_id = table_id;
968 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
970 struct rte_port_in *port, *port_prev, *port_next;
972 uint32_t port_prev_id, port_next_id;
974 /* Check input arguments */
976 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
981 if (port_id >= p->num_ports_in) {
982 RTE_LOG(ERR, PIPELINE,
983 "%s: port IN ID %u is out of range\n",
988 port = &p->ports_in[port_id];
990 /* Return if current input port is already enabled */
991 port_mask = 1LLU << port_id;
992 if (p->enabled_port_in_mask & port_mask)
995 p->enabled_port_in_mask |= port_mask;
997 /* Add current input port to the pipeline chain of enabled ports */
998 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
999 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1001 port_prev = &p->ports_in[port_prev_id];
1002 port_next = &p->ports_in[port_next_id];
1004 port_prev->next = port;
1005 port->next = port_next;
1007 /* Check if list of enabled ports was previously empty */
1008 if (p->enabled_port_in_mask == port_mask)
1009 p->port_in_next = port;
1015 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
1017 struct rte_port_in *port, *port_prev, *port_next;
1019 uint32_t port_prev_id, port_next_id;
1021 /* Check input arguments */
1023 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1028 if (port_id >= p->num_ports_in) {
1029 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
1034 port = &p->ports_in[port_id];
1036 /* Return if current input port is already disabled */
1037 port_mask = 1LLU << port_id;
1038 if ((p->enabled_port_in_mask & port_mask) == 0)
1041 p->enabled_port_in_mask &= ~port_mask;
1043 /* Return if no other enabled ports */
1044 if (p->enabled_port_in_mask == 0) {
1045 p->port_in_next = NULL;
1050 /* Add current input port to the pipeline chain of enabled ports */
1051 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
1052 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1054 port_prev = &p->ports_in[port_prev_id];
1055 port_next = &p->ports_in[port_next_id];
1057 port_prev->next = port_next;
1059 /* Check if the port which has just been disabled is next to serve */
1060 if (port == p->port_in_next)
1061 p->port_in_next = port_next;
1071 rte_pipeline_check(struct rte_pipeline *p)
1073 uint32_t port_in_id;
1075 /* Check input arguments */
1077 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1082 /* Check that pipeline has at least one input port, one table and one
1084 if (p->num_ports_in == 0) {
1085 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
1089 if (p->num_tables == 0) {
1090 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
1094 if (p->num_ports_out == 0) {
1095 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
1100 /* Check that all input ports are connected */
1101 for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
1102 struct rte_port_in *port_in = &p->ports_in[port_in_id];
1104 if (port_in->table_id == RTE_TABLE_INVALID) {
1105 RTE_LOG(ERR, PIPELINE,
1106 "%s: Port IN ID %u is not connected\n",
1107 __func__, port_in_id);
1116 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
1118 p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1119 p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1120 p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
1121 p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1123 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1124 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1127 for (i = 0; i < n_pkts; i++) {
1128 uint64_t pkt_mask = 1LLU << i;
1129 uint32_t pos = p->entries[i]->action;
1131 p->action_mask1[pos] |= pkt_mask;
1136 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1137 uint64_t pkt_mask = 1LLU << i;
1140 if ((pkt_mask & pkts_mask) == 0)
1143 pos = p->entries[i]->action;
1144 p->action_mask1[pos] |= pkt_mask;
1150 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1151 uint64_t pkts_mask, uint32_t port_id)
1153 struct rte_port_out *port_out = &p->ports_out[port_id];
1155 p->pkts_mask = pkts_mask;
1157 /* Output port user actions */
1158 if (port_out->f_action != NULL) {
1159 port_out->f_action(p, p->pkts, pkts_mask, port_out->arg_ah);
1161 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1162 port_out->n_pkts_dropped_by_ah);
1165 /* Output port TX */
1166 if (p->pkts_mask != 0)
1167 port_out->ops.f_tx_bulk(port_out->h_port,
1173 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1175 p->pkts_mask = pkts_mask;
1177 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1178 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1181 for (i = 0; i < n_pkts; i++) {
1182 struct rte_mbuf *pkt = p->pkts[i];
1183 uint32_t port_out_id = p->entries[i]->port_id;
1184 struct rte_port_out *port_out =
1185 &p->ports_out[port_out_id];
1187 /* Output port user actions */
1188 if (port_out->f_action == NULL) /* Output port TX */
1189 port_out->ops.f_tx(port_out->h_port, pkt);
1191 uint64_t pkt_mask = 1LLU << i;
1193 port_out->f_action(p,
1198 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1199 port_out->n_pkts_dropped_by_ah);
1201 /* Output port TX */
1202 if (pkt_mask & p->pkts_mask)
1203 port_out->ops.f_tx(port_out->h_port,
1210 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1211 uint64_t pkt_mask = 1LLU << i;
1212 struct rte_mbuf *pkt;
1213 struct rte_port_out *port_out;
1214 uint32_t port_out_id;
1216 if ((pkt_mask & pkts_mask) == 0)
1220 port_out_id = p->entries[i]->port_id;
1221 port_out = &p->ports_out[port_out_id];
1223 /* Output port user actions */
1224 if (port_out->f_action == NULL) /* Output port TX */
1225 port_out->ops.f_tx(port_out->h_port, pkt);
1227 port_out->f_action(p,
1232 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1233 port_out->n_pkts_dropped_by_ah);
1235 /* Output port TX */
1236 if (pkt_mask & p->pkts_mask)
1237 port_out->ops.f_tx(port_out->h_port,
1245 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1248 p->pkts_mask = pkts_mask;
1250 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1251 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1254 for (i = 0; i < n_pkts; i++) {
1255 struct rte_mbuf *pkt = p->pkts[i];
1256 uint32_t port_out_id =
1257 RTE_MBUF_METADATA_UINT32(pkt,
1259 struct rte_port_out *port_out = &p->ports_out[
1262 /* Output port user actions */
1263 if (port_out->f_action == NULL) /* Output port TX */
1264 port_out->ops.f_tx(port_out->h_port, pkt);
1266 uint64_t pkt_mask = 1LLU << i;
1268 port_out->f_action(p,
1273 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1274 port_out->n_pkts_dropped_by_ah);
1276 /* Output port TX */
1277 if (pkt_mask & p->pkts_mask)
1278 port_out->ops.f_tx(port_out->h_port,
1285 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1286 uint64_t pkt_mask = 1LLU << i;
1287 struct rte_mbuf *pkt;
1288 struct rte_port_out *port_out;
1289 uint32_t port_out_id;
1291 if ((pkt_mask & pkts_mask) == 0)
1295 port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1297 port_out = &p->ports_out[port_out_id];
1299 /* Output port user actions */
1300 if (port_out->f_action == NULL) /* Output port TX */
1301 port_out->ops.f_tx(port_out->h_port, pkt);
1303 port_out->f_action(p,
1308 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1309 port_out->n_pkts_dropped_by_ah);
1311 /* Output port TX */
1312 if (pkt_mask & p->pkts_mask)
1313 port_out->ops.f_tx(port_out->h_port,
1321 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1323 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1324 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1327 for (i = 0; i < n_pkts; i++)
1328 rte_pktmbuf_free(p->pkts[i]);
1332 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1333 uint64_t pkt_mask = 1LLU << i;
1335 if ((pkt_mask & pkts_mask) == 0)
1338 rte_pktmbuf_free(p->pkts[i]);
1344 rte_pipeline_run(struct rte_pipeline *p)
1346 struct rte_port_in *port_in = p->port_in_next;
1347 uint32_t n_pkts, table_id;
1349 if (port_in == NULL)
1353 n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1354 port_in->burst_size);
1356 p->port_in_next = port_in->next;
1360 p->pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1361 p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1362 p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1363 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1364 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1366 /* Input port user actions */
1367 if (port_in->f_action != NULL) {
1368 port_in->f_action(p, p->pkts, n_pkts, port_in->arg_ah);
1370 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1371 port_in->n_pkts_dropped_by_ah);
1375 for (table_id = port_in->table_id; p->pkts_mask != 0; ) {
1376 struct rte_table *table;
1377 uint64_t lookup_hit_mask, lookup_miss_mask;
1380 table = &p->tables[table_id];
1381 table->ops.f_lookup(table->h_table, p->pkts, p->pkts_mask,
1382 &lookup_hit_mask, (void **) p->entries);
1383 lookup_miss_mask = p->pkts_mask & (~lookup_hit_mask);
1386 if (lookup_miss_mask != 0) {
1387 struct rte_pipeline_table_entry *default_entry =
1388 table->default_entry;
1390 p->pkts_mask = lookup_miss_mask;
1392 /* Table user actions */
1393 if (table->f_action_miss != NULL) {
1394 table->f_action_miss(p,
1400 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1401 table->n_pkts_dropped_by_lkp_miss_ah);
1404 /* Table reserved actions */
1405 if ((default_entry->action == RTE_PIPELINE_ACTION_PORT) &&
1406 (p->pkts_mask != 0))
1407 rte_pipeline_action_handler_port_bulk(p,
1409 default_entry->port_id);
1411 uint32_t pos = default_entry->action;
1413 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1415 p->action_mask0[pos] |= p->pkts_mask;
1417 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1418 table->n_pkts_dropped_lkp_miss);
1423 if (lookup_hit_mask != 0) {
1424 p->pkts_mask = lookup_hit_mask;
1426 /* Table user actions */
1427 if (table->f_action_hit != NULL) {
1428 table->f_action_hit(p,
1434 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1435 table->n_pkts_dropped_by_lkp_hit_ah);
1438 /* Table reserved actions */
1439 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1440 rte_pipeline_compute_masks(p, p->pkts_mask);
1441 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1443 RTE_PIPELINE_ACTION_DROP];
1444 p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1446 RTE_PIPELINE_ACTION_PORT];
1447 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1449 RTE_PIPELINE_ACTION_PORT_META];
1450 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1452 RTE_PIPELINE_ACTION_TABLE];
1454 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1455 table->n_pkts_dropped_lkp_hit);
1458 /* Prepare for next iteration */
1459 p->pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1460 table_id = table->table_next_id;
1461 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1464 /* Table reserved action PORT */
1465 rte_pipeline_action_handler_port(p,
1466 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1468 /* Table reserved action PORT META */
1469 rte_pipeline_action_handler_port_meta(p,
1470 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1472 /* Table reserved action DROP */
1473 rte_pipeline_action_handler_drop(p,
1474 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1476 /* Pick candidate for next port IN to serve */
1477 p->port_in_next = port_in->next;
1479 return (int) n_pkts;
1483 rte_pipeline_flush(struct rte_pipeline *p)
1487 /* Check input arguments */
1489 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1494 for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1495 struct rte_port_out *port = &p->ports_out[port_id];
1497 if (port->ops.f_flush != NULL)
1498 port->ops.f_flush(port->h_port);
1505 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1506 uint32_t port_id, struct rte_mbuf *pkt)
1508 struct rte_port_out *port_out = &p->ports_out[port_id];
1510 port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1515 int rte_pipeline_ah_packet_hijack(struct rte_pipeline *p,
1518 pkts_mask &= p->pkts_mask;
1519 p->pkts_mask &= ~pkts_mask;
1524 int rte_pipeline_ah_packet_drop(struct rte_pipeline *p,
1527 pkts_mask &= p->pkts_mask;
1528 p->pkts_mask &= ~pkts_mask;
1529 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask;
1531 RTE_PIPELINE_STATS_AH_DROP_WRITE(p, pkts_mask);
1535 int rte_pipeline_port_in_stats_read(struct rte_pipeline *p, uint32_t port_id,
1536 struct rte_pipeline_port_in_stats *stats, int clear)
1538 struct rte_port_in *port;
1542 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1547 if (port_id >= p->num_ports_in) {
1548 RTE_LOG(ERR, PIPELINE,
1549 "%s: port IN ID %u is out of range\n",
1554 port = &p->ports_in[port_id];
1556 if (port->ops.f_stats != NULL) {
1557 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1560 } else if (stats != NULL)
1561 memset(&stats->stats, 0, sizeof(stats->stats));
1564 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1567 port->n_pkts_dropped_by_ah = 0;
1572 int rte_pipeline_port_out_stats_read(struct rte_pipeline *p, uint32_t port_id,
1573 struct rte_pipeline_port_out_stats *stats, int clear)
1575 struct rte_port_out *port;
1579 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n", __func__);
1583 if (port_id >= p->num_ports_out) {
1584 RTE_LOG(ERR, PIPELINE,
1585 "%s: port OUT ID %u is out of range\n", __func__, port_id);
1589 port = &p->ports_out[port_id];
1590 if (port->ops.f_stats != NULL) {
1591 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1594 } else if (stats != NULL)
1595 memset(&stats->stats, 0, sizeof(stats->stats));
1598 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1601 port->n_pkts_dropped_by_ah = 0;
1606 int rte_pipeline_table_stats_read(struct rte_pipeline *p, uint32_t table_id,
1607 struct rte_pipeline_table_stats *stats, int clear)
1609 struct rte_table *table;
1613 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1618 if (table_id >= p->num_tables) {
1619 RTE_LOG(ERR, PIPELINE,
1620 "%s: table %u is out of range\n", __func__, table_id);
1624 table = &p->tables[table_id];
1625 if (table->ops.f_stats != NULL) {
1626 retval = table->ops.f_stats(table->h_table, &stats->stats, clear);
1629 } else if (stats != NULL)
1630 memset(&stats->stats, 0, sizeof(stats->stats));
1632 if (stats != NULL) {
1633 stats->n_pkts_dropped_by_lkp_hit_ah =
1634 table->n_pkts_dropped_by_lkp_hit_ah;
1635 stats->n_pkts_dropped_by_lkp_miss_ah =
1636 table->n_pkts_dropped_by_lkp_miss_ah;
1637 stats->n_pkts_dropped_lkp_hit = table->n_pkts_dropped_lkp_hit;
1638 stats->n_pkts_dropped_lkp_miss = table->n_pkts_dropped_lkp_miss;
1642 table->n_pkts_dropped_by_lkp_hit_ah = 0;
1643 table->n_pkts_dropped_by_lkp_miss_ah = 0;
1644 table->n_pkts_dropped_lkp_hit = 0;
1645 table->n_pkts_dropped_lkp_miss = 0;