1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include "test.h" 6 7 #include <stdio.h> 8 #include <unistd.h> 9 #include <string.h> 10 11 #include <rte_cycles.h> 12 #include <rte_errno.h> 13 #include <rte_mbuf.h> 14 15 #ifdef RTE_EXEC_ENV_WINDOWS 16 static int 17 test_reorder(void) 18 { 19 printf("reorder not supported on Windows, skipping test\n"); 20 return TEST_SKIPPED; 21 } 22 #else 23 24 #include <rte_reorder.h> 25 #include <rte_lcore.h> 26 #include <rte_malloc.h> 27 28 #define BURST 32 29 #define REORDER_BUFFER_SIZE 16384 30 #define NUM_MBUFS (2*REORDER_BUFFER_SIZE) 31 #define REORDER_BUFFER_SIZE_INVALID 2049 32 33 struct reorder_unittest_params { 34 struct rte_mempool *p; 35 struct rte_reorder_buffer *b; 36 }; 37 38 static struct reorder_unittest_params default_params = { 39 .p = NULL, 40 .b = NULL 41 }; 42 43 static struct reorder_unittest_params *test_params = &default_params; 44 45 static int 46 test_reorder_create(void) 47 { 48 struct rte_reorder_buffer *b = NULL; 49 50 b = rte_reorder_create(NULL, rte_socket_id(), REORDER_BUFFER_SIZE); 51 TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), 52 "No error on create() with NULL name"); 53 54 b = rte_reorder_create("PKT", rte_socket_id(), REORDER_BUFFER_SIZE_INVALID); 55 TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), 56 "No error on create() with invalid buffer size param."); 57 58 b = rte_reorder_create("PKT_RO1", rte_socket_id(), REORDER_BUFFER_SIZE); 59 TEST_ASSERT_EQUAL(b, test_params->b, 60 "New reorder instance created with already existing name"); 61 62 return 0; 63 } 64 65 static int 66 test_reorder_init(void) 67 { 68 struct rte_reorder_buffer *b = NULL; 69 unsigned int size; 70 /* 71 * The minimum memory area size that should be passed to library is, 72 * sizeof(struct rte_reorder_buffer) + (2 * size * sizeof(struct rte_mbuf *)); 73 * Otherwise error will be thrown 74 */ 75 76 size = 100; 77 b = rte_reorder_init(b, size, "PKT1", REORDER_BUFFER_SIZE); 78 TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), 79 "No error on init with NULL buffer."); 80 81 b = rte_malloc(NULL, size, 0); 82 b = rte_reorder_init(b, size, "PKT1", REORDER_BUFFER_SIZE); 83 TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), 84 "No error on init with invalid mem zone size."); 85 rte_free(b); 86 87 size = 262336; 88 b = rte_malloc(NULL, size, 0); 89 b = rte_reorder_init(b, size, "PKT1", REORDER_BUFFER_SIZE_INVALID); 90 TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), 91 "No error on init with invalid buffer size param."); 92 93 b = rte_reorder_init(b, size, NULL, REORDER_BUFFER_SIZE); 94 TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), 95 "No error on init with invalid name."); 96 rte_free(b); 97 98 return 0; 99 } 100 101 static int 102 test_reorder_find_existing(void) 103 { 104 struct rte_reorder_buffer *b = NULL; 105 106 /* Try to find existing reorder buffer instance */ 107 b = rte_reorder_find_existing("PKT_RO1"); 108 TEST_ASSERT_EQUAL(b, test_params->b, 109 "existing reorder buffer instance not found"); 110 111 /* Try to find non existing reorder buffer instance */ 112 b = rte_reorder_find_existing("ro_find_non_existing"); 113 TEST_ASSERT((b == NULL) && (rte_errno == ENOENT), 114 "non existing reorder buffer instance found"); 115 116 return 0; 117 } 118 119 static int 120 test_reorder_free(void) 121 { 122 struct rte_reorder_buffer *b1 = NULL, *b2 = NULL; 123 const char *name = "test_free"; 124 125 b1 = rte_reorder_create(name, rte_socket_id(), 8); 126 TEST_ASSERT_NOT_NULL(b1, "Failed to create reorder buffer."); 127 128 b2 = rte_reorder_find_existing(name); 129 TEST_ASSERT_EQUAL(b1, b2, "Failed to find existing reorder buffer"); 130 131 rte_reorder_free(b1); 132 133 b2 = rte_reorder_find_existing(name); 134 TEST_ASSERT((b2 == NULL) && (rte_errno == ENOENT), 135 "Found previously freed reorder buffer"); 136 137 return 0; 138 } 139 140 static int 141 test_reorder_insert(void) 142 { 143 struct rte_reorder_buffer *b = NULL; 144 struct rte_mempool *p = test_params->p; 145 const unsigned int size = 4; 146 const unsigned int num_bufs = 7; 147 struct rte_mbuf *bufs[num_bufs]; 148 int ret = 0; 149 unsigned i; 150 151 /* This would create a reorder buffer instance consisting of: 152 * reorder_seq = 0 153 * ready_buf: RB[size] = {NULL, NULL, NULL, NULL} 154 * order_buf: OB[size] = {NULL, NULL, NULL, NULL} 155 */ 156 b = rte_reorder_create("test_insert", rte_socket_id(), size); 157 TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer"); 158 159 for (i = 0; i < num_bufs; i++) { 160 bufs[i] = rte_pktmbuf_alloc(p); 161 TEST_ASSERT_NOT_NULL(bufs[i], "Packet allocation failed\n"); 162 *rte_reorder_seqn(bufs[i]) = i; 163 } 164 165 /* This should fill up order buffer: 166 * reorder_seq = 0 167 * RB[] = {NULL, NULL, NULL, NULL} 168 * OB[] = {0, 1, 2, 3} 169 */ 170 for (i = 0; i < size; i++) { 171 ret = rte_reorder_insert(b, bufs[i]); 172 if (ret != 0) { 173 printf("%s:%d: Error inserting packet with seqn less than size\n", 174 __func__, __LINE__); 175 ret = -1; 176 goto exit; 177 } 178 bufs[i] = NULL; 179 } 180 181 /* early packet - should move mbufs to ready buf and move sequence window 182 * reorder_seq = 4 183 * RB[] = {0, 1, 2, 3} 184 * OB[] = {4, NULL, NULL, NULL} 185 */ 186 ret = rte_reorder_insert(b, bufs[4]); 187 if (ret != 0) { 188 printf("%s:%d: Error inserting early packet with seqn: size\n", 189 __func__, __LINE__); 190 ret = -1; 191 goto exit; 192 } 193 bufs[4] = NULL; 194 195 /* early packet from current sequence window - full ready buffer */ 196 *rte_reorder_seqn(bufs[5]) = 2 * size; 197 ret = rte_reorder_insert(b, bufs[5]); 198 if (!((ret == -1) && (rte_errno == ENOSPC))) { 199 printf("%s:%d: No error inserting early packet with full ready buffer\n", 200 __func__, __LINE__); 201 ret = -1; 202 goto exit; 203 } 204 bufs[5] = NULL; 205 206 /* late packet */ 207 *rte_reorder_seqn(bufs[6]) = 3 * size; 208 ret = rte_reorder_insert(b, bufs[6]); 209 if (!((ret == -1) && (rte_errno == ERANGE))) { 210 printf("%s:%d: No error inserting late packet with seqn:" 211 " 3 * size\n", __func__, __LINE__); 212 ret = -1; 213 goto exit; 214 } 215 bufs[6] = NULL; 216 217 ret = 0; 218 exit: 219 rte_reorder_free(b); 220 for (i = 0; i < num_bufs; i++) { 221 rte_pktmbuf_free(bufs[i]); 222 } 223 return ret; 224 } 225 226 static int 227 test_reorder_drain(void) 228 { 229 struct rte_reorder_buffer *b = NULL; 230 struct rte_mempool *p = test_params->p; 231 const unsigned int size = 4; 232 const unsigned int num_bufs = 8; 233 struct rte_mbuf *bufs[num_bufs]; 234 struct rte_mbuf *robufs[num_bufs]; 235 int ret = 0; 236 unsigned i, cnt; 237 238 /* initialize all robufs to NULL */ 239 for (i = 0; i < num_bufs; i++) 240 robufs[i] = NULL; 241 242 /* This would create a reorder buffer instance consisting of: 243 * reorder_seq = 0 244 * ready_buf: RB[size] = {NULL, NULL, NULL, NULL} 245 * order_buf: OB[size] = {NULL, NULL, NULL, NULL} 246 */ 247 b = rte_reorder_create("test_drain", rte_socket_id(), size); 248 TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer"); 249 250 /* Check no drained packets if reorder is empty */ 251 cnt = rte_reorder_drain(b, robufs, 1); 252 if (cnt != 0) { 253 printf("%s:%d: drained packets from empty reorder buffer\n", 254 __func__, __LINE__); 255 ret = -1; 256 goto exit; 257 } 258 259 for (i = 0; i < num_bufs; i++) { 260 bufs[i] = rte_pktmbuf_alloc(p); 261 TEST_ASSERT_NOT_NULL(bufs[i], "Packet allocation failed\n"); 262 *rte_reorder_seqn(bufs[i]) = i; 263 } 264 265 /* Insert packet with seqn 1: 266 * reorder_seq = 0 267 * RB[] = {NULL, NULL, NULL, NULL} 268 * OB[] = {1, NULL, NULL, NULL} 269 */ 270 rte_reorder_insert(b, bufs[1]); 271 bufs[1] = NULL; 272 273 cnt = rte_reorder_drain(b, robufs, 1); 274 if (cnt != 1) { 275 printf("%s:%d:%d: number of expected packets not drained\n", 276 __func__, __LINE__, cnt); 277 ret = -1; 278 goto exit; 279 } 280 rte_pktmbuf_free(robufs[0]); 281 memset(robufs, 0, sizeof(robufs)); 282 283 /* Insert more packets 284 * RB[] = {NULL, NULL, NULL, NULL} 285 * OB[] = {NULL, 2, 3, NULL} 286 */ 287 rte_reorder_insert(b, bufs[2]); 288 rte_reorder_insert(b, bufs[3]); 289 bufs[2] = NULL; 290 bufs[3] = NULL; 291 292 /* Insert more packets 293 * RB[] = {NULL, NULL, NULL, NULL} 294 * OB[] = {NULL, 2, 3, 4} 295 */ 296 rte_reorder_insert(b, bufs[4]); 297 bufs[4] = NULL; 298 299 /* Insert more packets 300 * RB[] = {2, 3, 4, NULL} 301 * OB[] = {NULL, NULL, 7, NULL} 302 */ 303 rte_reorder_insert(b, bufs[7]); 304 bufs[7] = NULL; 305 306 /* drained expected packets */ 307 cnt = rte_reorder_drain(b, robufs, 4); 308 if (cnt != 3) { 309 printf("%s:%d:%d: number of expected packets not drained\n", 310 __func__, __LINE__, cnt); 311 ret = -1; 312 goto exit; 313 } 314 for (i = 0; i < 3; i++) { 315 rte_pktmbuf_free(robufs[i]); 316 } 317 memset(robufs, 0, sizeof(robufs)); 318 319 /* 320 * RB[] = {NULL, NULL, NULL, NULL} 321 * OB[] = {NULL, NULL, 7, NULL} 322 */ 323 cnt = rte_reorder_drain(b, robufs, 1); 324 if (cnt != 0) { 325 printf("%s:%d:%d: number of expected packets not drained\n", 326 __func__, __LINE__, cnt); 327 ret = -1; 328 goto exit; 329 } 330 ret = 0; 331 exit: 332 rte_reorder_free(b); 333 for (i = 0; i < num_bufs; i++) { 334 rte_pktmbuf_free(bufs[i]); 335 rte_pktmbuf_free(robufs[i]); 336 } 337 return ret; 338 } 339 340 static void 341 buffer_to_reorder_move(struct rte_mbuf **mbuf, struct rte_reorder_buffer *b) 342 { 343 rte_reorder_insert(b, *mbuf); 344 *mbuf = NULL; 345 } 346 347 static int 348 test_reorder_drain_up_to_seqn(void) 349 { 350 struct rte_mempool *p = test_params->p; 351 struct rte_reorder_buffer *b = NULL; 352 const unsigned int num_bufs = 10; 353 const unsigned int size = 4; 354 unsigned int i, cnt; 355 int ret = 0; 356 357 struct rte_mbuf *bufs[num_bufs]; 358 struct rte_mbuf *robufs[num_bufs]; 359 360 /* initialize all robufs to NULL */ 361 memset(robufs, 0, sizeof(robufs)); 362 363 /* This would create a reorder buffer instance consisting of: 364 * reorder_seq = 0 365 * ready_buf: RB[size] = {NULL, NULL, NULL, NULL} 366 * order_buf: OB[size] = {NULL, NULL, NULL, NULL} 367 */ 368 b = rte_reorder_create("test_drain_up_to_seqn", rte_socket_id(), size); 369 TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer"); 370 371 for (i = 0; i < num_bufs; i++) { 372 bufs[i] = rte_pktmbuf_alloc(p); 373 TEST_ASSERT_NOT_NULL(bufs[i], "Packet allocation failed\n"); 374 *rte_reorder_seqn(bufs[i]) = i; 375 } 376 377 /* Insert packet with seqn 1 and 3: 378 * RB[] = {NULL, NULL, NULL, NULL} 379 * OB[] = {1, 2, 3, NULL} 380 */ 381 buffer_to_reorder_move(&bufs[1], b); 382 buffer_to_reorder_move(&bufs[2], b); 383 buffer_to_reorder_move(&bufs[3], b); 384 /* Draining 1, 2 */ 385 cnt = rte_reorder_drain_up_to_seqn(b, robufs, num_bufs, 3); 386 if (cnt != 2) { 387 printf("%s:%d:%d: number of expected packets not drained\n", 388 __func__, __LINE__, cnt); 389 ret = -1; 390 goto exit; 391 } 392 for (i = 0; i < 2; i++) 393 rte_pktmbuf_free(robufs[i]); 394 memset(robufs, 0, sizeof(robufs)); 395 396 /* Insert more packets 397 * RB[] = {NULL, NULL, NULL, NULL} 398 * OB[] = {3, 4, NULL, 6} 399 */ 400 buffer_to_reorder_move(&bufs[4], b); 401 buffer_to_reorder_move(&bufs[6], b); 402 /* Insert more packets to utilize Ready buffer 403 * RB[] = {3, NULL, 5, 6} 404 * OB[] = {NULL, NULL, 8, NULL} 405 */ 406 buffer_to_reorder_move(&bufs[8], b); 407 408 /* Drain 3 and 5 */ 409 cnt = rte_reorder_drain_up_to_seqn(b, robufs, num_bufs, 6); 410 if (cnt != 2) { 411 printf("%s:%d:%d: number of expected packets not drained\n", 412 __func__, __LINE__, cnt); 413 ret = -1; 414 goto exit; 415 } 416 for (i = 0; i < 2; i++) 417 rte_pktmbuf_free(robufs[i]); 418 memset(robufs, 0, sizeof(robufs)); 419 420 ret = 0; 421 exit: 422 rte_reorder_free(b); 423 for (i = 0; i < num_bufs; i++) { 424 rte_pktmbuf_free(bufs[i]); 425 rte_pktmbuf_free(robufs[i]); 426 } 427 return ret; 428 } 429 430 static int 431 test_reorder_set_seqn(void) 432 { 433 struct rte_mempool *p = test_params->p; 434 struct rte_reorder_buffer *b = NULL; 435 const unsigned int num_bufs = 7; 436 const unsigned int size = 4; 437 unsigned int i; 438 int ret = 0; 439 440 struct rte_mbuf *bufs[num_bufs]; 441 442 /* This would create a reorder buffer instance consisting of: 443 * reorder_seq = 0 444 * ready_buf: RB[size] = {NULL, NULL, NULL, NULL} 445 * order_buf: OB[size] = {NULL, NULL, NULL, NULL} 446 */ 447 b = rte_reorder_create("test_min_seqn_set", rte_socket_id(), size); 448 TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer"); 449 450 for (i = 0; i < num_bufs; i++) { 451 bufs[i] = rte_pktmbuf_alloc(p); 452 if (bufs[i] == NULL) { 453 printf("Packet allocation failed\n"); 454 goto exit; 455 } 456 *rte_reorder_seqn(bufs[i]) = i; 457 } 458 459 ret = rte_reorder_min_seqn_set(b, 5); 460 if (ret != 0) { 461 printf("%s:%d: Error in setting min sequence number\n", __func__, __LINE__); 462 ret = -1; 463 goto exit; 464 } 465 466 ret = rte_reorder_insert(b, bufs[0]); 467 if (ret >= 0) { 468 printf("%s:%d: Insertion with value less the min seq number\n", __func__, __LINE__); 469 ret = -1; 470 goto exit; 471 } 472 473 ret = rte_reorder_insert(b, bufs[5]); 474 if (ret != 0) { 475 printf("%s:%d: Error inserting packet with valid seqn\n", __func__, __LINE__); 476 ret = -1; 477 goto exit; 478 } 479 bufs[5] = NULL; 480 481 ret = rte_reorder_min_seqn_set(b, 0); 482 if (ret >= 0) { 483 printf("%s:%d: Error in setting min sequence number with non-empty buffer\n", 484 __func__, __LINE__); 485 ret = -1; 486 goto exit; 487 } 488 489 ret = 0; 490 exit: 491 rte_reorder_free(b); 492 for (i = 0; i < num_bufs; i++) 493 rte_pktmbuf_free(bufs[i]); 494 495 return ret; 496 } 497 498 static int 499 test_setup(void) 500 { 501 /* reorder buffer instance creation */ 502 if (test_params->b == NULL) { 503 test_params->b = rte_reorder_create("PKT_RO1", rte_socket_id(), 504 REORDER_BUFFER_SIZE); 505 if (test_params->b == NULL) { 506 printf("%s: Error creating reorder buffer instance b\n", 507 __func__); 508 return -1; 509 } 510 } else 511 rte_reorder_reset(test_params->b); 512 513 /* mempool creation */ 514 if (test_params->p == NULL) { 515 test_params->p = rte_pktmbuf_pool_create("RO_MBUF_POOL", 516 NUM_MBUFS, BURST, 0, RTE_MBUF_DEFAULT_BUF_SIZE, 517 rte_socket_id()); 518 if (test_params->p == NULL) { 519 printf("%s: Error creating mempool\n", __func__); 520 return -1; 521 } 522 } 523 return 0; 524 } 525 526 static void 527 test_teardown(void) 528 { 529 rte_reorder_free(test_params->b); 530 test_params->b = NULL; 531 rte_mempool_free(test_params->p); 532 test_params->p = NULL; 533 } 534 535 536 static struct unit_test_suite reorder_test_suite = { 537 538 .setup = test_setup, 539 .teardown = test_teardown, 540 .suite_name = "Reorder Unit Test Suite", 541 .unit_test_cases = { 542 TEST_CASE(test_reorder_create), 543 TEST_CASE(test_reorder_init), 544 TEST_CASE(test_reorder_find_existing), 545 TEST_CASE(test_reorder_free), 546 TEST_CASE(test_reorder_insert), 547 TEST_CASE(test_reorder_drain), 548 TEST_CASE(test_reorder_drain_up_to_seqn), 549 TEST_CASE(test_reorder_set_seqn), 550 TEST_CASES_END() 551 } 552 }; 553 554 static int 555 test_reorder(void) 556 { 557 return unit_test_suite_runner(&reorder_test_suite); 558 } 559 560 #endif /* !RTE_EXEC_ENV_WINDOWS */ 561 562 REGISTER_TEST_COMMAND(reorder_autotest, test_reorder); 563