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 #include <string.h> 35 #include <stdarg.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <stdint.h> 39 #include <inttypes.h> 40 #include <errno.h> 41 #include <sys/queue.h> 42 43 #include <rte_common.h> 44 #include <rte_debug.h> 45 #include <rte_log.h> 46 #include <rte_common.h> 47 #include <rte_memory.h> 48 #include <rte_memcpy.h> 49 #include <rte_memzone.h> 50 #include <rte_launch.h> 51 #include <rte_eal.h> 52 #include <rte_per_lcore.h> 53 #include <rte_lcore.h> 54 #include <rte_atomic.h> 55 #include <rte_branch_prediction.h> 56 #include <rte_ring.h> 57 #include <rte_mempool.h> 58 #include <rte_mbuf.h> 59 #include <rte_random.h> 60 #include <rte_cycles.h> 61 62 #include "test.h" 63 64 #define MBUF_DATA_SIZE 2048 65 #define NB_MBUF 128 66 #define MBUF_TEST_DATA_LEN 1464 67 #define MBUF_TEST_DATA_LEN2 50 68 #define MBUF_TEST_HDR1_LEN 20 69 #define MBUF_TEST_HDR2_LEN 30 70 #define MBUF_TEST_ALL_HDRS_LEN (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN) 71 72 /* size of private data for mbuf in pktmbuf_pool2 */ 73 #define MBUF2_PRIV_SIZE 128 74 75 #define REFCNT_MAX_ITER 64 76 #define REFCNT_MAX_TIMEOUT 10 77 #define REFCNT_MAX_REF (RTE_MAX_LCORE) 78 #define REFCNT_MBUF_NUM 64 79 #define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) 80 81 #define MAGIC_DATA 0x42424242 82 83 #define MAKE_STRING(x) # x 84 85 static struct rte_mempool *pktmbuf_pool = NULL; 86 static struct rte_mempool *pktmbuf_pool2 = NULL; 87 88 #ifdef RTE_MBUF_REFCNT_ATOMIC 89 90 static struct rte_mempool *refcnt_pool = NULL; 91 static struct rte_ring *refcnt_mbuf_ring = NULL; 92 static volatile uint32_t refcnt_stop_slaves; 93 static unsigned refcnt_lcore[RTE_MAX_LCORE]; 94 95 #endif 96 97 /* 98 * MBUF 99 * ==== 100 * 101 * #. Allocate a mbuf pool. 102 * 103 * - The pool contains NB_MBUF elements, where each mbuf is MBUF_SIZE 104 * bytes long. 105 * 106 * #. Test multiple allocations of mbufs from this pool. 107 * 108 * - Allocate NB_MBUF and store pointers in a table. 109 * - If an allocation fails, return an error. 110 * - Free all these mbufs. 111 * - Repeat the same test to check that mbufs were freed correctly. 112 * 113 * #. Test data manipulation in pktmbuf. 114 * 115 * - Alloc an mbuf. 116 * - Append data using rte_pktmbuf_append(). 117 * - Test for error in rte_pktmbuf_append() when len is too large. 118 * - Trim data at the end of mbuf using rte_pktmbuf_trim(). 119 * - Test for error in rte_pktmbuf_trim() when len is too large. 120 * - Prepend a header using rte_pktmbuf_prepend(). 121 * - Test for error in rte_pktmbuf_prepend() when len is too large. 122 * - Remove data at the beginning of mbuf using rte_pktmbuf_adj(). 123 * - Test for error in rte_pktmbuf_adj() when len is too large. 124 * - Check that appended data is not corrupt. 125 * - Free the mbuf. 126 * - Between all these tests, check data_len and pkt_len, and 127 * that the mbuf is contiguous. 128 * - Repeat the test to check that allocation operations 129 * reinitialize the mbuf correctly. 130 * 131 * #. Test packet cloning 132 * - Clone a mbuf and verify the data 133 * - Clone the cloned mbuf and verify the data 134 * - Attach a mbuf to another that does not have the same priv_size. 135 */ 136 137 #define GOTO_FAIL(str, ...) do { \ 138 printf("mbuf test FAILED (l.%d): <" str ">\n", \ 139 __LINE__, ##__VA_ARGS__); \ 140 goto fail; \ 141 } while(0) 142 143 /* 144 * test data manipulation in mbuf with non-ascii data 145 */ 146 static int 147 test_pktmbuf_with_non_ascii_data(void) 148 { 149 struct rte_mbuf *m = NULL; 150 char *data; 151 152 m = rte_pktmbuf_alloc(pktmbuf_pool); 153 if (m == NULL) 154 GOTO_FAIL("Cannot allocate mbuf"); 155 if (rte_pktmbuf_pkt_len(m) != 0) 156 GOTO_FAIL("Bad length"); 157 158 data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN); 159 if (data == NULL) 160 GOTO_FAIL("Cannot append data"); 161 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) 162 GOTO_FAIL("Bad pkt length"); 163 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) 164 GOTO_FAIL("Bad data length"); 165 memset(data, 0xff, rte_pktmbuf_pkt_len(m)); 166 if (!rte_pktmbuf_is_contiguous(m)) 167 GOTO_FAIL("Buffer should be continuous"); 168 rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN); 169 170 rte_pktmbuf_free(m); 171 172 return 0; 173 174 fail: 175 if(m) { 176 rte_pktmbuf_free(m); 177 } 178 return -1; 179 } 180 181 /* 182 * test data manipulation in mbuf 183 */ 184 static int 185 test_one_pktmbuf(void) 186 { 187 struct rte_mbuf *m = NULL; 188 char *data, *data2, *hdr; 189 unsigned i; 190 191 printf("Test pktmbuf API\n"); 192 193 /* alloc a mbuf */ 194 195 m = rte_pktmbuf_alloc(pktmbuf_pool); 196 if (m == NULL) 197 GOTO_FAIL("Cannot allocate mbuf"); 198 if (rte_pktmbuf_pkt_len(m) != 0) 199 GOTO_FAIL("Bad length"); 200 201 rte_pktmbuf_dump(stdout, m, 0); 202 203 /* append data */ 204 205 data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN); 206 if (data == NULL) 207 GOTO_FAIL("Cannot append data"); 208 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) 209 GOTO_FAIL("Bad pkt length"); 210 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) 211 GOTO_FAIL("Bad data length"); 212 memset(data, 0x66, rte_pktmbuf_pkt_len(m)); 213 if (!rte_pktmbuf_is_contiguous(m)) 214 GOTO_FAIL("Buffer should be continuous"); 215 rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN); 216 rte_pktmbuf_dump(stdout, m, 2*MBUF_TEST_DATA_LEN); 217 218 /* this append should fail */ 219 220 data2 = rte_pktmbuf_append(m, (uint16_t)(rte_pktmbuf_tailroom(m) + 1)); 221 if (data2 != NULL) 222 GOTO_FAIL("Append should not succeed"); 223 224 /* append some more data */ 225 226 data2 = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2); 227 if (data2 == NULL) 228 GOTO_FAIL("Cannot append data"); 229 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2) 230 GOTO_FAIL("Bad pkt length"); 231 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2) 232 GOTO_FAIL("Bad data length"); 233 if (!rte_pktmbuf_is_contiguous(m)) 234 GOTO_FAIL("Buffer should be continuous"); 235 236 /* trim data at the end of mbuf */ 237 238 if (rte_pktmbuf_trim(m, MBUF_TEST_DATA_LEN2) < 0) 239 GOTO_FAIL("Cannot trim data"); 240 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) 241 GOTO_FAIL("Bad pkt length"); 242 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) 243 GOTO_FAIL("Bad data length"); 244 if (!rte_pktmbuf_is_contiguous(m)) 245 GOTO_FAIL("Buffer should be continuous"); 246 247 /* this trim should fail */ 248 249 if (rte_pktmbuf_trim(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) == 0) 250 GOTO_FAIL("trim should not succeed"); 251 252 /* prepend one header */ 253 254 hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR1_LEN); 255 if (hdr == NULL) 256 GOTO_FAIL("Cannot prepend"); 257 if (data - hdr != MBUF_TEST_HDR1_LEN) 258 GOTO_FAIL("Prepend failed"); 259 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN) 260 GOTO_FAIL("Bad pkt length"); 261 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN) 262 GOTO_FAIL("Bad data length"); 263 if (!rte_pktmbuf_is_contiguous(m)) 264 GOTO_FAIL("Buffer should be continuous"); 265 memset(hdr, 0x55, MBUF_TEST_HDR1_LEN); 266 267 /* prepend another header */ 268 269 hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR2_LEN); 270 if (hdr == NULL) 271 GOTO_FAIL("Cannot prepend"); 272 if (data - hdr != MBUF_TEST_ALL_HDRS_LEN) 273 GOTO_FAIL("Prepend failed"); 274 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN) 275 GOTO_FAIL("Bad pkt length"); 276 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN) 277 GOTO_FAIL("Bad data length"); 278 if (!rte_pktmbuf_is_contiguous(m)) 279 GOTO_FAIL("Buffer should be continuous"); 280 memset(hdr, 0x55, MBUF_TEST_HDR2_LEN); 281 282 rte_mbuf_sanity_check(m, 1); 283 rte_mbuf_sanity_check(m, 0); 284 rte_pktmbuf_dump(stdout, m, 0); 285 286 /* this prepend should fail */ 287 288 hdr = rte_pktmbuf_prepend(m, (uint16_t)(rte_pktmbuf_headroom(m) + 1)); 289 if (hdr != NULL) 290 GOTO_FAIL("prepend should not succeed"); 291 292 /* remove data at beginning of mbuf (adj) */ 293 294 if (data != rte_pktmbuf_adj(m, MBUF_TEST_ALL_HDRS_LEN)) 295 GOTO_FAIL("rte_pktmbuf_adj failed"); 296 if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) 297 GOTO_FAIL("Bad pkt length"); 298 if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) 299 GOTO_FAIL("Bad data length"); 300 if (!rte_pktmbuf_is_contiguous(m)) 301 GOTO_FAIL("Buffer should be continuous"); 302 303 /* this adj should fail */ 304 305 if (rte_pktmbuf_adj(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) != NULL) 306 GOTO_FAIL("rte_pktmbuf_adj should not succeed"); 307 308 /* check data */ 309 310 if (!rte_pktmbuf_is_contiguous(m)) 311 GOTO_FAIL("Buffer should be continuous"); 312 313 for (i=0; i<MBUF_TEST_DATA_LEN; i++) { 314 if (data[i] != 0x66) 315 GOTO_FAIL("Data corrupted at offset %u", i); 316 } 317 318 /* free mbuf */ 319 320 rte_pktmbuf_free(m); 321 m = NULL; 322 return 0; 323 324 fail: 325 if (m) 326 rte_pktmbuf_free(m); 327 return -1; 328 } 329 330 static int 331 testclone_testupdate_testdetach(void) 332 { 333 struct rte_mbuf *m = NULL; 334 struct rte_mbuf *clone = NULL; 335 struct rte_mbuf *clone2 = NULL; 336 unaligned_uint32_t *data; 337 338 /* alloc a mbuf */ 339 m = rte_pktmbuf_alloc(pktmbuf_pool); 340 if (m == NULL) 341 GOTO_FAIL("ooops not allocating mbuf"); 342 343 if (rte_pktmbuf_pkt_len(m) != 0) 344 GOTO_FAIL("Bad length"); 345 346 rte_pktmbuf_append(m, sizeof(uint32_t)); 347 data = rte_pktmbuf_mtod(m, unaligned_uint32_t *); 348 *data = MAGIC_DATA; 349 350 /* clone the allocated mbuf */ 351 clone = rte_pktmbuf_clone(m, pktmbuf_pool); 352 if (clone == NULL) 353 GOTO_FAIL("cannot clone data\n"); 354 355 data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *); 356 if (*data != MAGIC_DATA) 357 GOTO_FAIL("invalid data in clone\n"); 358 359 if (rte_mbuf_refcnt_read(m) != 2) 360 GOTO_FAIL("invalid refcnt in m\n"); 361 362 /* free the clone */ 363 rte_pktmbuf_free(clone); 364 clone = NULL; 365 366 /* same test with a chained mbuf */ 367 m->next = rte_pktmbuf_alloc(pktmbuf_pool); 368 if (m->next == NULL) 369 GOTO_FAIL("Next Pkt Null\n"); 370 371 rte_pktmbuf_append(m->next, sizeof(uint32_t)); 372 data = rte_pktmbuf_mtod(m->next, unaligned_uint32_t *); 373 *data = MAGIC_DATA; 374 375 clone = rte_pktmbuf_clone(m, pktmbuf_pool); 376 if (clone == NULL) 377 GOTO_FAIL("cannot clone data\n"); 378 379 data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *); 380 if (*data != MAGIC_DATA) 381 GOTO_FAIL("invalid data in clone\n"); 382 383 data = rte_pktmbuf_mtod(clone->next, unaligned_uint32_t *); 384 if (*data != MAGIC_DATA) 385 GOTO_FAIL("invalid data in clone->next\n"); 386 387 if (rte_mbuf_refcnt_read(m) != 2) 388 GOTO_FAIL("invalid refcnt in m\n"); 389 390 if (rte_mbuf_refcnt_read(m->next) != 2) 391 GOTO_FAIL("invalid refcnt in m->next\n"); 392 393 /* try to clone the clone */ 394 395 clone2 = rte_pktmbuf_clone(clone, pktmbuf_pool); 396 if (clone2 == NULL) 397 GOTO_FAIL("cannot clone the clone\n"); 398 399 data = rte_pktmbuf_mtod(clone2, unaligned_uint32_t *); 400 if (*data != MAGIC_DATA) 401 GOTO_FAIL("invalid data in clone2\n"); 402 403 data = rte_pktmbuf_mtod(clone2->next, unaligned_uint32_t *); 404 if (*data != MAGIC_DATA) 405 GOTO_FAIL("invalid data in clone2->next\n"); 406 407 if (rte_mbuf_refcnt_read(m) != 3) 408 GOTO_FAIL("invalid refcnt in m\n"); 409 410 if (rte_mbuf_refcnt_read(m->next) != 3) 411 GOTO_FAIL("invalid refcnt in m->next\n"); 412 413 /* free mbuf */ 414 rte_pktmbuf_free(m); 415 rte_pktmbuf_free(clone); 416 rte_pktmbuf_free(clone2); 417 418 m = NULL; 419 clone = NULL; 420 clone2 = NULL; 421 printf("%s ok\n", __func__); 422 return 0; 423 424 fail: 425 if (m) 426 rte_pktmbuf_free(m); 427 if (clone) 428 rte_pktmbuf_free(clone); 429 if (clone2) 430 rte_pktmbuf_free(clone2); 431 return -1; 432 } 433 434 static int 435 test_attach_from_different_pool(void) 436 { 437 struct rte_mbuf *m = NULL; 438 struct rte_mbuf *clone = NULL; 439 struct rte_mbuf *clone2 = NULL; 440 char *data, *c_data, *c_data2; 441 442 /* alloc a mbuf */ 443 m = rte_pktmbuf_alloc(pktmbuf_pool); 444 if (m == NULL) 445 GOTO_FAIL("cannot allocate mbuf"); 446 447 if (rte_pktmbuf_pkt_len(m) != 0) 448 GOTO_FAIL("Bad length"); 449 450 data = rte_pktmbuf_mtod(m, char *); 451 452 /* allocate a new mbuf from the second pool, and attach it to the first 453 * mbuf */ 454 clone = rte_pktmbuf_alloc(pktmbuf_pool2); 455 if (clone == NULL) 456 GOTO_FAIL("cannot allocate mbuf from second pool\n"); 457 458 /* check data room size and priv size, and erase priv */ 459 if (rte_pktmbuf_data_room_size(clone->pool) != 0) 460 GOTO_FAIL("data room size should be 0\n"); 461 if (rte_pktmbuf_priv_size(clone->pool) != MBUF2_PRIV_SIZE) 462 GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE); 463 memset(clone + 1, 0, MBUF2_PRIV_SIZE); 464 465 /* save data pointer to compare it after detach() */ 466 c_data = rte_pktmbuf_mtod(clone, char *); 467 if (c_data != (char *)clone + sizeof(*clone) + MBUF2_PRIV_SIZE) 468 GOTO_FAIL("bad data pointer in clone"); 469 if (rte_pktmbuf_headroom(clone) != 0) 470 GOTO_FAIL("bad headroom in clone"); 471 472 rte_pktmbuf_attach(clone, m); 473 474 if (rte_pktmbuf_mtod(clone, char *) != data) 475 GOTO_FAIL("clone was not attached properly\n"); 476 if (rte_pktmbuf_headroom(clone) != RTE_PKTMBUF_HEADROOM) 477 GOTO_FAIL("bad headroom in clone after attach"); 478 if (rte_mbuf_refcnt_read(m) != 2) 479 GOTO_FAIL("invalid refcnt in m\n"); 480 481 /* allocate a new mbuf from the second pool, and attach it to the first 482 * cloned mbuf */ 483 clone2 = rte_pktmbuf_alloc(pktmbuf_pool2); 484 if (clone2 == NULL) 485 GOTO_FAIL("cannot allocate clone2 from second pool\n"); 486 487 /* check data room size and priv size, and erase priv */ 488 if (rte_pktmbuf_data_room_size(clone2->pool) != 0) 489 GOTO_FAIL("data room size should be 0\n"); 490 if (rte_pktmbuf_priv_size(clone2->pool) != MBUF2_PRIV_SIZE) 491 GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE); 492 memset(clone2 + 1, 0, MBUF2_PRIV_SIZE); 493 494 /* save data pointer to compare it after detach() */ 495 c_data2 = rte_pktmbuf_mtod(clone2, char *); 496 if (c_data2 != (char *)clone2 + sizeof(*clone2) + MBUF2_PRIV_SIZE) 497 GOTO_FAIL("bad data pointer in clone2"); 498 if (rte_pktmbuf_headroom(clone2) != 0) 499 GOTO_FAIL("bad headroom in clone2"); 500 501 rte_pktmbuf_attach(clone2, clone); 502 503 if (rte_pktmbuf_mtod(clone2, char *) != data) 504 GOTO_FAIL("clone2 was not attached properly\n"); 505 if (rte_pktmbuf_headroom(clone2) != RTE_PKTMBUF_HEADROOM) 506 GOTO_FAIL("bad headroom in clone2 after attach"); 507 if (rte_mbuf_refcnt_read(m) != 3) 508 GOTO_FAIL("invalid refcnt in m\n"); 509 510 /* detach the clones */ 511 rte_pktmbuf_detach(clone); 512 if (c_data != rte_pktmbuf_mtod(clone, char *)) 513 GOTO_FAIL("clone was not detached properly\n"); 514 if (rte_mbuf_refcnt_read(m) != 2) 515 GOTO_FAIL("invalid refcnt in m\n"); 516 517 rte_pktmbuf_detach(clone2); 518 if (c_data2 != rte_pktmbuf_mtod(clone2, char *)) 519 GOTO_FAIL("clone2 was not detached properly\n"); 520 if (rte_mbuf_refcnt_read(m) != 1) 521 GOTO_FAIL("invalid refcnt in m\n"); 522 523 /* free the clones and the initial mbuf */ 524 rte_pktmbuf_free(clone2); 525 rte_pktmbuf_free(clone); 526 rte_pktmbuf_free(m); 527 printf("%s ok\n", __func__); 528 return 0; 529 530 fail: 531 if (m) 532 rte_pktmbuf_free(m); 533 if (clone) 534 rte_pktmbuf_free(clone); 535 if (clone2) 536 rte_pktmbuf_free(clone2); 537 return -1; 538 } 539 #undef GOTO_FAIL 540 541 /* 542 * test allocation and free of mbufs 543 */ 544 static int 545 test_pktmbuf_pool(void) 546 { 547 unsigned i; 548 struct rte_mbuf *m[NB_MBUF]; 549 int ret = 0; 550 551 for (i=0; i<NB_MBUF; i++) 552 m[i] = NULL; 553 554 /* alloc NB_MBUF mbufs */ 555 for (i=0; i<NB_MBUF; i++) { 556 m[i] = rte_pktmbuf_alloc(pktmbuf_pool); 557 if (m[i] == NULL) { 558 printf("rte_pktmbuf_alloc() failed (%u)\n", i); 559 ret = -1; 560 } 561 } 562 struct rte_mbuf *extra = NULL; 563 extra = rte_pktmbuf_alloc(pktmbuf_pool); 564 if(extra != NULL) { 565 printf("Error pool not empty"); 566 ret = -1; 567 } 568 extra = rte_pktmbuf_clone(m[0], pktmbuf_pool); 569 if(extra != NULL) { 570 printf("Error pool not empty"); 571 ret = -1; 572 } 573 /* free them */ 574 for (i=0; i<NB_MBUF; i++) { 575 if (m[i] != NULL) 576 rte_pktmbuf_free(m[i]); 577 } 578 579 return ret; 580 } 581 582 /* 583 * test that the pointer to the data on a packet mbuf is set properly 584 */ 585 static int 586 test_pktmbuf_pool_ptr(void) 587 { 588 unsigned i; 589 struct rte_mbuf *m[NB_MBUF]; 590 int ret = 0; 591 592 for (i=0; i<NB_MBUF; i++) 593 m[i] = NULL; 594 595 /* alloc NB_MBUF mbufs */ 596 for (i=0; i<NB_MBUF; i++) { 597 m[i] = rte_pktmbuf_alloc(pktmbuf_pool); 598 if (m[i] == NULL) { 599 printf("rte_pktmbuf_alloc() failed (%u)\n", i); 600 ret = -1; 601 break; 602 } 603 m[i]->data_off += 64; 604 } 605 606 /* free them */ 607 for (i=0; i<NB_MBUF; i++) { 608 if (m[i] != NULL) 609 rte_pktmbuf_free(m[i]); 610 } 611 612 for (i=0; i<NB_MBUF; i++) 613 m[i] = NULL; 614 615 /* alloc NB_MBUF mbufs */ 616 for (i=0; i<NB_MBUF; i++) { 617 m[i] = rte_pktmbuf_alloc(pktmbuf_pool); 618 if (m[i] == NULL) { 619 printf("rte_pktmbuf_alloc() failed (%u)\n", i); 620 ret = -1; 621 break; 622 } 623 if (m[i]->data_off != RTE_PKTMBUF_HEADROOM) { 624 printf("invalid data_off\n"); 625 ret = -1; 626 } 627 } 628 629 /* free them */ 630 for (i=0; i<NB_MBUF; i++) { 631 if (m[i] != NULL) 632 rte_pktmbuf_free(m[i]); 633 } 634 635 return ret; 636 } 637 638 static int 639 test_pktmbuf_free_segment(void) 640 { 641 unsigned i; 642 struct rte_mbuf *m[NB_MBUF]; 643 int ret = 0; 644 645 for (i=0; i<NB_MBUF; i++) 646 m[i] = NULL; 647 648 /* alloc NB_MBUF mbufs */ 649 for (i=0; i<NB_MBUF; i++) { 650 m[i] = rte_pktmbuf_alloc(pktmbuf_pool); 651 if (m[i] == NULL) { 652 printf("rte_pktmbuf_alloc() failed (%u)\n", i); 653 ret = -1; 654 } 655 } 656 657 /* free them */ 658 for (i=0; i<NB_MBUF; i++) { 659 if (m[i] != NULL) { 660 struct rte_mbuf *mb, *mt; 661 662 mb = m[i]; 663 while(mb != NULL) { 664 mt = mb; 665 mb = mb->next; 666 rte_pktmbuf_free_seg(mt); 667 } 668 } 669 } 670 671 return ret; 672 } 673 674 /* 675 * Stress test for rte_mbuf atomic refcnt. 676 * Implies that RTE_MBUF_REFCNT_ATOMIC is defined. 677 * For more efficency, recomended to run with RTE_LIBRTE_MBUF_DEBUG defined. 678 */ 679 680 #ifdef RTE_MBUF_REFCNT_ATOMIC 681 682 static int 683 test_refcnt_slave(__attribute__((unused)) void *arg) 684 { 685 unsigned lcore, free; 686 void *mp = 0; 687 688 lcore = rte_lcore_id(); 689 printf("%s started at lcore %u\n", __func__, lcore); 690 691 free = 0; 692 while (refcnt_stop_slaves == 0) { 693 if (rte_ring_dequeue(refcnt_mbuf_ring, &mp) == 0) { 694 free++; 695 rte_pktmbuf_free((struct rte_mbuf *)mp); 696 } 697 } 698 699 refcnt_lcore[lcore] += free; 700 printf("%s finished at lcore %u, " 701 "number of freed mbufs: %u\n", 702 __func__, lcore, free); 703 return 0; 704 } 705 706 static void 707 test_refcnt_iter(unsigned lcore, unsigned iter) 708 { 709 uint16_t ref; 710 unsigned i, n, tref, wn; 711 struct rte_mbuf *m; 712 713 tref = 0; 714 715 /* For each mbuf in the pool: 716 * - allocate mbuf, 717 * - increment it's reference up to N+1, 718 * - enqueue it N times into the ring for slave cores to free. 719 */ 720 for (i = 0, n = rte_mempool_avail_count(refcnt_pool); 721 i != n && (m = rte_pktmbuf_alloc(refcnt_pool)) != NULL; 722 i++) { 723 ref = RTE_MAX(rte_rand() % REFCNT_MAX_REF, 1UL); 724 tref += ref; 725 if ((ref & 1) != 0) { 726 rte_pktmbuf_refcnt_update(m, ref); 727 while (ref-- != 0) 728 rte_ring_enqueue(refcnt_mbuf_ring, m); 729 } else { 730 while (ref-- != 0) { 731 rte_pktmbuf_refcnt_update(m, 1); 732 rte_ring_enqueue(refcnt_mbuf_ring, m); 733 } 734 } 735 rte_pktmbuf_free(m); 736 } 737 738 if (i != n) 739 rte_panic("(lcore=%u, iter=%u): was able to allocate only " 740 "%u from %u mbufs\n", lcore, iter, i, n); 741 742 /* wait till slave lcores will consume all mbufs */ 743 while (!rte_ring_empty(refcnt_mbuf_ring)) 744 ; 745 746 /* check that all mbufs are back into mempool by now */ 747 for (wn = 0; wn != REFCNT_MAX_TIMEOUT; wn++) { 748 if ((i = rte_mempool_avail_count(refcnt_pool)) == n) { 749 refcnt_lcore[lcore] += tref; 750 printf("%s(lcore=%u, iter=%u) completed, " 751 "%u references processed\n", 752 __func__, lcore, iter, tref); 753 return; 754 } 755 rte_delay_ms(100); 756 } 757 758 rte_panic("(lcore=%u, iter=%u): after %us only " 759 "%u of %u mbufs left free\n", lcore, iter, wn, i, n); 760 } 761 762 static int 763 test_refcnt_master(void) 764 { 765 unsigned i, lcore; 766 767 lcore = rte_lcore_id(); 768 printf("%s started at lcore %u\n", __func__, lcore); 769 770 for (i = 0; i != REFCNT_MAX_ITER; i++) 771 test_refcnt_iter(lcore, i); 772 773 refcnt_stop_slaves = 1; 774 rte_wmb(); 775 776 printf("%s finished at lcore %u\n", __func__, lcore); 777 return 0; 778 } 779 780 #endif 781 782 static int 783 test_refcnt_mbuf(void) 784 { 785 #ifdef RTE_MBUF_REFCNT_ATOMIC 786 787 unsigned lnum, master, slave, tref; 788 789 790 if ((lnum = rte_lcore_count()) == 1) { 791 printf("skipping %s, number of lcores: %u is not enough\n", 792 __func__, lnum); 793 return 0; 794 } 795 796 printf("starting %s, at %u lcores\n", __func__, lnum); 797 798 /* create refcnt pool & ring if they don't exist */ 799 800 if (refcnt_pool == NULL && 801 (refcnt_pool = rte_pktmbuf_pool_create( 802 MAKE_STRING(refcnt_pool), 803 REFCNT_MBUF_NUM, 0, 0, 0, 804 SOCKET_ID_ANY)) == NULL) { 805 printf("%s: cannot allocate " MAKE_STRING(refcnt_pool) "\n", 806 __func__); 807 return -1; 808 } 809 810 if (refcnt_mbuf_ring == NULL && 811 (refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring", 812 rte_align32pow2(REFCNT_RING_SIZE), SOCKET_ID_ANY, 813 RING_F_SP_ENQ)) == NULL) { 814 printf("%s: cannot allocate " MAKE_STRING(refcnt_mbuf_ring) 815 "\n", __func__); 816 return -1; 817 } 818 819 refcnt_stop_slaves = 0; 820 memset(refcnt_lcore, 0, sizeof (refcnt_lcore)); 821 822 rte_eal_mp_remote_launch(test_refcnt_slave, NULL, SKIP_MASTER); 823 824 test_refcnt_master(); 825 826 rte_eal_mp_wait_lcore(); 827 828 /* check that we porcessed all references */ 829 tref = 0; 830 master = rte_get_master_lcore(); 831 832 RTE_LCORE_FOREACH_SLAVE(slave) 833 tref += refcnt_lcore[slave]; 834 835 if (tref != refcnt_lcore[master]) 836 rte_panic("refernced mbufs: %u, freed mbufs: %u\n", 837 tref, refcnt_lcore[master]); 838 839 rte_mempool_dump(stdout, refcnt_pool); 840 rte_ring_dump(stdout, refcnt_mbuf_ring); 841 842 #endif 843 return 0; 844 } 845 846 #include <unistd.h> 847 #include <sys/wait.h> 848 849 /* use fork() to test mbuf errors panic */ 850 static int 851 verify_mbuf_check_panics(struct rte_mbuf *buf) 852 { 853 int pid; 854 int status; 855 856 pid = fork(); 857 858 if (pid == 0) { 859 rte_mbuf_sanity_check(buf, 1); /* should panic */ 860 exit(0); /* return normally if it doesn't panic */ 861 } else if (pid < 0){ 862 printf("Fork Failed\n"); 863 return -1; 864 } 865 wait(&status); 866 if(status == 0) 867 return -1; 868 869 return 0; 870 } 871 872 static int 873 test_failing_mbuf_sanity_check(void) 874 { 875 struct rte_mbuf *buf; 876 struct rte_mbuf badbuf; 877 878 printf("Checking rte_mbuf_sanity_check for failure conditions\n"); 879 880 /* get a good mbuf to use to make copies */ 881 buf = rte_pktmbuf_alloc(pktmbuf_pool); 882 if (buf == NULL) 883 return -1; 884 printf("Checking good mbuf initially\n"); 885 if (verify_mbuf_check_panics(buf) != -1) 886 return -1; 887 888 printf("Now checking for error conditions\n"); 889 890 if (verify_mbuf_check_panics(NULL)) { 891 printf("Error with NULL mbuf test\n"); 892 return -1; 893 } 894 895 badbuf = *buf; 896 badbuf.pool = NULL; 897 if (verify_mbuf_check_panics(&badbuf)) { 898 printf("Error with bad-pool mbuf test\n"); 899 return -1; 900 } 901 902 badbuf = *buf; 903 badbuf.buf_physaddr = 0; 904 if (verify_mbuf_check_panics(&badbuf)) { 905 printf("Error with bad-physaddr mbuf test\n"); 906 return -1; 907 } 908 909 badbuf = *buf; 910 badbuf.buf_addr = NULL; 911 if (verify_mbuf_check_panics(&badbuf)) { 912 printf("Error with bad-addr mbuf test\n"); 913 return -1; 914 } 915 916 badbuf = *buf; 917 badbuf.refcnt = 0; 918 if (verify_mbuf_check_panics(&badbuf)) { 919 printf("Error with bad-refcnt(0) mbuf test\n"); 920 return -1; 921 } 922 923 badbuf = *buf; 924 badbuf.refcnt = UINT16_MAX; 925 if (verify_mbuf_check_panics(&badbuf)) { 926 printf("Error with bad-refcnt(MAX) mbuf test\n"); 927 return -1; 928 } 929 930 return 0; 931 } 932 933 934 static int 935 test_mbuf(void) 936 { 937 RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != RTE_CACHE_LINE_MIN_SIZE * 2); 938 939 /* create pktmbuf pool if it does not exist */ 940 if (pktmbuf_pool == NULL) { 941 pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool", 942 NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY); 943 } 944 945 if (pktmbuf_pool == NULL) { 946 printf("cannot allocate mbuf pool\n"); 947 return -1; 948 } 949 950 /* create a specific pktmbuf pool with a priv_size != 0 and no data 951 * room size */ 952 if (pktmbuf_pool2 == NULL) { 953 pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2", 954 NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY); 955 } 956 957 if (pktmbuf_pool2 == NULL) { 958 printf("cannot allocate mbuf pool\n"); 959 return -1; 960 } 961 962 /* test multiple mbuf alloc */ 963 if (test_pktmbuf_pool() < 0) { 964 printf("test_mbuf_pool() failed\n"); 965 return -1; 966 } 967 968 /* do it another time to check that all mbufs were freed */ 969 if (test_pktmbuf_pool() < 0) { 970 printf("test_mbuf_pool() failed (2)\n"); 971 return -1; 972 } 973 974 /* test that the pointer to the data on a packet mbuf is set properly */ 975 if (test_pktmbuf_pool_ptr() < 0) { 976 printf("test_pktmbuf_pool_ptr() failed\n"); 977 return -1; 978 } 979 980 /* test data manipulation in mbuf */ 981 if (test_one_pktmbuf() < 0) { 982 printf("test_one_mbuf() failed\n"); 983 return -1; 984 } 985 986 987 /* 988 * do it another time, to check that allocation reinitialize 989 * the mbuf correctly 990 */ 991 if (test_one_pktmbuf() < 0) { 992 printf("test_one_mbuf() failed (2)\n"); 993 return -1; 994 } 995 996 if (test_pktmbuf_with_non_ascii_data() < 0) { 997 printf("test_pktmbuf_with_non_ascii_data() failed\n"); 998 return -1; 999 } 1000 1001 /* test free pktmbuf segment one by one */ 1002 if (test_pktmbuf_free_segment() < 0) { 1003 printf("test_pktmbuf_free_segment() failed.\n"); 1004 return -1; 1005 } 1006 1007 if (testclone_testupdate_testdetach()<0){ 1008 printf("testclone_and_testupdate() failed \n"); 1009 return -1; 1010 } 1011 1012 if (test_attach_from_different_pool() < 0) { 1013 printf("test_attach_from_different_pool() failed\n"); 1014 return -1; 1015 } 1016 1017 if (test_refcnt_mbuf()<0){ 1018 printf("test_refcnt_mbuf() failed \n"); 1019 return -1; 1020 } 1021 1022 if (test_failing_mbuf_sanity_check() < 0) { 1023 printf("test_failing_mbuf_sanity_check() failed\n"); 1024 return -1; 1025 } 1026 return 0; 1027 } 1028 1029 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf); 1030