1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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. 32 */ 33 34 #ifndef RTE_LIBRTE_PIPELINE 35 36 #include "test.h" 37 38 #else 39 40 #include <string.h> 41 #include <rte_pipeline.h> 42 #include <rte_log.h> 43 #include <inttypes.h> 44 #include <rte_hexdump.h> 45 #include "test_table.h" 46 #include "test_table_pipeline.h" 47 48 #define RTE_CBUF_UINT8_PTR(cbuf, offset) \ 49 (&cbuf->data[offset]) 50 #define RTE_CBUF_UINT32_PTR(cbuf, offset) \ 51 (&cbuf->data32[offset/sizeof(uint32_t)]) 52 53 #if 0 54 55 static rte_pipeline_port_out_action_handler port_action_0x00 56 (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); 57 static rte_pipeline_port_out_action_handler port_action_0xFF 58 (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); 59 static rte_pipeline_port_out_action_handler port_action_stub 60 (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); 61 62 63 rte_pipeline_port_out_action_handler port_action_0x00(struct rte_mbuf **pkts, 64 uint32_t n, 65 uint64_t *pkts_mask, 66 void *arg) 67 { 68 RTE_SET_USED(pkts); 69 RTE_SET_USED(n); 70 RTE_SET_USED(arg); 71 printf("Port Action 0x00\n"); 72 *pkts_mask = 0x00; 73 return 0; 74 } 75 76 rte_pipeline_port_out_action_handler port_action_0xFF(struct rte_mbuf **pkts, 77 uint32_t n, 78 uint64_t *pkts_mask, 79 void *arg) 80 { 81 RTE_SET_USED(pkts); 82 RTE_SET_USED(n); 83 RTE_SET_USED(arg); 84 printf("Port Action 0xFF\n"); 85 *pkts_mask = 0xFF; 86 return 0; 87 } 88 89 rte_pipeline_port_out_action_handler port_action_stub(struct rte_mbuf **pkts, 90 uint32_t n, 91 uint64_t *pkts_mask, 92 void *arg) 93 { 94 RTE_SET_USED(pkts); 95 RTE_SET_USED(n); 96 RTE_SET_USED(pkts_mask); 97 RTE_SET_USED(arg); 98 printf("Port Action stub\n"); 99 return 0; 100 } 101 102 #endif 103 104 rte_pipeline_table_action_handler_hit 105 table_action_0x00(struct rte_mbuf **pkts, uint64_t *pkts_mask, 106 struct rte_pipeline_table_entry **actions, uint32_t action_mask); 107 108 rte_pipeline_table_action_handler_hit 109 table_action_stub_hit(struct rte_mbuf **pkts, uint64_t *pkts_mask, 110 struct rte_pipeline_table_entry **actions, uint32_t action_mask); 111 112 rte_pipeline_table_action_handler_miss 113 table_action_stub_miss(struct rte_mbuf **pkts, uint64_t *pkts_mask, 114 struct rte_pipeline_table_entry *action, uint32_t action_mask); 115 116 rte_pipeline_table_action_handler_hit 117 table_action_0x00(__attribute__((unused)) struct rte_mbuf **pkts, 118 uint64_t *pkts_mask, 119 __attribute__((unused)) struct rte_pipeline_table_entry **actions, 120 __attribute__((unused)) uint32_t action_mask) 121 { 122 printf("Table Action, setting pkts_mask to 0x00\n"); 123 *pkts_mask = 0x00; 124 return 0; 125 } 126 127 rte_pipeline_table_action_handler_hit 128 table_action_stub_hit(__attribute__((unused)) struct rte_mbuf **pkts, 129 uint64_t *pkts_mask, 130 __attribute__((unused)) struct rte_pipeline_table_entry **actions, 131 __attribute__((unused)) uint32_t action_mask) 132 { 133 printf("STUB Table Action Hit - doing nothing\n"); 134 printf("STUB Table Action Hit - setting mask to 0x%"PRIx64"\n", 135 override_hit_mask); 136 *pkts_mask = override_hit_mask; 137 return 0; 138 } 139 rte_pipeline_table_action_handler_miss 140 table_action_stub_miss(__attribute__((unused)) struct rte_mbuf **pkts, 141 uint64_t *pkts_mask, 142 __attribute__((unused)) struct rte_pipeline_table_entry *action, 143 __attribute__((unused)) uint32_t action_mask) 144 { 145 printf("STUB Table Action Miss - setting mask to 0x%"PRIx64"\n", 146 override_miss_mask); 147 *pkts_mask = override_miss_mask; 148 return 0; 149 } 150 151 152 enum e_test_type { 153 e_TEST_STUB = 0, 154 e_TEST_LPM, 155 e_TEST_LPM6, 156 e_TEST_HASH_LRU_8, 157 e_TEST_HASH_LRU_16, 158 e_TEST_HASH_LRU_32, 159 e_TEST_HASH_EXT_8, 160 e_TEST_HASH_EXT_16, 161 e_TEST_HASH_EXT_32 162 }; 163 164 char pipeline_test_names[][64] = { 165 "Stub", 166 "LPM", 167 "LPMv6", 168 "8-bit LRU Hash", 169 "16-bit LRU Hash", 170 "32-bit LRU Hash", 171 "16-bit Ext Hash", 172 "8-bit Ext Hash", 173 "32-bit Ext Hash", 174 "" 175 }; 176 177 178 static int 179 cleanup_pipeline(void) 180 { 181 182 rte_pipeline_free(p); 183 184 return 0; 185 } 186 187 188 static int check_pipeline_invalid_params(void); 189 190 static int 191 check_pipeline_invalid_params(void) 192 { 193 struct rte_pipeline_params pipeline_params_1 = { 194 .name = NULL, 195 .socket_id = 0, 196 }; 197 struct rte_pipeline_params pipeline_params_2 = { 198 .name = "PIPELINE", 199 .socket_id = -1, 200 }; 201 struct rte_pipeline_params pipeline_params_3 = { 202 .name = "PIPELINE", 203 .socket_id = 127, 204 }; 205 206 p = rte_pipeline_create(NULL); 207 if (p != NULL) { 208 RTE_LOG(INFO, PIPELINE, 209 "%s: configured pipeline with null params\n", 210 __func__); 211 goto fail; 212 } 213 p = rte_pipeline_create(&pipeline_params_1); 214 if (p != NULL) { 215 RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with NULL " 216 "name\n", __func__); 217 goto fail; 218 } 219 220 p = rte_pipeline_create(&pipeline_params_2); 221 if (p != NULL) { 222 RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid " 223 "socket\n", __func__); 224 goto fail; 225 } 226 227 p = rte_pipeline_create(&pipeline_params_3); 228 if (p != NULL) { 229 RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid " 230 "socket\n", __func__); 231 goto fail; 232 } 233 234 /* Check pipeline consistency */ 235 if (!rte_pipeline_check(p)) { 236 rte_panic("Pipeline consistency reported as OK\n"); 237 goto fail; 238 } 239 240 241 return 0; 242 fail: 243 return -1; 244 } 245 246 247 static int 248 setup_pipeline(int test_type) 249 { 250 int ret; 251 int i; 252 struct rte_pipeline_params pipeline_params = { 253 .name = "PIPELINE", 254 .socket_id = 0, 255 }; 256 257 RTE_LOG(INFO, PIPELINE, "%s: **** Setting up %s test\n", 258 __func__, pipeline_test_names[test_type]); 259 260 /* Pipeline configuration */ 261 p = rte_pipeline_create(&pipeline_params); 262 if (p == NULL) { 263 RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", 264 __func__); 265 goto fail; 266 } 267 268 ret = rte_pipeline_free(p); 269 if (ret != 0) { 270 RTE_LOG(INFO, PIPELINE, "%s: Failed to free pipeline\n", 271 __func__); 272 goto fail; 273 } 274 275 /* Pipeline configuration */ 276 p = rte_pipeline_create(&pipeline_params); 277 if (p == NULL) { 278 RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", 279 __func__); 280 goto fail; 281 } 282 283 284 /* Input port configuration */ 285 for (i = 0; i < N_PORTS; i++) { 286 struct rte_port_ring_reader_params port_ring_params = { 287 .ring = rings_rx[i], 288 }; 289 290 struct rte_pipeline_port_in_params port_params = { 291 .ops = &rte_port_ring_reader_ops, 292 .arg_create = (void *) &port_ring_params, 293 .f_action = NULL, 294 .burst_size = BURST_SIZE, 295 }; 296 297 /* Put in action for some ports */ 298 if (i) 299 port_params.f_action = NULL; 300 301 ret = rte_pipeline_port_in_create(p, &port_params, 302 &port_in_id[i]); 303 if (ret) { 304 rte_panic("Unable to configure input port %d, ret:%d\n", 305 i, ret); 306 goto fail; 307 } 308 } 309 310 /* output Port configuration */ 311 for (i = 0; i < N_PORTS; i++) { 312 struct rte_port_ring_writer_params port_ring_params = { 313 .ring = rings_tx[i], 314 .tx_burst_sz = BURST_SIZE, 315 }; 316 317 struct rte_pipeline_port_out_params port_params = { 318 .ops = &rte_port_ring_writer_ops, 319 .arg_create = (void *) &port_ring_params, 320 .f_action = NULL, 321 .arg_ah = NULL, 322 }; 323 324 if (i) 325 port_params.f_action = port_out_action; 326 327 if (rte_pipeline_port_out_create(p, &port_params, 328 &port_out_id[i])) { 329 rte_panic("Unable to configure output port %d\n", i); 330 goto fail; 331 } 332 } 333 334 /* Table configuration */ 335 for (i = 0; i < N_PORTS; i++) { 336 struct rte_pipeline_table_params table_params = { 337 .ops = &rte_table_stub_ops, 338 .arg_create = NULL, 339 .f_action_hit = action_handler_hit, 340 .f_action_miss = action_handler_miss, 341 .action_data_size = 0, 342 }; 343 344 if (rte_pipeline_table_create(p, &table_params, &table_id[i])) { 345 rte_panic("Unable to configure table %u\n", i); 346 goto fail; 347 } 348 349 if (connect_miss_action_to_table) 350 if (rte_pipeline_table_create(p, &table_params, 351 &table_id[i+2])) { 352 rte_panic("Unable to configure table %u\n", i); 353 goto fail; 354 } 355 } 356 357 for (i = 0; i < N_PORTS; i++) 358 if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], 359 table_id[i])) { 360 rte_panic("Unable to connect input port %u to " 361 "table %u\n", port_in_id[i], table_id[i]); 362 goto fail; 363 } 364 365 /* Add entries to tables */ 366 for (i = 0; i < N_PORTS; i++) { 367 struct rte_pipeline_table_entry default_entry = { 368 .action = (enum rte_pipeline_action) 369 table_entry_default_action, 370 {.port_id = port_out_id[i^1]}, 371 }; 372 struct rte_pipeline_table_entry *default_entry_ptr; 373 374 if (connect_miss_action_to_table) { 375 printf("Setting first table to output to next table\n"); 376 default_entry.action = RTE_PIPELINE_ACTION_TABLE; 377 default_entry.table_id = table_id[i+2]; 378 } 379 380 /* Add the default action for the table. */ 381 ret = rte_pipeline_table_default_entry_add(p, table_id[i], 382 &default_entry, &default_entry_ptr); 383 if (ret < 0) { 384 rte_panic("Unable to add default entry to table %u " 385 "code %d\n", table_id[i], ret); 386 goto fail; 387 } else 388 printf("Added default entry to table id %d with " 389 "action %x\n", 390 table_id[i], default_entry.action); 391 392 if (connect_miss_action_to_table) { 393 /* We create a second table so the first can pass 394 traffic into it */ 395 struct rte_pipeline_table_entry default_entry = { 396 .action = RTE_PIPELINE_ACTION_PORT, 397 {.port_id = port_out_id[i^1]}, 398 }; 399 printf("Setting secont table to output to port\n"); 400 401 /* Add the default action for the table. */ 402 ret = rte_pipeline_table_default_entry_add(p, 403 table_id[i+2], 404 &default_entry, &default_entry_ptr); 405 if (ret < 0) { 406 rte_panic("Unable to add default entry to " 407 "table %u code %d\n", 408 table_id[i], ret); 409 goto fail; 410 } else 411 printf("Added default entry to table id %d " 412 "with action %x\n", 413 table_id[i], default_entry.action); 414 } 415 } 416 417 /* Enable input ports */ 418 for (i = 0; i < N_PORTS ; i++) 419 if (rte_pipeline_port_in_enable(p, port_in_id[i])) 420 rte_panic("Unable to enable input port %u\n", 421 port_in_id[i]); 422 423 /* Check pipeline consistency */ 424 if (rte_pipeline_check(p) < 0) { 425 rte_panic("Pipeline consistency check failed\n"); 426 goto fail; 427 } else 428 printf("Pipeline Consistency OK!\n"); 429 430 return 0; 431 fail: 432 433 return -1; 434 } 435 436 static int 437 test_pipeline_single_filter(int test_type, int expected_count) 438 { 439 int i; 440 int j; 441 int ret; 442 int tx_count; 443 444 RTE_LOG(INFO, PIPELINE, "%s: **** Running %s test\n", 445 __func__, pipeline_test_names[test_type]); 446 /* Run pipeline once */ 447 rte_pipeline_run(p); 448 449 450 ret = rte_pipeline_flush(NULL); 451 if (ret != -EINVAL) { 452 RTE_LOG(INFO, PIPELINE, 453 "%s: No pipeline flush error NULL pipeline (%d)\n", 454 __func__, ret); 455 goto fail; 456 } 457 458 /* 459 * Allocate a few mbufs and manually insert into the rings. */ 460 for (i = 0; i < N_PORTS; i++) 461 for (j = 0; j < N_PORTS; j++) { 462 struct rte_mbuf *m; 463 uint8_t *key; 464 uint32_t *k32; 465 466 m = rte_pktmbuf_alloc(pool); 467 if (m == NULL) { 468 rte_panic("Failed to alloc mbuf from pool\n"); 469 return -1; 470 } 471 key = RTE_MBUF_METADATA_UINT8_PTR(m, 32); 472 473 k32 = (uint32_t *) key; 474 k32[0] = 0xadadadad >> (j % 2); 475 476 RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n", 477 __func__, i); 478 rte_ring_enqueue(rings_rx[i], m); 479 } 480 481 /* Run pipeline once */ 482 rte_pipeline_run(p); 483 484 /* 485 * need to flush the pipeline, as there may be less hits than the burst 486 size and they will not have been flushed to the tx rings. */ 487 rte_pipeline_flush(p); 488 489 /* 490 * Now we'll see what we got back on the tx rings. We should see whatever 491 * packets we had hits on that were destined for the output ports. 492 */ 493 tx_count = 0; 494 495 for (i = 0; i < N_PORTS; i++) { 496 void *objs[RING_TX_SIZE]; 497 struct rte_mbuf *mbuf; 498 499 ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10); 500 if (ret <= 0) 501 printf("Got no objects from ring %d - error code %d\n", 502 i, ret); 503 else { 504 printf("Got %d object(s) from ring %d!\n", ret, i); 505 for (j = 0; j < ret; j++) { 506 mbuf = (struct rte_mbuf *)objs[j]; 507 rte_hexdump(stdout, "Object:", mbuf->pkt.data, 508 mbuf->pkt.data_len); 509 rte_pktmbuf_free(mbuf); 510 } 511 tx_count += ret; 512 } 513 } 514 515 if (tx_count != expected_count) { 516 RTE_LOG(INFO, PIPELINE, 517 "%s: Unexpected packets out for %s test, expected %d, " 518 "got %d\n", __func__, pipeline_test_names[test_type], 519 expected_count, tx_count); 520 goto fail; 521 } 522 523 cleanup_pipeline(); 524 525 return 0; 526 fail: 527 return -1; 528 529 } 530 531 int 532 test_table_pipeline(void) 533 { 534 /* TEST - All packets dropped */ 535 action_handler_hit = NULL; 536 action_handler_miss = NULL; 537 table_entry_default_action = RTE_PIPELINE_ACTION_DROP; 538 setup_pipeline(e_TEST_STUB); 539 if (test_pipeline_single_filter(e_TEST_STUB, 0) < 0) 540 return -1; 541 542 /* TEST - All packets passed through */ 543 table_entry_default_action = RTE_PIPELINE_ACTION_PORT; 544 setup_pipeline(e_TEST_STUB); 545 if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) 546 return -1; 547 548 /* TEST - one packet per port */ 549 action_handler_hit = NULL; 550 action_handler_miss = 551 (rte_pipeline_table_action_handler_miss) table_action_stub_miss; 552 table_entry_default_action = RTE_PIPELINE_ACTION_PORT; 553 override_miss_mask = 0x01; /* one packet per port */ 554 setup_pipeline(e_TEST_STUB); 555 if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) 556 return -1; 557 558 /* TEST - one packet per port */ 559 override_miss_mask = 0x02; /*all per port */ 560 setup_pipeline(e_TEST_STUB); 561 if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) 562 return -1; 563 564 /* TEST - all packets per port */ 565 override_miss_mask = 0x03; /*all per port */ 566 setup_pipeline(e_TEST_STUB); 567 if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) 568 return -1; 569 570 /* 571 * This test will set up two tables in the pipeline. the first table 572 * will forward to another table on miss, and the second table will 573 * forward to port. 574 */ 575 connect_miss_action_to_table = 1; 576 table_entry_default_action = RTE_PIPELINE_ACTION_TABLE; 577 action_handler_hit = NULL; /* not for stub, hitmask always zero */ 578 action_handler_miss = NULL; 579 setup_pipeline(e_TEST_STUB); 580 if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) 581 return -1; 582 connect_miss_action_to_table = 0; 583 584 printf("TEST - two tables, hitmask override to 0x01\n"); 585 connect_miss_action_to_table = 1; 586 action_handler_miss = 587 (rte_pipeline_table_action_handler_miss)table_action_stub_miss; 588 override_miss_mask = 0x01; 589 setup_pipeline(e_TEST_STUB); 590 if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) 591 return -1; 592 connect_miss_action_to_table = 0; 593 594 if (check_pipeline_invalid_params()) { 595 RTE_LOG(INFO, PIPELINE, "%s: Check pipeline invalid params " 596 "failed.\n", __func__); 597 return -1; 598 } 599 600 return 0; 601 } 602 603 #endif 604