xref: /dpdk/app/test/test_mbuf.c (revision cf435a07)
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