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