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.
35 #include <rte_pipeline.h>
38 #include <rte_hexdump.h>
39 #include "test_table.h"
40 #include "test_table_pipeline.h"
42 #define RTE_CBUF_UINT8_PTR(cbuf, offset) \
44 #define RTE_CBUF_UINT32_PTR(cbuf, offset) \
45 (&cbuf->data32[offset/sizeof(uint32_t)])
49 static rte_pipeline_port_out_action_handler port_action_0x00
50 (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg);
51 static rte_pipeline_port_out_action_handler port_action_0xFF
52 (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg);
53 static rte_pipeline_port_out_action_handler port_action_stub
54 (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg);
57 rte_pipeline_port_out_action_handler port_action_0x00(struct rte_mbuf **pkts,
65 printf("Port Action 0x00\n");
70 rte_pipeline_port_out_action_handler port_action_0xFF(struct rte_mbuf **pkts,
78 printf("Port Action 0xFF\n");
83 rte_pipeline_port_out_action_handler port_action_stub(struct rte_mbuf **pkts,
90 RTE_SET_USED(pkts_mask);
92 printf("Port Action stub\n");
98 rte_pipeline_table_action_handler_hit
99 table_action_0x00(struct rte_mbuf **pkts, uint64_t *pkts_mask,
100 struct rte_pipeline_table_entry **actions, uint32_t action_mask);
102 rte_pipeline_table_action_handler_hit
103 table_action_stub_hit(struct rte_mbuf **pkts, uint64_t *pkts_mask,
104 struct rte_pipeline_table_entry **actions, uint32_t action_mask);
106 rte_pipeline_table_action_handler_miss
107 table_action_stub_miss(struct rte_mbuf **pkts, uint64_t *pkts_mask,
108 struct rte_pipeline_table_entry *action, uint32_t action_mask);
110 rte_pipeline_table_action_handler_hit
111 table_action_0x00(__attribute__((unused)) struct rte_mbuf **pkts,
113 __attribute__((unused)) struct rte_pipeline_table_entry **actions,
114 __attribute__((unused)) uint32_t action_mask)
116 printf("Table Action, setting pkts_mask to 0x00\n");
121 rte_pipeline_table_action_handler_hit
122 table_action_stub_hit(__attribute__((unused)) struct rte_mbuf **pkts,
124 __attribute__((unused)) struct rte_pipeline_table_entry **actions,
125 __attribute__((unused)) uint32_t action_mask)
127 printf("STUB Table Action Hit - doing nothing\n");
128 printf("STUB Table Action Hit - setting mask to 0x%"PRIx64"\n",
130 *pkts_mask = override_hit_mask;
133 rte_pipeline_table_action_handler_miss
134 table_action_stub_miss(__attribute__((unused)) struct rte_mbuf **pkts,
136 __attribute__((unused)) struct rte_pipeline_table_entry *action,
137 __attribute__((unused)) uint32_t action_mask)
139 printf("STUB Table Action Miss - setting mask to 0x%"PRIx64"\n",
141 *pkts_mask = override_miss_mask;
158 char pipeline_test_names[][64] = {
173 cleanup_pipeline(void)
176 rte_pipeline_free(p);
182 static int check_pipeline_invalid_params(void);
185 check_pipeline_invalid_params(void)
187 struct rte_pipeline_params pipeline_params_1 = {
191 struct rte_pipeline_params pipeline_params_2 = {
195 struct rte_pipeline_params pipeline_params_3 = {
200 p = rte_pipeline_create(NULL);
202 RTE_LOG(INFO, PIPELINE,
203 "%s: configured pipeline with null params\n",
207 p = rte_pipeline_create(&pipeline_params_1);
209 RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with NULL "
214 p = rte_pipeline_create(&pipeline_params_2);
216 RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid "
217 "socket\n", __func__);
221 p = rte_pipeline_create(&pipeline_params_3);
223 RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid "
224 "socket\n", __func__);
228 /* Check pipeline consistency */
229 if (!rte_pipeline_check(p)) {
230 rte_panic("Pipeline consistency reported as OK\n");
242 setup_pipeline(int test_type)
246 struct rte_pipeline_params pipeline_params = {
251 RTE_LOG(INFO, PIPELINE, "%s: **** Setting up %s test\n",
252 __func__, pipeline_test_names[test_type]);
254 /* Pipeline configuration */
255 p = rte_pipeline_create(&pipeline_params);
257 RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n",
262 ret = rte_pipeline_free(p);
264 RTE_LOG(INFO, PIPELINE, "%s: Failed to free pipeline\n",
269 /* Pipeline configuration */
270 p = rte_pipeline_create(&pipeline_params);
272 RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n",
278 /* Input port configuration */
279 for (i = 0; i < N_PORTS; i++) {
280 struct rte_port_ring_reader_params port_ring_params = {
284 struct rte_pipeline_port_in_params port_params = {
285 .ops = &rte_port_ring_reader_ops,
286 .arg_create = (void *) &port_ring_params,
288 .burst_size = BURST_SIZE,
291 /* Put in action for some ports */
293 port_params.f_action = NULL;
295 ret = rte_pipeline_port_in_create(p, &port_params,
298 rte_panic("Unable to configure input port %d, ret:%d\n",
304 /* output Port configuration */
305 for (i = 0; i < N_PORTS; i++) {
306 struct rte_port_ring_writer_params port_ring_params = {
308 .tx_burst_sz = BURST_SIZE,
311 struct rte_pipeline_port_out_params port_params = {
312 .ops = &rte_port_ring_writer_ops,
313 .arg_create = (void *) &port_ring_params,
319 port_params.f_action = port_out_action;
321 if (rte_pipeline_port_out_create(p, &port_params,
323 rte_panic("Unable to configure output port %d\n", i);
328 /* Table configuration */
329 for (i = 0; i < N_PORTS; i++) {
330 struct rte_pipeline_table_params table_params = {
331 .ops = &rte_table_stub_ops,
333 .f_action_hit = action_handler_hit,
334 .f_action_miss = action_handler_miss,
335 .action_data_size = 0,
338 if (rte_pipeline_table_create(p, &table_params, &table_id[i])) {
339 rte_panic("Unable to configure table %u\n", i);
343 if (connect_miss_action_to_table)
344 if (rte_pipeline_table_create(p, &table_params,
346 rte_panic("Unable to configure table %u\n", i);
351 for (i = 0; i < N_PORTS; i++)
352 if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
354 rte_panic("Unable to connect input port %u to "
355 "table %u\n", port_in_id[i], table_id[i]);
359 /* Add entries to tables */
360 for (i = 0; i < N_PORTS; i++) {
361 struct rte_pipeline_table_entry default_entry = {
362 .action = (enum rte_pipeline_action)
363 table_entry_default_action,
364 {.port_id = port_out_id[i^1]},
366 struct rte_pipeline_table_entry *default_entry_ptr;
368 if (connect_miss_action_to_table) {
369 printf("Setting first table to output to next table\n");
370 default_entry.action = RTE_PIPELINE_ACTION_TABLE;
371 default_entry.table_id = table_id[i+2];
374 /* Add the default action for the table. */
375 ret = rte_pipeline_table_default_entry_add(p, table_id[i],
376 &default_entry, &default_entry_ptr);
378 rte_panic("Unable to add default entry to table %u "
379 "code %d\n", table_id[i], ret);
382 printf("Added default entry to table id %d with "
384 table_id[i], default_entry.action);
386 if (connect_miss_action_to_table) {
387 /* We create a second table so the first can pass
389 struct rte_pipeline_table_entry default_entry = {
390 .action = RTE_PIPELINE_ACTION_PORT,
391 {.port_id = port_out_id[i^1]},
393 printf("Setting secont table to output to port\n");
395 /* Add the default action for the table. */
396 ret = rte_pipeline_table_default_entry_add(p,
398 &default_entry, &default_entry_ptr);
400 rte_panic("Unable to add default entry to "
401 "table %u code %d\n",
405 printf("Added default entry to table id %d "
407 table_id[i], default_entry.action);
411 /* Enable input ports */
412 for (i = 0; i < N_PORTS ; i++)
413 if (rte_pipeline_port_in_enable(p, port_in_id[i]))
414 rte_panic("Unable to enable input port %u\n",
417 /* Check pipeline consistency */
418 if (rte_pipeline_check(p) < 0) {
419 rte_panic("Pipeline consistency check failed\n");
422 printf("Pipeline Consistency OK!\n");
431 test_pipeline_single_filter(int test_type, int expected_count)
438 RTE_LOG(INFO, PIPELINE, "%s: **** Running %s test\n",
439 __func__, pipeline_test_names[test_type]);
440 /* Run pipeline once */
444 ret = rte_pipeline_flush(NULL);
445 if (ret != -EINVAL) {
446 RTE_LOG(INFO, PIPELINE,
447 "%s: No pipeline flush error NULL pipeline (%d)\n",
453 * Allocate a few mbufs and manually insert into the rings. */
454 for (i = 0; i < N_PORTS; i++)
455 for (j = 0; j < N_PORTS; j++) {
460 m = rte_pktmbuf_alloc(pool);
462 rte_panic("Failed to alloc mbuf from pool\n");
465 key = RTE_MBUF_METADATA_UINT8_PTR(m, 32);
467 k32 = (uint32_t *) key;
468 k32[0] = 0xadadadad >> (j % 2);
470 RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n",
472 rte_ring_enqueue(rings_rx[i], m);
475 /* Run pipeline once */
479 * need to flush the pipeline, as there may be less hits than the burst
480 size and they will not have been flushed to the tx rings. */
481 rte_pipeline_flush(p);
484 * Now we'll see what we got back on the tx rings. We should see whatever
485 * packets we had hits on that were destined for the output ports.
489 for (i = 0; i < N_PORTS; i++) {
490 void *objs[RING_TX_SIZE];
491 struct rte_mbuf *mbuf;
493 ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10);
495 printf("Got no objects from ring %d - error code %d\n",
498 printf("Got %d object(s) from ring %d!\n", ret, i);
499 for (j = 0; j < ret; j++) {
500 mbuf = (struct rte_mbuf *)objs[j];
501 rte_hexdump(stdout, "Object:", mbuf->pkt.data,
503 rte_pktmbuf_free(mbuf);
509 if (tx_count != expected_count) {
510 RTE_LOG(INFO, PIPELINE,
511 "%s: Unexpected packets out for %s test, expected %d, "
512 "got %d\n", __func__, pipeline_test_names[test_type],
513 expected_count, tx_count);
526 test_table_pipeline(void)
528 /* TEST - All packets dropped */
529 action_handler_hit = NULL;
530 action_handler_miss = NULL;
531 table_entry_default_action = RTE_PIPELINE_ACTION_DROP;
532 setup_pipeline(e_TEST_STUB);
533 if (test_pipeline_single_filter(e_TEST_STUB, 0) < 0)
536 /* TEST - All packets passed through */
537 table_entry_default_action = RTE_PIPELINE_ACTION_PORT;
538 setup_pipeline(e_TEST_STUB);
539 if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0)
542 /* TEST - one packet per port */
543 action_handler_hit = NULL;
544 action_handler_miss =
545 (rte_pipeline_table_action_handler_miss) table_action_stub_miss;
546 table_entry_default_action = RTE_PIPELINE_ACTION_PORT;
547 override_miss_mask = 0x01; /* one packet per port */
548 setup_pipeline(e_TEST_STUB);
549 if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0)
552 /* TEST - one packet per port */
553 override_miss_mask = 0x02; /*all per port */
554 setup_pipeline(e_TEST_STUB);
555 if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0)
558 /* TEST - all packets per port */
559 override_miss_mask = 0x03; /*all per port */
560 setup_pipeline(e_TEST_STUB);
561 if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0)
565 * This test will set up two tables in the pipeline. the first table
566 * will forward to another table on miss, and the second table will
569 connect_miss_action_to_table = 1;
570 table_entry_default_action = RTE_PIPELINE_ACTION_TABLE;
571 action_handler_hit = NULL; /* not for stub, hitmask always zero */
572 action_handler_miss = NULL;
573 setup_pipeline(e_TEST_STUB);
574 if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0)
576 connect_miss_action_to_table = 0;
578 printf("TEST - two tables, hitmask override to 0x01\n");
579 connect_miss_action_to_table = 1;
580 action_handler_miss =
581 (rte_pipeline_table_action_handler_miss)table_action_stub_miss;
582 override_miss_mask = 0x01;
583 setup_pipeline(e_TEST_STUB);
584 if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0)
586 connect_miss_action_to_table = 0;
588 if (check_pipeline_invalid_params()) {
589 RTE_LOG(INFO, PIPELINE, "%s: Check pipeline invalid params "
590 "failed.\n", __func__);