1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2016 Intel Corporation
8 #include <rte_common.h>
9 #include <rte_memory.h>
10 #include <rte_cycles.h>
11 #include <rte_prefetch.h>
12 #include <rte_branch_prediction.h>
14 #include <rte_malloc.h>
15 #include <rte_string_fns.h>
17 #include "rte_pipeline.h"
19 #define RTE_TABLE_INVALID UINT32_MAX
21 #ifdef RTE_PIPELINE_STATS_COLLECT
23 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask) \
24 ({ (p)->n_pkts_ah_drop = __builtin_popcountll(mask); })
26 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter) \
27 ({ (counter) += (p)->n_pkts_ah_drop; (p)->n_pkts_ah_drop = 0; })
29 #define RTE_PIPELINE_STATS_TABLE_DROP0(p) \
30 ({ (p)->pkts_drop_mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; })
32 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter) \
34 uint64_t mask = (p)->action_mask0[RTE_PIPELINE_ACTION_DROP]; \
35 mask ^= (p)->pkts_drop_mask; \
36 (counter) += __builtin_popcountll(mask); \
41 #define RTE_PIPELINE_STATS_AH_DROP_WRITE(p, mask)
42 #define RTE_PIPELINE_STATS_AH_DROP_READ(p, counter)
43 #define RTE_PIPELINE_STATS_TABLE_DROP0(p)
44 #define RTE_PIPELINE_STATS_TABLE_DROP1(p, counter)
49 /* Input parameters */
50 struct rte_port_in_ops ops;
51 rte_pipeline_port_in_action_handler f_action;
55 /* The table to which this port is connected */
58 /* Handle to low-level port */
61 /* List of enabled ports */
62 struct rte_port_in *next;
65 uint64_t n_pkts_dropped_by_ah;
69 /* Input parameters */
70 struct rte_port_out_ops ops;
71 rte_pipeline_port_out_action_handler f_action;
74 /* Handle to low-level port */
78 uint64_t n_pkts_dropped_by_ah;
82 /* Input parameters */
83 struct rte_table_ops ops;
84 rte_pipeline_table_action_handler_hit f_action_hit;
85 rte_pipeline_table_action_handler_miss f_action_miss;
87 struct rte_pipeline_table_entry *default_entry;
90 uint32_t table_next_id;
91 uint32_t table_next_id_valid;
93 /* Handle to the low-level table object */
97 uint64_t n_pkts_dropped_by_lkp_hit_ah;
98 uint64_t n_pkts_dropped_by_lkp_miss_ah;
99 uint64_t n_pkts_dropped_lkp_hit;
100 uint64_t n_pkts_dropped_lkp_miss;
103 #define RTE_PIPELINE_MAX_NAME_SZ 124
105 struct rte_pipeline {
106 /* Input parameters */
107 char name[RTE_PIPELINE_MAX_NAME_SZ];
109 uint32_t offset_port_id;
111 /* Internal tables */
112 struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
113 struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
114 struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
116 /* Occupancy of internal tables */
117 uint32_t num_ports_in;
118 uint32_t num_ports_out;
121 /* List of enabled ports */
122 uint64_t enabled_port_in_mask;
123 struct rte_port_in *port_in_next;
125 /* Pipeline run structures */
126 struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
127 struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
128 uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
129 uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
131 uint64_t n_pkts_ah_drop;
132 uint64_t pkts_drop_mask;
133 } __rte_cache_aligned;
135 static inline uint32_t
136 rte_mask_get_next(uint64_t mask, uint32_t pos)
138 uint64_t mask_rot = (mask << ((63 - pos) & 0x3F)) |
139 (mask >> ((pos + 1) & 0x3F));
140 return (__builtin_ctzll(mask_rot) - (63 - pos)) & 0x3F;
143 static inline uint32_t
144 rte_mask_get_prev(uint64_t mask, uint32_t pos)
146 uint64_t mask_rot = (mask >> (pos & 0x3F)) |
147 (mask << ((64 - pos) & 0x3F));
148 return ((63 - __builtin_clzll(mask_rot)) + pos) & 0x3F;
152 rte_pipeline_table_free(struct rte_table *table);
155 rte_pipeline_port_in_free(struct rte_port_in *port);
158 rte_pipeline_port_out_free(struct rte_port_out *port);
165 rte_pipeline_check_params(struct rte_pipeline_params *params)
167 if (params == NULL) {
168 RTE_LOG(ERR, PIPELINE,
169 "%s: Incorrect value for parameter params\n", __func__);
174 if (params->name == NULL) {
175 RTE_LOG(ERR, PIPELINE,
176 "%s: Incorrect value for parameter name\n", __func__);
181 if ((params->socket_id < 0) ||
182 (params->socket_id >= RTE_MAX_NUMA_NODES)) {
183 RTE_LOG(ERR, PIPELINE,
184 "%s: Incorrect value for parameter socket_id\n",
192 struct rte_pipeline *
193 rte_pipeline_create(struct rte_pipeline_params *params)
195 struct rte_pipeline *p;
198 /* Check input parameters */
199 status = rte_pipeline_check_params(params);
201 RTE_LOG(ERR, PIPELINE,
202 "%s: Pipeline params check failed (%d)\n",
207 /* Allocate memory for the pipeline on requested socket */
208 p = rte_zmalloc_socket("PIPELINE", sizeof(struct rte_pipeline),
209 RTE_CACHE_LINE_SIZE, params->socket_id);
212 RTE_LOG(ERR, PIPELINE,
213 "%s: Pipeline memory allocation failed\n", __func__);
217 /* Save input parameters */
218 snprintf(p->name, RTE_PIPELINE_MAX_NAME_SZ, "%s", params->name);
219 p->socket_id = params->socket_id;
220 p->offset_port_id = params->offset_port_id;
222 /* Initialize pipeline internal data structure */
224 p->num_ports_out = 0;
226 p->enabled_port_in_mask = 0;
227 p->port_in_next = NULL;
229 p->n_pkts_ah_drop = 0;
235 rte_pipeline_free(struct rte_pipeline *p)
239 /* Check input parameters */
241 RTE_LOG(ERR, PIPELINE,
242 "%s: rte_pipeline parameter is NULL\n", __func__);
246 /* Free input ports */
247 for (i = 0; i < p->num_ports_in; i++) {
248 struct rte_port_in *port = &p->ports_in[i];
250 rte_pipeline_port_in_free(port);
254 for (i = 0; i < p->num_tables; i++) {
255 struct rte_table *table = &p->tables[i];
257 rte_pipeline_table_free(table);
260 /* Free output ports */
261 for (i = 0; i < p->num_ports_out; i++) {
262 struct rte_port_out *port = &p->ports_out[i];
264 rte_pipeline_port_out_free(port);
267 /* Free pipeline memory */
278 rte_table_check_params(struct rte_pipeline *p,
279 struct rte_pipeline_table_params *params,
283 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
287 if (params == NULL) {
288 RTE_LOG(ERR, PIPELINE, "%s: params parameter is NULL\n",
292 if (table_id == NULL) {
293 RTE_LOG(ERR, PIPELINE, "%s: table_id parameter is NULL\n",
299 if (params->ops == NULL) {
300 RTE_LOG(ERR, PIPELINE, "%s: params->ops is NULL\n",
305 if (params->ops->f_create == NULL) {
306 RTE_LOG(ERR, PIPELINE,
307 "%s: f_create function pointer is NULL\n", __func__);
311 if (params->ops->f_lookup == NULL) {
312 RTE_LOG(ERR, PIPELINE,
313 "%s: f_lookup function pointer is NULL\n", __func__);
317 /* De we have room for one more table? */
318 if (p->num_tables == RTE_PIPELINE_TABLE_MAX) {
319 RTE_LOG(ERR, PIPELINE,
320 "%s: Incorrect value for num_tables parameter\n",
329 rte_pipeline_table_create(struct rte_pipeline *p,
330 struct rte_pipeline_table_params *params,
333 struct rte_table *table;
334 struct rte_pipeline_table_entry *default_entry;
336 uint32_t entry_size, id;
339 /* Check input arguments */
340 status = rte_table_check_params(p, params, table_id);
345 table = &p->tables[id];
347 /* Allocate space for the default table entry */
348 entry_size = sizeof(struct rte_pipeline_table_entry) +
349 params->action_data_size;
350 default_entry = rte_zmalloc_socket(
351 "PIPELINE", entry_size, RTE_CACHE_LINE_SIZE, p->socket_id);
352 if (default_entry == NULL) {
353 RTE_LOG(ERR, PIPELINE,
354 "%s: Failed to allocate default entry\n", __func__);
358 /* Create the table */
359 h_table = params->ops->f_create(params->arg_create, p->socket_id,
361 if (h_table == NULL) {
362 rte_free(default_entry);
363 RTE_LOG(ERR, PIPELINE, "%s: Table creation failed\n", __func__);
367 /* Commit current table to the pipeline */
371 /* Save input parameters */
372 memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
373 table->f_action_hit = params->f_action_hit;
374 table->f_action_miss = params->f_action_miss;
375 table->arg_ah = params->arg_ah;
376 table->entry_size = entry_size;
378 /* Clear the lookup miss actions (to be set later through API) */
379 table->default_entry = default_entry;
380 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
382 /* Initialize table internal data structure */
383 table->h_table = h_table;
384 table->table_next_id = 0;
385 table->table_next_id_valid = 0;
391 rte_pipeline_table_free(struct rte_table *table)
393 if (table->ops.f_free != NULL)
394 table->ops.f_free(table->h_table);
396 rte_free(table->default_entry);
400 rte_pipeline_table_default_entry_add(struct rte_pipeline *p,
402 struct rte_pipeline_table_entry *default_entry,
403 struct rte_pipeline_table_entry **default_entry_ptr)
405 struct rte_table *table;
407 /* Check input arguments */
409 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
414 if (default_entry == NULL) {
415 RTE_LOG(ERR, PIPELINE,
416 "%s: default_entry parameter is NULL\n", __func__);
420 if (table_id >= p->num_tables) {
421 RTE_LOG(ERR, PIPELINE,
422 "%s: table_id %d out of range\n", __func__, table_id);
426 table = &p->tables[table_id];
428 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
429 table->table_next_id_valid &&
430 (default_entry->table_id != table->table_next_id)) {
431 RTE_LOG(ERR, PIPELINE,
432 "%s: Tree-like topologies not allowed\n", __func__);
436 /* Set the lookup miss actions */
437 if ((default_entry->action == RTE_PIPELINE_ACTION_TABLE) &&
438 (table->table_next_id_valid == 0)) {
439 table->table_next_id = default_entry->table_id;
440 table->table_next_id_valid = 1;
443 memcpy(table->default_entry, default_entry, table->entry_size);
445 *default_entry_ptr = table->default_entry;
450 rte_pipeline_table_default_entry_delete(struct rte_pipeline *p,
452 struct rte_pipeline_table_entry *entry)
454 struct rte_table *table;
456 /* Check input arguments */
458 RTE_LOG(ERR, PIPELINE,
459 "%s: pipeline parameter is NULL\n", __func__);
463 if (table_id >= p->num_tables) {
464 RTE_LOG(ERR, PIPELINE,
465 "%s: table_id %d out of range\n", __func__, table_id);
469 table = &p->tables[table_id];
471 /* Save the current contents of the default entry */
473 memcpy(entry, table->default_entry, table->entry_size);
475 /* Clear the lookup miss actions */
476 memset(table->default_entry, 0, table->entry_size);
477 table->default_entry->action = RTE_PIPELINE_ACTION_DROP;
483 rte_pipeline_table_entry_add(struct rte_pipeline *p,
486 struct rte_pipeline_table_entry *entry,
488 struct rte_pipeline_table_entry **entry_ptr)
490 struct rte_table *table;
492 /* Check input arguments */
494 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
500 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", __func__);
505 RTE_LOG(ERR, PIPELINE, "%s: entry parameter is NULL\n",
510 if (table_id >= p->num_tables) {
511 RTE_LOG(ERR, PIPELINE,
512 "%s: table_id %d out of range\n", __func__, table_id);
516 table = &p->tables[table_id];
518 if (table->ops.f_add == NULL) {
519 RTE_LOG(ERR, PIPELINE, "%s: f_add function pointer NULL\n",
524 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
525 table->table_next_id_valid &&
526 (entry->table_id != table->table_next_id)) {
527 RTE_LOG(ERR, PIPELINE,
528 "%s: Tree-like topologies not allowed\n", __func__);
533 if ((entry->action == RTE_PIPELINE_ACTION_TABLE) &&
534 (table->table_next_id_valid == 0)) {
535 table->table_next_id = entry->table_id;
536 table->table_next_id_valid = 1;
539 return (table->ops.f_add)(table->h_table, key, (void *) entry,
540 key_found, (void **) entry_ptr);
544 rte_pipeline_table_entry_delete(struct rte_pipeline *p,
548 struct rte_pipeline_table_entry *entry)
550 struct rte_table *table;
552 /* Check input arguments */
554 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
560 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
565 if (table_id >= p->num_tables) {
566 RTE_LOG(ERR, PIPELINE,
567 "%s: table_id %d out of range\n", __func__, table_id);
571 table = &p->tables[table_id];
573 if (table->ops.f_delete == NULL) {
574 RTE_LOG(ERR, PIPELINE,
575 "%s: f_delete function pointer NULL\n", __func__);
579 return (table->ops.f_delete)(table->h_table, key, key_found, entry);
582 int rte_pipeline_table_entry_add_bulk(struct rte_pipeline *p,
585 struct rte_pipeline_table_entry **entries,
588 struct rte_pipeline_table_entry **entries_ptr)
590 struct rte_table *table;
593 /* Check input arguments */
595 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n",
601 RTE_LOG(ERR, PIPELINE, "%s: keys parameter is NULL\n", __func__);
605 if (entries == NULL) {
606 RTE_LOG(ERR, PIPELINE, "%s: entries parameter is NULL\n",
611 if (table_id >= p->num_tables) {
612 RTE_LOG(ERR, PIPELINE,
613 "%s: table_id %d out of range\n", __func__, table_id);
617 table = &p->tables[table_id];
619 if (table->ops.f_add_bulk == NULL) {
620 RTE_LOG(ERR, PIPELINE, "%s: f_add_bulk function pointer NULL\n",
625 for (i = 0; i < n_keys; i++) {
626 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
627 table->table_next_id_valid &&
628 (entries[i]->table_id != table->table_next_id)) {
629 RTE_LOG(ERR, PIPELINE,
630 "%s: Tree-like topologies not allowed\n", __func__);
636 for (i = 0; i < n_keys; i++) {
637 if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) &&
638 (table->table_next_id_valid == 0)) {
639 table->table_next_id = entries[i]->table_id;
640 table->table_next_id_valid = 1;
644 return (table->ops.f_add_bulk)(table->h_table, keys, (void **) entries,
645 n_keys, key_found, (void **) entries_ptr);
648 int rte_pipeline_table_entry_delete_bulk(struct rte_pipeline *p,
653 struct rte_pipeline_table_entry **entries)
655 struct rte_table *table;
657 /* Check input arguments */
659 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
665 RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n",
670 if (table_id >= p->num_tables) {
671 RTE_LOG(ERR, PIPELINE,
672 "%s: table_id %d out of range\n", __func__, table_id);
676 table = &p->tables[table_id];
678 if (table->ops.f_delete_bulk == NULL) {
679 RTE_LOG(ERR, PIPELINE,
680 "%s: f_delete function pointer NULL\n", __func__);
684 return (table->ops.f_delete_bulk)(table->h_table, keys, n_keys, key_found,
693 rte_pipeline_port_in_check_params(struct rte_pipeline *p,
694 struct rte_pipeline_port_in_params *params,
698 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
702 if (params == NULL) {
703 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
706 if (port_id == NULL) {
707 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
713 if (params->ops == NULL) {
714 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
719 if (params->ops->f_create == NULL) {
720 RTE_LOG(ERR, PIPELINE,
721 "%s: f_create function pointer NULL\n", __func__);
725 if (params->ops->f_rx == NULL) {
726 RTE_LOG(ERR, PIPELINE, "%s: f_rx function pointer NULL\n",
732 if ((params->burst_size == 0) ||
733 (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) {
734 RTE_LOG(ERR, PIPELINE, "%s: invalid value for burst_size\n",
739 /* Do we have room for one more port? */
740 if (p->num_ports_in == RTE_PIPELINE_PORT_IN_MAX) {
741 RTE_LOG(ERR, PIPELINE,
742 "%s: invalid value for num_ports_in\n", __func__);
750 rte_pipeline_port_out_check_params(struct rte_pipeline *p,
751 struct rte_pipeline_port_out_params *params,
755 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
760 if (params == NULL) {
761 RTE_LOG(ERR, PIPELINE, "%s: params parameter NULL\n", __func__);
765 if (port_id == NULL) {
766 RTE_LOG(ERR, PIPELINE, "%s: port_id parameter NULL\n",
772 if (params->ops == NULL) {
773 RTE_LOG(ERR, PIPELINE, "%s: params->ops parameter NULL\n",
778 if (params->ops->f_create == NULL) {
779 RTE_LOG(ERR, PIPELINE,
780 "%s: f_create function pointer NULL\n", __func__);
784 if (params->ops->f_tx == NULL) {
785 RTE_LOG(ERR, PIPELINE,
786 "%s: f_tx function pointer NULL\n", __func__);
790 if (params->ops->f_tx_bulk == NULL) {
791 RTE_LOG(ERR, PIPELINE,
792 "%s: f_tx_bulk function pointer NULL\n", __func__);
796 /* Do we have room for one more port? */
797 if (p->num_ports_out == RTE_PIPELINE_PORT_OUT_MAX) {
798 RTE_LOG(ERR, PIPELINE,
799 "%s: invalid value for num_ports_out\n", __func__);
807 rte_pipeline_port_in_create(struct rte_pipeline *p,
808 struct rte_pipeline_port_in_params *params,
811 struct rte_port_in *port;
816 /* Check input arguments */
817 status = rte_pipeline_port_in_check_params(p, params, port_id);
821 id = p->num_ports_in;
822 port = &p->ports_in[id];
824 /* Create the port */
825 h_port = params->ops->f_create(params->arg_create, p->socket_id);
826 if (h_port == NULL) {
827 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
831 /* Commit current table to the pipeline */
835 /* Save input parameters */
836 memcpy(&port->ops, params->ops, sizeof(struct rte_port_in_ops));
837 port->f_action = params->f_action;
838 port->arg_ah = params->arg_ah;
839 port->burst_size = params->burst_size;
841 /* Initialize port internal data structure */
842 port->table_id = RTE_TABLE_INVALID;
843 port->h_port = h_port;
850 rte_pipeline_port_in_free(struct rte_port_in *port)
852 if (port->ops.f_free != NULL)
853 port->ops.f_free(port->h_port);
857 rte_pipeline_port_out_create(struct rte_pipeline *p,
858 struct rte_pipeline_port_out_params *params,
861 struct rte_port_out *port;
866 /* Check input arguments */
867 status = rte_pipeline_port_out_check_params(p, params, port_id);
871 id = p->num_ports_out;
872 port = &p->ports_out[id];
874 /* Create the port */
875 h_port = params->ops->f_create(params->arg_create, p->socket_id);
876 if (h_port == NULL) {
877 RTE_LOG(ERR, PIPELINE, "%s: Port creation failed\n", __func__);
881 /* Commit current table to the pipeline */
885 /* Save input parameters */
886 memcpy(&port->ops, params->ops, sizeof(struct rte_port_out_ops));
887 port->f_action = params->f_action;
888 port->arg_ah = params->arg_ah;
890 /* Initialize port internal data structure */
891 port->h_port = h_port;
897 rte_pipeline_port_out_free(struct rte_port_out *port)
899 if (port->ops.f_free != NULL)
900 port->ops.f_free(port->h_port);
904 rte_pipeline_port_in_connect_to_table(struct rte_pipeline *p,
908 struct rte_port_in *port;
910 /* Check input arguments */
912 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
917 if (port_id >= p->num_ports_in) {
918 RTE_LOG(ERR, PIPELINE,
919 "%s: port IN ID %u is out of range\n",
924 if (table_id >= p->num_tables) {
925 RTE_LOG(ERR, PIPELINE,
926 "%s: Table ID %u is out of range\n",
931 port = &p->ports_in[port_id];
932 port->table_id = table_id;
938 rte_pipeline_port_in_enable(struct rte_pipeline *p, uint32_t port_id)
940 struct rte_port_in *port, *port_prev, *port_next;
942 uint32_t port_prev_id, port_next_id;
944 /* Check input arguments */
946 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
951 if (port_id >= p->num_ports_in) {
952 RTE_LOG(ERR, PIPELINE,
953 "%s: port IN ID %u is out of range\n",
958 port = &p->ports_in[port_id];
960 /* Return if current input port is already enabled */
961 port_mask = 1LLU << port_id;
962 if (p->enabled_port_in_mask & port_mask)
965 p->enabled_port_in_mask |= port_mask;
967 /* Add current input port to the pipeline chain of enabled ports */
968 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
969 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
971 port_prev = &p->ports_in[port_prev_id];
972 port_next = &p->ports_in[port_next_id];
974 port_prev->next = port;
975 port->next = port_next;
977 /* Check if list of enabled ports was previously empty */
978 if (p->enabled_port_in_mask == port_mask)
979 p->port_in_next = port;
985 rte_pipeline_port_in_disable(struct rte_pipeline *p, uint32_t port_id)
987 struct rte_port_in *port, *port_prev, *port_next;
989 uint32_t port_prev_id, port_next_id;
991 /* Check input arguments */
993 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
998 if (port_id >= p->num_ports_in) {
999 RTE_LOG(ERR, PIPELINE, "%s: port IN ID %u is out of range\n",
1004 port = &p->ports_in[port_id];
1006 /* Return if current input port is already disabled */
1007 port_mask = 1LLU << port_id;
1008 if ((p->enabled_port_in_mask & port_mask) == 0)
1011 p->enabled_port_in_mask &= ~port_mask;
1013 /* Return if no other enabled ports */
1014 if (p->enabled_port_in_mask == 0) {
1015 p->port_in_next = NULL;
1020 /* Add current input port to the pipeline chain of enabled ports */
1021 port_prev_id = rte_mask_get_prev(p->enabled_port_in_mask, port_id);
1022 port_next_id = rte_mask_get_next(p->enabled_port_in_mask, port_id);
1024 port_prev = &p->ports_in[port_prev_id];
1025 port_next = &p->ports_in[port_next_id];
1027 port_prev->next = port_next;
1029 /* Check if the port which has just been disabled is next to serve */
1030 if (port == p->port_in_next)
1031 p->port_in_next = port_next;
1041 rte_pipeline_check(struct rte_pipeline *p)
1043 uint32_t port_in_id;
1045 /* Check input arguments */
1047 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1052 /* Check that pipeline has at least one input port, one table and one
1054 if (p->num_ports_in == 0) {
1055 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 input port\n",
1059 if (p->num_tables == 0) {
1060 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 table\n",
1064 if (p->num_ports_out == 0) {
1065 RTE_LOG(ERR, PIPELINE, "%s: must have at least 1 output port\n",
1070 /* Check that all input ports are connected */
1071 for (port_in_id = 0; port_in_id < p->num_ports_in; port_in_id++) {
1072 struct rte_port_in *port_in = &p->ports_in[port_in_id];
1074 if (port_in->table_id == RTE_TABLE_INVALID) {
1075 RTE_LOG(ERR, PIPELINE,
1076 "%s: Port IN ID %u is not connected\n",
1077 __func__, port_in_id);
1086 rte_pipeline_compute_masks(struct rte_pipeline *p, uint64_t pkts_mask)
1088 p->action_mask1[RTE_PIPELINE_ACTION_DROP] = 0;
1089 p->action_mask1[RTE_PIPELINE_ACTION_PORT] = 0;
1090 p->action_mask1[RTE_PIPELINE_ACTION_PORT_META] = 0;
1091 p->action_mask1[RTE_PIPELINE_ACTION_TABLE] = 0;
1093 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1094 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1097 for (i = 0; i < n_pkts; i++) {
1098 uint64_t pkt_mask = 1LLU << i;
1099 uint32_t pos = p->entries[i]->action;
1101 p->action_mask1[pos] |= pkt_mask;
1106 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1107 uint64_t pkt_mask = 1LLU << i;
1110 if ((pkt_mask & pkts_mask) == 0)
1113 pos = p->entries[i]->action;
1114 p->action_mask1[pos] |= pkt_mask;
1120 rte_pipeline_action_handler_port_bulk(struct rte_pipeline *p,
1121 uint64_t pkts_mask, uint32_t port_id)
1123 struct rte_port_out *port_out = &p->ports_out[port_id];
1125 p->pkts_mask = pkts_mask;
1127 /* Output port user actions */
1128 if (port_out->f_action != NULL) {
1129 port_out->f_action(p, p->pkts, pkts_mask, port_out->arg_ah);
1131 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1132 port_out->n_pkts_dropped_by_ah);
1135 /* Output port TX */
1136 if (p->pkts_mask != 0)
1137 port_out->ops.f_tx_bulk(port_out->h_port,
1143 rte_pipeline_action_handler_port(struct rte_pipeline *p, uint64_t pkts_mask)
1145 p->pkts_mask = pkts_mask;
1147 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1148 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1151 for (i = 0; i < n_pkts; i++) {
1152 struct rte_mbuf *pkt = p->pkts[i];
1153 uint32_t port_out_id = p->entries[i]->port_id;
1154 struct rte_port_out *port_out =
1155 &p->ports_out[port_out_id];
1157 /* Output port user actions */
1158 if (port_out->f_action == NULL) /* Output port TX */
1159 port_out->ops.f_tx(port_out->h_port, pkt);
1161 uint64_t pkt_mask = 1LLU << i;
1163 port_out->f_action(p,
1168 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1169 port_out->n_pkts_dropped_by_ah);
1171 /* Output port TX */
1172 if (pkt_mask & p->pkts_mask)
1173 port_out->ops.f_tx(port_out->h_port,
1180 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1181 uint64_t pkt_mask = 1LLU << i;
1182 struct rte_mbuf *pkt;
1183 struct rte_port_out *port_out;
1184 uint32_t port_out_id;
1186 if ((pkt_mask & pkts_mask) == 0)
1190 port_out_id = p->entries[i]->port_id;
1191 port_out = &p->ports_out[port_out_id];
1193 /* Output port user actions */
1194 if (port_out->f_action == NULL) /* Output port TX */
1195 port_out->ops.f_tx(port_out->h_port, pkt);
1197 port_out->f_action(p,
1202 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1203 port_out->n_pkts_dropped_by_ah);
1205 /* Output port TX */
1206 if (pkt_mask & p->pkts_mask)
1207 port_out->ops.f_tx(port_out->h_port,
1215 rte_pipeline_action_handler_port_meta(struct rte_pipeline *p,
1218 p->pkts_mask = pkts_mask;
1220 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1221 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1224 for (i = 0; i < n_pkts; i++) {
1225 struct rte_mbuf *pkt = p->pkts[i];
1226 uint32_t port_out_id =
1227 RTE_MBUF_METADATA_UINT32(pkt,
1229 struct rte_port_out *port_out = &p->ports_out[
1232 /* Output port user actions */
1233 if (port_out->f_action == NULL) /* Output port TX */
1234 port_out->ops.f_tx(port_out->h_port, pkt);
1236 uint64_t pkt_mask = 1LLU << i;
1238 port_out->f_action(p,
1243 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1244 port_out->n_pkts_dropped_by_ah);
1246 /* Output port TX */
1247 if (pkt_mask & p->pkts_mask)
1248 port_out->ops.f_tx(port_out->h_port,
1255 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1256 uint64_t pkt_mask = 1LLU << i;
1257 struct rte_mbuf *pkt;
1258 struct rte_port_out *port_out;
1259 uint32_t port_out_id;
1261 if ((pkt_mask & pkts_mask) == 0)
1265 port_out_id = RTE_MBUF_METADATA_UINT32(pkt,
1267 port_out = &p->ports_out[port_out_id];
1269 /* Output port user actions */
1270 if (port_out->f_action == NULL) /* Output port TX */
1271 port_out->ops.f_tx(port_out->h_port, pkt);
1273 port_out->f_action(p,
1278 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1279 port_out->n_pkts_dropped_by_ah);
1281 /* Output port TX */
1282 if (pkt_mask & p->pkts_mask)
1283 port_out->ops.f_tx(port_out->h_port,
1291 rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
1293 if ((pkts_mask & (pkts_mask + 1)) == 0) {
1294 uint64_t n_pkts = __builtin_popcountll(pkts_mask);
1297 for (i = 0; i < n_pkts; i++)
1298 rte_pktmbuf_free(p->pkts[i]);
1302 for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) {
1303 uint64_t pkt_mask = 1LLU << i;
1305 if ((pkt_mask & pkts_mask) == 0)
1308 rte_pktmbuf_free(p->pkts[i]);
1314 rte_pipeline_run(struct rte_pipeline *p)
1316 struct rte_port_in *port_in = p->port_in_next;
1317 uint32_t n_pkts, table_id;
1319 if (port_in == NULL)
1323 n_pkts = port_in->ops.f_rx(port_in->h_port, p->pkts,
1324 port_in->burst_size);
1326 p->port_in_next = port_in->next;
1330 p->pkts_mask = RTE_LEN2MASK(n_pkts, uint64_t);
1331 p->action_mask0[RTE_PIPELINE_ACTION_DROP] = 0;
1332 p->action_mask0[RTE_PIPELINE_ACTION_PORT] = 0;
1333 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] = 0;
1334 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1336 /* Input port user actions */
1337 if (port_in->f_action != NULL) {
1338 port_in->f_action(p, p->pkts, n_pkts, port_in->arg_ah);
1340 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1341 port_in->n_pkts_dropped_by_ah);
1345 for (table_id = port_in->table_id; p->pkts_mask != 0; ) {
1346 struct rte_table *table;
1347 uint64_t lookup_hit_mask, lookup_miss_mask;
1350 table = &p->tables[table_id];
1351 table->ops.f_lookup(table->h_table, p->pkts, p->pkts_mask,
1352 &lookup_hit_mask, (void **) p->entries);
1353 lookup_miss_mask = p->pkts_mask & (~lookup_hit_mask);
1356 if (lookup_miss_mask != 0) {
1357 struct rte_pipeline_table_entry *default_entry =
1358 table->default_entry;
1360 p->pkts_mask = lookup_miss_mask;
1362 /* Table user actions */
1363 if (table->f_action_miss != NULL) {
1364 table->f_action_miss(p,
1370 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1371 table->n_pkts_dropped_by_lkp_miss_ah);
1374 /* Table reserved actions */
1375 if ((default_entry->action == RTE_PIPELINE_ACTION_PORT) &&
1376 (p->pkts_mask != 0))
1377 rte_pipeline_action_handler_port_bulk(p,
1379 default_entry->port_id);
1381 uint32_t pos = default_entry->action;
1383 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1385 p->action_mask0[pos] |= p->pkts_mask;
1387 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1388 table->n_pkts_dropped_lkp_miss);
1393 if (lookup_hit_mask != 0) {
1394 p->pkts_mask = lookup_hit_mask;
1396 /* Table user actions */
1397 if (table->f_action_hit != NULL) {
1398 table->f_action_hit(p,
1404 RTE_PIPELINE_STATS_AH_DROP_READ(p,
1405 table->n_pkts_dropped_by_lkp_hit_ah);
1408 /* Table reserved actions */
1409 RTE_PIPELINE_STATS_TABLE_DROP0(p);
1410 rte_pipeline_compute_masks(p, p->pkts_mask);
1411 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |=
1413 RTE_PIPELINE_ACTION_DROP];
1414 p->action_mask0[RTE_PIPELINE_ACTION_PORT] |=
1416 RTE_PIPELINE_ACTION_PORT];
1417 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META] |=
1419 RTE_PIPELINE_ACTION_PORT_META];
1420 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] |=
1422 RTE_PIPELINE_ACTION_TABLE];
1424 RTE_PIPELINE_STATS_TABLE_DROP1(p,
1425 table->n_pkts_dropped_lkp_hit);
1428 /* Prepare for next iteration */
1429 p->pkts_mask = p->action_mask0[RTE_PIPELINE_ACTION_TABLE];
1430 table_id = table->table_next_id;
1431 p->action_mask0[RTE_PIPELINE_ACTION_TABLE] = 0;
1434 /* Table reserved action PORT */
1435 rte_pipeline_action_handler_port(p,
1436 p->action_mask0[RTE_PIPELINE_ACTION_PORT]);
1438 /* Table reserved action PORT META */
1439 rte_pipeline_action_handler_port_meta(p,
1440 p->action_mask0[RTE_PIPELINE_ACTION_PORT_META]);
1442 /* Table reserved action DROP */
1443 rte_pipeline_action_handler_drop(p,
1444 p->action_mask0[RTE_PIPELINE_ACTION_DROP]);
1446 /* Pick candidate for next port IN to serve */
1447 p->port_in_next = port_in->next;
1449 return (int) n_pkts;
1453 rte_pipeline_flush(struct rte_pipeline *p)
1457 /* Check input arguments */
1459 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1464 for (port_id = 0; port_id < p->num_ports_out; port_id++) {
1465 struct rte_port_out *port = &p->ports_out[port_id];
1467 if (port->ops.f_flush != NULL)
1468 port->ops.f_flush(port->h_port);
1475 rte_pipeline_port_out_packet_insert(struct rte_pipeline *p,
1476 uint32_t port_id, struct rte_mbuf *pkt)
1478 struct rte_port_out *port_out = &p->ports_out[port_id];
1480 port_out->ops.f_tx(port_out->h_port, pkt); /* Output port TX */
1485 int rte_pipeline_ah_packet_hijack(struct rte_pipeline *p,
1488 pkts_mask &= p->pkts_mask;
1489 p->pkts_mask &= ~pkts_mask;
1494 int rte_pipeline_ah_packet_drop(struct rte_pipeline *p,
1497 pkts_mask &= p->pkts_mask;
1498 p->pkts_mask &= ~pkts_mask;
1499 p->action_mask0[RTE_PIPELINE_ACTION_DROP] |= pkts_mask;
1501 RTE_PIPELINE_STATS_AH_DROP_WRITE(p, pkts_mask);
1505 int rte_pipeline_port_in_stats_read(struct rte_pipeline *p, uint32_t port_id,
1506 struct rte_pipeline_port_in_stats *stats, int clear)
1508 struct rte_port_in *port;
1512 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1517 if (port_id >= p->num_ports_in) {
1518 RTE_LOG(ERR, PIPELINE,
1519 "%s: port IN ID %u is out of range\n",
1524 port = &p->ports_in[port_id];
1526 if (port->ops.f_stats != NULL) {
1527 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1530 } else if (stats != NULL)
1531 memset(&stats->stats, 0, sizeof(stats->stats));
1534 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1537 port->n_pkts_dropped_by_ah = 0;
1542 int rte_pipeline_port_out_stats_read(struct rte_pipeline *p, uint32_t port_id,
1543 struct rte_pipeline_port_out_stats *stats, int clear)
1545 struct rte_port_out *port;
1549 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n", __func__);
1553 if (port_id >= p->num_ports_out) {
1554 RTE_LOG(ERR, PIPELINE,
1555 "%s: port OUT ID %u is out of range\n", __func__, port_id);
1559 port = &p->ports_out[port_id];
1560 if (port->ops.f_stats != NULL) {
1561 retval = port->ops.f_stats(port->h_port, &stats->stats, clear);
1564 } else if (stats != NULL)
1565 memset(&stats->stats, 0, sizeof(stats->stats));
1568 stats->n_pkts_dropped_by_ah = port->n_pkts_dropped_by_ah;
1571 port->n_pkts_dropped_by_ah = 0;
1576 int rte_pipeline_table_stats_read(struct rte_pipeline *p, uint32_t table_id,
1577 struct rte_pipeline_table_stats *stats, int clear)
1579 struct rte_table *table;
1583 RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n",
1588 if (table_id >= p->num_tables) {
1589 RTE_LOG(ERR, PIPELINE,
1590 "%s: table %u is out of range\n", __func__, table_id);
1594 table = &p->tables[table_id];
1595 if (table->ops.f_stats != NULL) {
1596 retval = table->ops.f_stats(table->h_table, &stats->stats, clear);
1599 } else if (stats != NULL)
1600 memset(&stats->stats, 0, sizeof(stats->stats));
1602 if (stats != NULL) {
1603 stats->n_pkts_dropped_by_lkp_hit_ah =
1604 table->n_pkts_dropped_by_lkp_hit_ah;
1605 stats->n_pkts_dropped_by_lkp_miss_ah =
1606 table->n_pkts_dropped_by_lkp_miss_ah;
1607 stats->n_pkts_dropped_lkp_hit = table->n_pkts_dropped_lkp_hit;
1608 stats->n_pkts_dropped_lkp_miss = table->n_pkts_dropped_lkp_miss;
1612 table->n_pkts_dropped_by_lkp_hit_ah = 0;
1613 table->n_pkts_dropped_by_lkp_miss_ah = 0;
1614 table->n_pkts_dropped_lkp_hit = 0;
1615 table->n_pkts_dropped_lkp_miss = 0;