test/mbuf: add case for bulk alloc/free functions
[dpdk.git] / app / test / test_mbuf.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <inttypes.h>
11 #include <errno.h>
12 #include <sys/queue.h>
13
14 #include <rte_common.h>
15 #include <rte_errno.h>
16 #include <rte_debug.h>
17 #include <rte_log.h>
18 #include <rte_memory.h>
19 #include <rte_memcpy.h>
20 #include <rte_launch.h>
21 #include <rte_eal.h>
22 #include <rte_per_lcore.h>
23 #include <rte_lcore.h>
24 #include <rte_atomic.h>
25 #include <rte_branch_prediction.h>
26 #include <rte_ring.h>
27 #include <rte_mempool.h>
28 #include <rte_mbuf.h>
29 #include <rte_random.h>
30 #include <rte_cycles.h>
31 #include <rte_malloc.h>
32
33 #include "test.h"
34
35 #define MBUF_DATA_SIZE          2048
36 #define NB_MBUF                 128
37 #define MBUF_TEST_DATA_LEN      1464
38 #define MBUF_TEST_DATA_LEN2     50
39 #define MBUF_TEST_HDR1_LEN      20
40 #define MBUF_TEST_HDR2_LEN      30
41 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
42
43 /* chain length in bulk test */
44 #define CHAIN_LEN 16
45
46 /* size of private data for mbuf in pktmbuf_pool2 */
47 #define MBUF2_PRIV_SIZE         128
48
49 #define REFCNT_MAX_ITER         64
50 #define REFCNT_MAX_TIMEOUT      10
51 #define REFCNT_MAX_REF          (RTE_MAX_LCORE)
52 #define REFCNT_MBUF_NUM         64
53 #define REFCNT_RING_SIZE        (REFCNT_MBUF_NUM * REFCNT_MAX_REF)
54
55 #define MAGIC_DATA              0x42424242
56
57 #define MAKE_STRING(x)          # x
58
59 #ifdef RTE_MBUF_REFCNT_ATOMIC
60
61 static volatile uint32_t refcnt_stop_slaves;
62 static unsigned refcnt_lcore[RTE_MAX_LCORE];
63
64 #endif
65
66 /*
67  * MBUF
68  * ====
69  *
70  * #. Allocate a mbuf pool.
71  *
72  *    - The pool contains NB_MBUF elements, where each mbuf is MBUF_SIZE
73  *      bytes long.
74  *
75  * #. Test multiple allocations of mbufs from this pool.
76  *
77  *    - Allocate NB_MBUF and store pointers in a table.
78  *    - If an allocation fails, return an error.
79  *    - Free all these mbufs.
80  *    - Repeat the same test to check that mbufs were freed correctly.
81  *
82  * #. Test data manipulation in pktmbuf.
83  *
84  *    - Alloc an mbuf.
85  *    - Append data using rte_pktmbuf_append().
86  *    - Test for error in rte_pktmbuf_append() when len is too large.
87  *    - Trim data at the end of mbuf using rte_pktmbuf_trim().
88  *    - Test for error in rte_pktmbuf_trim() when len is too large.
89  *    - Prepend a header using rte_pktmbuf_prepend().
90  *    - Test for error in rte_pktmbuf_prepend() when len is too large.
91  *    - Remove data at the beginning of mbuf using rte_pktmbuf_adj().
92  *    - Test for error in rte_pktmbuf_adj() when len is too large.
93  *    - Check that appended data is not corrupt.
94  *    - Free the mbuf.
95  *    - Between all these tests, check data_len and pkt_len, and
96  *      that the mbuf is contiguous.
97  *    - Repeat the test to check that allocation operations
98  *      reinitialize the mbuf correctly.
99  *
100  * #. Test packet cloning
101  *    - Clone a mbuf and verify the data
102  *    - Clone the cloned mbuf and verify the data
103  *    - Attach a mbuf to another that does not have the same priv_size.
104  */
105
106 #define GOTO_FAIL(str, ...) do {                                        \
107                 printf("mbuf test FAILED (l.%d): <" str ">\n",          \
108                        __LINE__,  ##__VA_ARGS__);                       \
109                 goto fail;                                              \
110 } while(0)
111
112 /*
113  * test data manipulation in mbuf with non-ascii data
114  */
115 static int
116 test_pktmbuf_with_non_ascii_data(struct rte_mempool *pktmbuf_pool)
117 {
118         struct rte_mbuf *m = NULL;
119         char *data;
120
121         m = rte_pktmbuf_alloc(pktmbuf_pool);
122         if (m == NULL)
123                 GOTO_FAIL("Cannot allocate mbuf");
124         if (rte_pktmbuf_pkt_len(m) != 0)
125                 GOTO_FAIL("Bad length");
126
127         data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN);
128         if (data == NULL)
129                 GOTO_FAIL("Cannot append data");
130         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
131                 GOTO_FAIL("Bad pkt length");
132         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
133                 GOTO_FAIL("Bad data length");
134         memset(data, 0xff, rte_pktmbuf_pkt_len(m));
135         if (!rte_pktmbuf_is_contiguous(m))
136                 GOTO_FAIL("Buffer should be continuous");
137         rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN);
138
139         rte_pktmbuf_free(m);
140
141         return 0;
142
143 fail:
144         if(m) {
145                 rte_pktmbuf_free(m);
146         }
147         return -1;
148 }
149
150 /*
151  * test data manipulation in mbuf
152  */
153 static int
154 test_one_pktmbuf(struct rte_mempool *pktmbuf_pool)
155 {
156         struct rte_mbuf *m = NULL;
157         char *data, *data2, *hdr;
158         unsigned i;
159
160         printf("Test pktmbuf API\n");
161
162         /* alloc a mbuf */
163
164         m = rte_pktmbuf_alloc(pktmbuf_pool);
165         if (m == NULL)
166                 GOTO_FAIL("Cannot allocate mbuf");
167         if (rte_pktmbuf_pkt_len(m) != 0)
168                 GOTO_FAIL("Bad length");
169
170         rte_pktmbuf_dump(stdout, m, 0);
171
172         /* append data */
173
174         data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN);
175         if (data == NULL)
176                 GOTO_FAIL("Cannot append data");
177         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
178                 GOTO_FAIL("Bad pkt length");
179         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
180                 GOTO_FAIL("Bad data length");
181         memset(data, 0x66, rte_pktmbuf_pkt_len(m));
182         if (!rte_pktmbuf_is_contiguous(m))
183                 GOTO_FAIL("Buffer should be continuous");
184         rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN);
185         rte_pktmbuf_dump(stdout, m, 2*MBUF_TEST_DATA_LEN);
186
187         /* this append should fail */
188
189         data2 = rte_pktmbuf_append(m, (uint16_t)(rte_pktmbuf_tailroom(m) + 1));
190         if (data2 != NULL)
191                 GOTO_FAIL("Append should not succeed");
192
193         /* append some more data */
194
195         data2 = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
196         if (data2 == NULL)
197                 GOTO_FAIL("Cannot append data");
198         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2)
199                 GOTO_FAIL("Bad pkt length");
200         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2)
201                 GOTO_FAIL("Bad data length");
202         if (!rte_pktmbuf_is_contiguous(m))
203                 GOTO_FAIL("Buffer should be continuous");
204
205         /* trim data at the end of mbuf */
206
207         if (rte_pktmbuf_trim(m, MBUF_TEST_DATA_LEN2) < 0)
208                 GOTO_FAIL("Cannot trim data");
209         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
210                 GOTO_FAIL("Bad pkt length");
211         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
212                 GOTO_FAIL("Bad data length");
213         if (!rte_pktmbuf_is_contiguous(m))
214                 GOTO_FAIL("Buffer should be continuous");
215
216         /* this trim should fail */
217
218         if (rte_pktmbuf_trim(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) == 0)
219                 GOTO_FAIL("trim should not succeed");
220
221         /* prepend one header */
222
223         hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR1_LEN);
224         if (hdr == NULL)
225                 GOTO_FAIL("Cannot prepend");
226         if (data - hdr != MBUF_TEST_HDR1_LEN)
227                 GOTO_FAIL("Prepend failed");
228         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN)
229                 GOTO_FAIL("Bad pkt length");
230         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN)
231                 GOTO_FAIL("Bad data length");
232         if (!rte_pktmbuf_is_contiguous(m))
233                 GOTO_FAIL("Buffer should be continuous");
234         memset(hdr, 0x55, MBUF_TEST_HDR1_LEN);
235
236         /* prepend another header */
237
238         hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR2_LEN);
239         if (hdr == NULL)
240                 GOTO_FAIL("Cannot prepend");
241         if (data - hdr != MBUF_TEST_ALL_HDRS_LEN)
242                 GOTO_FAIL("Prepend failed");
243         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN)
244                 GOTO_FAIL("Bad pkt length");
245         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN)
246                 GOTO_FAIL("Bad data length");
247         if (!rte_pktmbuf_is_contiguous(m))
248                 GOTO_FAIL("Buffer should be continuous");
249         memset(hdr, 0x55, MBUF_TEST_HDR2_LEN);
250
251         rte_mbuf_sanity_check(m, 1);
252         rte_mbuf_sanity_check(m, 0);
253         rte_pktmbuf_dump(stdout, m, 0);
254
255         /* this prepend should fail */
256
257         hdr = rte_pktmbuf_prepend(m, (uint16_t)(rte_pktmbuf_headroom(m) + 1));
258         if (hdr != NULL)
259                 GOTO_FAIL("prepend should not succeed");
260
261         /* remove data at beginning of mbuf (adj) */
262
263         if (data != rte_pktmbuf_adj(m, MBUF_TEST_ALL_HDRS_LEN))
264                 GOTO_FAIL("rte_pktmbuf_adj failed");
265         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
266                 GOTO_FAIL("Bad pkt length");
267         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
268                 GOTO_FAIL("Bad data length");
269         if (!rte_pktmbuf_is_contiguous(m))
270                 GOTO_FAIL("Buffer should be continuous");
271
272         /* this adj should fail */
273
274         if (rte_pktmbuf_adj(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) != NULL)
275                 GOTO_FAIL("rte_pktmbuf_adj should not succeed");
276
277         /* check data */
278
279         if (!rte_pktmbuf_is_contiguous(m))
280                 GOTO_FAIL("Buffer should be continuous");
281
282         for (i=0; i<MBUF_TEST_DATA_LEN; i++) {
283                 if (data[i] != 0x66)
284                         GOTO_FAIL("Data corrupted at offset %u", i);
285         }
286
287         /* free mbuf */
288
289         rte_pktmbuf_free(m);
290         m = NULL;
291         return 0;
292
293 fail:
294         if (m)
295                 rte_pktmbuf_free(m);
296         return -1;
297 }
298
299 static int
300 testclone_testupdate_testdetach(struct rte_mempool *pktmbuf_pool)
301 {
302         struct rte_mbuf *m = NULL;
303         struct rte_mbuf *clone = NULL;
304         struct rte_mbuf *clone2 = NULL;
305         unaligned_uint32_t *data;
306
307         /* alloc a mbuf */
308         m = rte_pktmbuf_alloc(pktmbuf_pool);
309         if (m == NULL)
310                 GOTO_FAIL("ooops not allocating mbuf");
311
312         if (rte_pktmbuf_pkt_len(m) != 0)
313                 GOTO_FAIL("Bad length");
314
315         rte_pktmbuf_append(m, sizeof(uint32_t));
316         data = rte_pktmbuf_mtod(m, unaligned_uint32_t *);
317         *data = MAGIC_DATA;
318
319         /* clone the allocated mbuf */
320         clone = rte_pktmbuf_clone(m, pktmbuf_pool);
321         if (clone == NULL)
322                 GOTO_FAIL("cannot clone data\n");
323
324         data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *);
325         if (*data != MAGIC_DATA)
326                 GOTO_FAIL("invalid data in clone\n");
327
328         if (rte_mbuf_refcnt_read(m) != 2)
329                 GOTO_FAIL("invalid refcnt in m\n");
330
331         /* free the clone */
332         rte_pktmbuf_free(clone);
333         clone = NULL;
334
335         /* same test with a chained mbuf */
336         m->next = rte_pktmbuf_alloc(pktmbuf_pool);
337         if (m->next == NULL)
338                 GOTO_FAIL("Next Pkt Null\n");
339         m->nb_segs = 2;
340
341         rte_pktmbuf_append(m->next, sizeof(uint32_t));
342         m->pkt_len = 2 * sizeof(uint32_t);
343
344         data = rte_pktmbuf_mtod(m->next, unaligned_uint32_t *);
345         *data = MAGIC_DATA;
346
347         clone = rte_pktmbuf_clone(m, pktmbuf_pool);
348         if (clone == NULL)
349                 GOTO_FAIL("cannot clone data\n");
350
351         data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *);
352         if (*data != MAGIC_DATA)
353                 GOTO_FAIL("invalid data in clone\n");
354
355         data = rte_pktmbuf_mtod(clone->next, unaligned_uint32_t *);
356         if (*data != MAGIC_DATA)
357                 GOTO_FAIL("invalid data in clone->next\n");
358
359         if (rte_mbuf_refcnt_read(m) != 2)
360                 GOTO_FAIL("invalid refcnt in m\n");
361
362         if (rte_mbuf_refcnt_read(m->next) != 2)
363                 GOTO_FAIL("invalid refcnt in m->next\n");
364
365         /* try to clone the clone */
366
367         clone2 = rte_pktmbuf_clone(clone, pktmbuf_pool);
368         if (clone2 == NULL)
369                 GOTO_FAIL("cannot clone the clone\n");
370
371         data = rte_pktmbuf_mtod(clone2, unaligned_uint32_t *);
372         if (*data != MAGIC_DATA)
373                 GOTO_FAIL("invalid data in clone2\n");
374
375         data = rte_pktmbuf_mtod(clone2->next, unaligned_uint32_t *);
376         if (*data != MAGIC_DATA)
377                 GOTO_FAIL("invalid data in clone2->next\n");
378
379         if (rte_mbuf_refcnt_read(m) != 3)
380                 GOTO_FAIL("invalid refcnt in m\n");
381
382         if (rte_mbuf_refcnt_read(m->next) != 3)
383                 GOTO_FAIL("invalid refcnt in m->next\n");
384
385         /* free mbuf */
386         rte_pktmbuf_free(m);
387         rte_pktmbuf_free(clone);
388         rte_pktmbuf_free(clone2);
389
390         m = NULL;
391         clone = NULL;
392         clone2 = NULL;
393         printf("%s ok\n", __func__);
394         return 0;
395
396 fail:
397         if (m)
398                 rte_pktmbuf_free(m);
399         if (clone)
400                 rte_pktmbuf_free(clone);
401         if (clone2)
402                 rte_pktmbuf_free(clone2);
403         return -1;
404 }
405
406 static int
407 test_pktmbuf_copy(struct rte_mempool *pktmbuf_pool)
408 {
409         struct rte_mbuf *m = NULL;
410         struct rte_mbuf *copy = NULL;
411         struct rte_mbuf *copy2 = NULL;
412         struct rte_mbuf *clone = NULL;
413         unaligned_uint32_t *data;
414
415         /* alloc a mbuf */
416         m = rte_pktmbuf_alloc(pktmbuf_pool);
417         if (m == NULL)
418                 GOTO_FAIL("ooops not allocating mbuf");
419
420         if (rte_pktmbuf_pkt_len(m) != 0)
421                 GOTO_FAIL("Bad length");
422
423         rte_pktmbuf_append(m, sizeof(uint32_t));
424         data = rte_pktmbuf_mtod(m, unaligned_uint32_t *);
425         *data = MAGIC_DATA;
426
427         /* copy the allocated mbuf */
428         copy = rte_pktmbuf_copy(m, pktmbuf_pool, 0, UINT32_MAX);
429         if (copy == NULL)
430                 GOTO_FAIL("cannot copy data\n");
431
432         if (rte_pktmbuf_pkt_len(copy) != sizeof(uint32_t))
433                 GOTO_FAIL("copy length incorrect\n");
434
435         if (rte_pktmbuf_data_len(copy) != sizeof(uint32_t))
436                 GOTO_FAIL("copy data length incorrect\n");
437
438         data = rte_pktmbuf_mtod(copy, unaligned_uint32_t *);
439         if (*data != MAGIC_DATA)
440                 GOTO_FAIL("invalid data in copy\n");
441
442         /* free the copy */
443         rte_pktmbuf_free(copy);
444         copy = NULL;
445
446         /* same test with a cloned mbuf */
447         clone = rte_pktmbuf_clone(m, pktmbuf_pool);
448         if (clone == NULL)
449                 GOTO_FAIL("cannot clone data\n");
450
451         if (!RTE_MBUF_CLONED(clone))
452                 GOTO_FAIL("clone did not give a cloned mbuf\n");
453
454         copy = rte_pktmbuf_copy(clone, pktmbuf_pool, 0, UINT32_MAX);
455         if (copy == NULL)
456                 GOTO_FAIL("cannot copy cloned mbuf\n");
457
458         if (RTE_MBUF_CLONED(copy))
459                 GOTO_FAIL("copy of clone is cloned?\n");
460
461         if (rte_pktmbuf_pkt_len(copy) != sizeof(uint32_t))
462                 GOTO_FAIL("copy clone length incorrect\n");
463
464         if (rte_pktmbuf_data_len(copy) != sizeof(uint32_t))
465                 GOTO_FAIL("copy clone data length incorrect\n");
466
467         data = rte_pktmbuf_mtod(copy, unaligned_uint32_t *);
468         if (*data != MAGIC_DATA)
469                 GOTO_FAIL("invalid data in clone copy\n");
470         rte_pktmbuf_free(clone);
471         rte_pktmbuf_free(copy);
472         copy = NULL;
473         clone = NULL;
474
475
476         /* same test with a chained mbuf */
477         m->next = rte_pktmbuf_alloc(pktmbuf_pool);
478         if (m->next == NULL)
479                 GOTO_FAIL("Next Pkt Null\n");
480         m->nb_segs = 2;
481
482         rte_pktmbuf_append(m->next, sizeof(uint32_t));
483         m->pkt_len = 2 * sizeof(uint32_t);
484         data = rte_pktmbuf_mtod(m->next, unaligned_uint32_t *);
485         *data = MAGIC_DATA + 1;
486
487         copy = rte_pktmbuf_copy(m, pktmbuf_pool, 0, UINT32_MAX);
488         if (copy == NULL)
489                 GOTO_FAIL("cannot copy data\n");
490
491         if (rte_pktmbuf_pkt_len(copy) != 2 * sizeof(uint32_t))
492                 GOTO_FAIL("chain copy length incorrect\n");
493
494         if (rte_pktmbuf_data_len(copy) != 2 * sizeof(uint32_t))
495                 GOTO_FAIL("chain copy data length incorrect\n");
496
497         data = rte_pktmbuf_mtod(copy, unaligned_uint32_t *);
498         if (data[0] != MAGIC_DATA || data[1] != MAGIC_DATA + 1)
499                 GOTO_FAIL("invalid data in copy\n");
500
501         rte_pktmbuf_free(copy2);
502
503         /* test offset copy */
504         copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool,
505                                  sizeof(uint32_t), UINT32_MAX);
506         if (copy2 == NULL)
507                 GOTO_FAIL("cannot copy the copy\n");
508
509         if (rte_pktmbuf_pkt_len(copy2) != sizeof(uint32_t))
510                 GOTO_FAIL("copy with offset, length incorrect\n");
511
512         if (rte_pktmbuf_data_len(copy2) != sizeof(uint32_t))
513                 GOTO_FAIL("copy with offset, data length incorrect\n");
514
515         data = rte_pktmbuf_mtod(copy2, unaligned_uint32_t *);
516         if (data[0] != MAGIC_DATA + 1)
517                 GOTO_FAIL("copy with offset, invalid data\n");
518
519         rte_pktmbuf_free(copy2);
520
521         /* test truncation copy */
522         copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool,
523                                  0, sizeof(uint32_t));
524         if (copy2 == NULL)
525                 GOTO_FAIL("cannot copy the copy\n");
526
527         if (rte_pktmbuf_pkt_len(copy2) != sizeof(uint32_t))
528                 GOTO_FAIL("copy with truncate, length incorrect\n");
529
530         if (rte_pktmbuf_data_len(copy2) != sizeof(uint32_t))
531                 GOTO_FAIL("copy with truncate, data length incorrect\n");
532
533         data = rte_pktmbuf_mtod(copy2, unaligned_uint32_t *);
534         if (data[0] != MAGIC_DATA)
535                 GOTO_FAIL("copy with truncate, invalid data\n");
536
537         /* free mbuf */
538         rte_pktmbuf_free(m);
539         rte_pktmbuf_free(copy);
540         rte_pktmbuf_free(copy2);
541
542         m = NULL;
543         copy = NULL;
544         copy2 = NULL;
545         printf("%s ok\n", __func__);
546         return 0;
547
548 fail:
549         if (m)
550                 rte_pktmbuf_free(m);
551         if (copy)
552                 rte_pktmbuf_free(copy);
553         if (copy2)
554                 rte_pktmbuf_free(copy2);
555         return -1;
556 }
557
558 static int
559 test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
560                                 struct rte_mempool *pktmbuf_pool2)
561 {
562         struct rte_mbuf *m = NULL;
563         struct rte_mbuf *clone = NULL;
564         struct rte_mbuf *clone2 = NULL;
565         char *data, *c_data, *c_data2;
566
567         /* alloc a mbuf */
568         m = rte_pktmbuf_alloc(pktmbuf_pool);
569         if (m == NULL)
570                 GOTO_FAIL("cannot allocate mbuf");
571
572         if (rte_pktmbuf_pkt_len(m) != 0)
573                 GOTO_FAIL("Bad length");
574
575         data = rte_pktmbuf_mtod(m, char *);
576
577         /* allocate a new mbuf from the second pool, and attach it to the first
578          * mbuf */
579         clone = rte_pktmbuf_alloc(pktmbuf_pool2);
580         if (clone == NULL)
581                 GOTO_FAIL("cannot allocate mbuf from second pool\n");
582
583         /* check data room size and priv size, and erase priv */
584         if (rte_pktmbuf_data_room_size(clone->pool) != 0)
585                 GOTO_FAIL("data room size should be 0\n");
586         if (rte_pktmbuf_priv_size(clone->pool) != MBUF2_PRIV_SIZE)
587                 GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE);
588         memset(clone + 1, 0, MBUF2_PRIV_SIZE);
589
590         /* save data pointer to compare it after detach() */
591         c_data = rte_pktmbuf_mtod(clone, char *);
592         if (c_data != (char *)clone + sizeof(*clone) + MBUF2_PRIV_SIZE)
593                 GOTO_FAIL("bad data pointer in clone");
594         if (rte_pktmbuf_headroom(clone) != 0)
595                 GOTO_FAIL("bad headroom in clone");
596
597         rte_pktmbuf_attach(clone, m);
598
599         if (rte_pktmbuf_mtod(clone, char *) != data)
600                 GOTO_FAIL("clone was not attached properly\n");
601         if (rte_pktmbuf_headroom(clone) != RTE_PKTMBUF_HEADROOM)
602                 GOTO_FAIL("bad headroom in clone after attach");
603         if (rte_mbuf_refcnt_read(m) != 2)
604                 GOTO_FAIL("invalid refcnt in m\n");
605
606         /* allocate a new mbuf from the second pool, and attach it to the first
607          * cloned mbuf */
608         clone2 = rte_pktmbuf_alloc(pktmbuf_pool2);
609         if (clone2 == NULL)
610                 GOTO_FAIL("cannot allocate clone2 from second pool\n");
611
612         /* check data room size and priv size, and erase priv */
613         if (rte_pktmbuf_data_room_size(clone2->pool) != 0)
614                 GOTO_FAIL("data room size should be 0\n");
615         if (rte_pktmbuf_priv_size(clone2->pool) != MBUF2_PRIV_SIZE)
616                 GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE);
617         memset(clone2 + 1, 0, MBUF2_PRIV_SIZE);
618
619         /* save data pointer to compare it after detach() */
620         c_data2 = rte_pktmbuf_mtod(clone2, char *);
621         if (c_data2 != (char *)clone2 + sizeof(*clone2) + MBUF2_PRIV_SIZE)
622                 GOTO_FAIL("bad data pointer in clone2");
623         if (rte_pktmbuf_headroom(clone2) != 0)
624                 GOTO_FAIL("bad headroom in clone2");
625
626         rte_pktmbuf_attach(clone2, clone);
627
628         if (rte_pktmbuf_mtod(clone2, char *) != data)
629                 GOTO_FAIL("clone2 was not attached properly\n");
630         if (rte_pktmbuf_headroom(clone2) != RTE_PKTMBUF_HEADROOM)
631                 GOTO_FAIL("bad headroom in clone2 after attach");
632         if (rte_mbuf_refcnt_read(m) != 3)
633                 GOTO_FAIL("invalid refcnt in m\n");
634
635         /* detach the clones */
636         rte_pktmbuf_detach(clone);
637         if (c_data != rte_pktmbuf_mtod(clone, char *))
638                 GOTO_FAIL("clone was not detached properly\n");
639         if (rte_mbuf_refcnt_read(m) != 2)
640                 GOTO_FAIL("invalid refcnt in m\n");
641
642         rte_pktmbuf_detach(clone2);
643         if (c_data2 != rte_pktmbuf_mtod(clone2, char *))
644                 GOTO_FAIL("clone2 was not detached properly\n");
645         if (rte_mbuf_refcnt_read(m) != 1)
646                 GOTO_FAIL("invalid refcnt in m\n");
647
648         /* free the clones and the initial mbuf */
649         rte_pktmbuf_free(clone2);
650         rte_pktmbuf_free(clone);
651         rte_pktmbuf_free(m);
652         printf("%s ok\n", __func__);
653         return 0;
654
655 fail:
656         if (m)
657                 rte_pktmbuf_free(m);
658         if (clone)
659                 rte_pktmbuf_free(clone);
660         if (clone2)
661                 rte_pktmbuf_free(clone2);
662         return -1;
663 }
664 #undef GOTO_FAIL
665
666 /*
667  * test allocation and free of mbufs
668  */
669 static int
670 test_pktmbuf_pool(struct rte_mempool *pktmbuf_pool)
671 {
672         unsigned i;
673         struct rte_mbuf *m[NB_MBUF];
674         int ret = 0;
675
676         for (i=0; i<NB_MBUF; i++)
677                 m[i] = NULL;
678
679         /* alloc NB_MBUF mbufs */
680         for (i=0; i<NB_MBUF; i++) {
681                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
682                 if (m[i] == NULL) {
683                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
684                         ret = -1;
685                 }
686         }
687         struct rte_mbuf *extra = NULL;
688         extra = rte_pktmbuf_alloc(pktmbuf_pool);
689         if(extra != NULL) {
690                 printf("Error pool not empty");
691                 ret = -1;
692         }
693         extra = rte_pktmbuf_clone(m[0], pktmbuf_pool);
694         if(extra != NULL) {
695                 printf("Error pool not empty");
696                 ret = -1;
697         }
698         /* free them */
699         for (i=0; i<NB_MBUF; i++) {
700                 if (m[i] != NULL)
701                         rte_pktmbuf_free(m[i]);
702         }
703
704         return ret;
705 }
706
707 /*
708  * test bulk allocation and bulk free of mbufs
709  */
710 static int
711 test_pktmbuf_pool_bulk(void)
712 {
713         struct rte_mempool *pool = NULL;
714         struct rte_mempool *pool2 = NULL;
715         unsigned int i;
716         struct rte_mbuf *m;
717         struct rte_mbuf *mbufs[NB_MBUF];
718         int ret = 0;
719
720         /* We cannot use the preallocated mbuf pools because their caches
721          * prevent us from bulk allocating all objects in them.
722          * So we create our own mbuf pools without caches.
723          */
724         printf("Create mbuf pools for bulk allocation.\n");
725         pool = rte_pktmbuf_pool_create("test_pktmbuf_bulk",
726                         NB_MBUF, 0, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
727         if (pool == NULL) {
728                 printf("rte_pktmbuf_pool_create() failed. rte_errno %d\n",
729                        rte_errno);
730                 goto err;
731         }
732         pool2 = rte_pktmbuf_pool_create("test_pktmbuf_bulk2",
733                         NB_MBUF, 0, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
734         if (pool2 == NULL) {
735                 printf("rte_pktmbuf_pool_create() failed. rte_errno %d\n",
736                        rte_errno);
737                 goto err;
738         }
739
740         /* Preconditions: Mempools must be full. */
741         if (!(rte_mempool_full(pool) && rte_mempool_full(pool2))) {
742                 printf("Test precondition failed: mempools not full\n");
743                 goto err;
744         }
745         if (!(rte_mempool_avail_count(pool) == NB_MBUF &&
746                         rte_mempool_avail_count(pool2) == NB_MBUF)) {
747                 printf("Test precondition failed: mempools: %u+%u != %u+%u",
748                        rte_mempool_avail_count(pool),
749                        rte_mempool_avail_count(pool2),
750                        NB_MBUF, NB_MBUF);
751                 goto err;
752         }
753
754         printf("Test single bulk alloc, followed by multiple bulk free.\n");
755
756         /* Bulk allocate all mbufs in the pool, in one go. */
757         ret = rte_pktmbuf_alloc_bulk(pool, mbufs, NB_MBUF);
758         if (ret != 0) {
759                 printf("rte_pktmbuf_alloc_bulk() failed: %d\n", ret);
760                 goto err;
761         }
762         /* Test that they have been removed from the pool. */
763         if (!rte_mempool_empty(pool)) {
764                 printf("mempool not empty\n");
765                 goto err;
766         }
767         /* Bulk free all mbufs, in four steps. */
768         RTE_BUILD_BUG_ON(NB_MBUF % 4 != 0);
769         for (i = 0; i < NB_MBUF; i += NB_MBUF / 4) {
770                 rte_pktmbuf_free_bulk(&mbufs[i], NB_MBUF / 4);
771                 /* Test that they have been returned to the pool. */
772                 if (rte_mempool_avail_count(pool) != i + NB_MBUF / 4) {
773                         printf("mempool avail count incorrect\n");
774                         goto err;
775                 }
776         }
777
778         printf("Test multiple bulk alloc, followed by single bulk free.\n");
779
780         /* Bulk allocate all mbufs in the pool, in four steps. */
781         for (i = 0; i < NB_MBUF; i += NB_MBUF / 4) {
782                 ret = rte_pktmbuf_alloc_bulk(pool, &mbufs[i], NB_MBUF / 4);
783                 if (ret != 0) {
784                         printf("rte_pktmbuf_alloc_bulk() failed: %d\n", ret);
785                         goto err;
786                 }
787         }
788         /* Test that they have been removed from the pool. */
789         if (!rte_mempool_empty(pool)) {
790                 printf("mempool not empty\n");
791                 goto err;
792         }
793         /* Bulk free all mbufs, in one go. */
794         rte_pktmbuf_free_bulk(mbufs, NB_MBUF);
795         /* Test that they have been returned to the pool. */
796         if (!rte_mempool_full(pool)) {
797                 printf("mempool not full\n");
798                 goto err;
799         }
800
801         printf("Test bulk free of single long chain.\n");
802
803         /* Bulk allocate all mbufs in the pool, in one go. */
804         ret = rte_pktmbuf_alloc_bulk(pool, mbufs, NB_MBUF);
805         if (ret != 0) {
806                 printf("rte_pktmbuf_alloc_bulk() failed: %d\n", ret);
807                 goto err;
808         }
809         /* Create a long mbuf chain. */
810         for (i = 1; i < NB_MBUF; i++) {
811                 ret = rte_pktmbuf_chain(mbufs[0], mbufs[i]);
812                 if (ret != 0) {
813                         printf("rte_pktmbuf_chain() failed: %d\n", ret);
814                         goto err;
815                 }
816                 mbufs[i] = NULL;
817         }
818         /* Free the mbuf chain containing all the mbufs. */
819         rte_pktmbuf_free_bulk(mbufs, 1);
820         /* Test that they have been returned to the pool. */
821         if (!rte_mempool_full(pool)) {
822                 printf("mempool not full\n");
823                 goto err;
824         }
825
826         printf("Test bulk free of multiple chains using multiple pools.\n");
827
828         /* Create mbuf chains containing mbufs from different pools. */
829         RTE_BUILD_BUG_ON(CHAIN_LEN % 2 != 0);
830         RTE_BUILD_BUG_ON(NB_MBUF % (CHAIN_LEN / 2) != 0);
831         for (i = 0; i < NB_MBUF * 2; i++) {
832                 m = rte_pktmbuf_alloc((i & 4) ? pool2 : pool);
833                 if (m == NULL) {
834                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
835                         goto err;
836                 }
837                 if ((i % CHAIN_LEN) == 0)
838                         mbufs[i / CHAIN_LEN] = m;
839                 else
840                         rte_pktmbuf_chain(mbufs[i / CHAIN_LEN], m);
841         }
842         /* Test that both pools have been emptied. */
843         if (!(rte_mempool_empty(pool) && rte_mempool_empty(pool2))) {
844                 printf("mempools not empty\n");
845                 goto err;
846         }
847         /* Free one mbuf chain. */
848         rte_pktmbuf_free_bulk(mbufs, 1);
849         /* Test that the segments have been returned to the pools. */
850         if (!(rte_mempool_avail_count(pool) == CHAIN_LEN / 2 &&
851                         rte_mempool_avail_count(pool2) == CHAIN_LEN / 2)) {
852                 printf("all segments of first mbuf have not been returned\n");
853                 goto err;
854         }
855         /* Free the remaining mbuf chains. */
856         rte_pktmbuf_free_bulk(&mbufs[1], NB_MBUF * 2 / CHAIN_LEN - 1);
857         /* Test that they have been returned to the pools. */
858         if (!(rte_mempool_full(pool) && rte_mempool_full(pool2))) {
859                 printf("mempools not full\n");
860                 goto err;
861         }
862
863         ret = 0;
864         goto done;
865
866 err:
867         ret = -1;
868
869 done:
870         printf("Free mbuf pools for bulk allocation.\n");
871         rte_mempool_free(pool);
872         rte_mempool_free(pool2);
873         return ret;
874 }
875
876 /*
877  * test that the pointer to the data on a packet mbuf is set properly
878  */
879 static int
880 test_pktmbuf_pool_ptr(struct rte_mempool *pktmbuf_pool)
881 {
882         unsigned i;
883         struct rte_mbuf *m[NB_MBUF];
884         int ret = 0;
885
886         for (i=0; i<NB_MBUF; i++)
887                 m[i] = NULL;
888
889         /* alloc NB_MBUF mbufs */
890         for (i=0; i<NB_MBUF; i++) {
891                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
892                 if (m[i] == NULL) {
893                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
894                         ret = -1;
895                         break;
896                 }
897                 m[i]->data_off += 64;
898         }
899
900         /* free them */
901         for (i=0; i<NB_MBUF; i++) {
902                 if (m[i] != NULL)
903                         rte_pktmbuf_free(m[i]);
904         }
905
906         for (i=0; i<NB_MBUF; i++)
907                 m[i] = NULL;
908
909         /* alloc NB_MBUF mbufs */
910         for (i=0; i<NB_MBUF; i++) {
911                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
912                 if (m[i] == NULL) {
913                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
914                         ret = -1;
915                         break;
916                 }
917                 if (m[i]->data_off != RTE_PKTMBUF_HEADROOM) {
918                         printf("invalid data_off\n");
919                         ret = -1;
920                 }
921         }
922
923         /* free them */
924         for (i=0; i<NB_MBUF; i++) {
925                 if (m[i] != NULL)
926                         rte_pktmbuf_free(m[i]);
927         }
928
929         return ret;
930 }
931
932 static int
933 test_pktmbuf_free_segment(struct rte_mempool *pktmbuf_pool)
934 {
935         unsigned i;
936         struct rte_mbuf *m[NB_MBUF];
937         int ret = 0;
938
939         for (i=0; i<NB_MBUF; i++)
940                 m[i] = NULL;
941
942         /* alloc NB_MBUF mbufs */
943         for (i=0; i<NB_MBUF; i++) {
944                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
945                 if (m[i] == NULL) {
946                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
947                         ret = -1;
948                 }
949         }
950
951         /* free them */
952         for (i=0; i<NB_MBUF; i++) {
953                 if (m[i] != NULL) {
954                         struct rte_mbuf *mb, *mt;
955
956                         mb = m[i];
957                         while(mb != NULL) {
958                                 mt = mb;
959                                 mb = mb->next;
960                                 rte_pktmbuf_free_seg(mt);
961                         }
962                 }
963         }
964
965         return ret;
966 }
967
968 /*
969  * Stress test for rte_mbuf atomic refcnt.
970  * Implies that RTE_MBUF_REFCNT_ATOMIC is defined.
971  * For more efficiency, recommended to run with RTE_LIBRTE_MBUF_DEBUG defined.
972  */
973
974 #ifdef RTE_MBUF_REFCNT_ATOMIC
975
976 static int
977 test_refcnt_slave(void *arg)
978 {
979         unsigned lcore, free;
980         void *mp = 0;
981         struct rte_ring *refcnt_mbuf_ring = arg;
982
983         lcore = rte_lcore_id();
984         printf("%s started at lcore %u\n", __func__, lcore);
985
986         free = 0;
987         while (refcnt_stop_slaves == 0) {
988                 if (rte_ring_dequeue(refcnt_mbuf_ring, &mp) == 0) {
989                         free++;
990                         rte_pktmbuf_free(mp);
991                 }
992         }
993
994         refcnt_lcore[lcore] += free;
995         printf("%s finished at lcore %u, "
996                "number of freed mbufs: %u\n",
997                __func__, lcore, free);
998         return 0;
999 }
1000
1001 static void
1002 test_refcnt_iter(unsigned int lcore, unsigned int iter,
1003                  struct rte_mempool *refcnt_pool,
1004                  struct rte_ring *refcnt_mbuf_ring)
1005 {
1006         uint16_t ref;
1007         unsigned i, n, tref, wn;
1008         struct rte_mbuf *m;
1009
1010         tref = 0;
1011
1012         /* For each mbuf in the pool:
1013          * - allocate mbuf,
1014          * - increment it's reference up to N+1,
1015          * - enqueue it N times into the ring for slave cores to free.
1016          */
1017         for (i = 0, n = rte_mempool_avail_count(refcnt_pool);
1018             i != n && (m = rte_pktmbuf_alloc(refcnt_pool)) != NULL;
1019             i++) {
1020                 ref = RTE_MAX(rte_rand() % REFCNT_MAX_REF, 1UL);
1021                 tref += ref;
1022                 if ((ref & 1) != 0) {
1023                         rte_pktmbuf_refcnt_update(m, ref);
1024                         while (ref-- != 0)
1025                                 rte_ring_enqueue(refcnt_mbuf_ring, m);
1026                 } else {
1027                         while (ref-- != 0) {
1028                                 rte_pktmbuf_refcnt_update(m, 1);
1029                                 rte_ring_enqueue(refcnt_mbuf_ring, m);
1030                         }
1031                 }
1032                 rte_pktmbuf_free(m);
1033         }
1034
1035         if (i != n)
1036                 rte_panic("(lcore=%u, iter=%u): was able to allocate only "
1037                           "%u from %u mbufs\n", lcore, iter, i, n);
1038
1039         /* wait till slave lcores  will consume all mbufs */
1040         while (!rte_ring_empty(refcnt_mbuf_ring))
1041                 ;
1042
1043         /* check that all mbufs are back into mempool by now */
1044         for (wn = 0; wn != REFCNT_MAX_TIMEOUT; wn++) {
1045                 if ((i = rte_mempool_avail_count(refcnt_pool)) == n) {
1046                         refcnt_lcore[lcore] += tref;
1047                         printf("%s(lcore=%u, iter=%u) completed, "
1048                             "%u references processed\n",
1049                             __func__, lcore, iter, tref);
1050                         return;
1051                 }
1052                 rte_delay_ms(100);
1053         }
1054
1055         rte_panic("(lcore=%u, iter=%u): after %us only "
1056                   "%u of %u mbufs left free\n", lcore, iter, wn, i, n);
1057 }
1058
1059 static int
1060 test_refcnt_master(struct rte_mempool *refcnt_pool,
1061                    struct rte_ring *refcnt_mbuf_ring)
1062 {
1063         unsigned i, lcore;
1064
1065         lcore = rte_lcore_id();
1066         printf("%s started at lcore %u\n", __func__, lcore);
1067
1068         for (i = 0; i != REFCNT_MAX_ITER; i++)
1069                 test_refcnt_iter(lcore, i, refcnt_pool, refcnt_mbuf_ring);
1070
1071         refcnt_stop_slaves = 1;
1072         rte_wmb();
1073
1074         printf("%s finished at lcore %u\n", __func__, lcore);
1075         return 0;
1076 }
1077
1078 #endif
1079
1080 static int
1081 test_refcnt_mbuf(void)
1082 {
1083 #ifdef RTE_MBUF_REFCNT_ATOMIC
1084         unsigned int master, slave, tref;
1085         int ret = -1;
1086         struct rte_mempool *refcnt_pool = NULL;
1087         struct rte_ring *refcnt_mbuf_ring = NULL;
1088
1089         if (rte_lcore_count() < 2) {
1090                 printf("Not enough cores for test_refcnt_mbuf, expecting at least 2\n");
1091                 return TEST_SKIPPED;
1092         }
1093
1094         printf("starting %s, at %u lcores\n", __func__, rte_lcore_count());
1095
1096         /* create refcnt pool & ring if they don't exist */
1097
1098         refcnt_pool = rte_pktmbuf_pool_create(MAKE_STRING(refcnt_pool),
1099                                               REFCNT_MBUF_NUM, 0, 0, 0,
1100                                               SOCKET_ID_ANY);
1101         if (refcnt_pool == NULL) {
1102                 printf("%s: cannot allocate " MAKE_STRING(refcnt_pool) "\n",
1103                     __func__);
1104                 return -1;
1105         }
1106
1107         refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring",
1108                         rte_align32pow2(REFCNT_RING_SIZE), SOCKET_ID_ANY,
1109                                         RING_F_SP_ENQ);
1110         if (refcnt_mbuf_ring == NULL) {
1111                 printf("%s: cannot allocate " MAKE_STRING(refcnt_mbuf_ring)
1112                     "\n", __func__);
1113                 goto err;
1114         }
1115
1116         refcnt_stop_slaves = 0;
1117         memset(refcnt_lcore, 0, sizeof (refcnt_lcore));
1118
1119         rte_eal_mp_remote_launch(test_refcnt_slave, refcnt_mbuf_ring,
1120                                  SKIP_MASTER);
1121
1122         test_refcnt_master(refcnt_pool, refcnt_mbuf_ring);
1123
1124         rte_eal_mp_wait_lcore();
1125
1126         /* check that we porcessed all references */
1127         tref = 0;
1128         master = rte_get_master_lcore();
1129
1130         RTE_LCORE_FOREACH_SLAVE(slave)
1131                 tref += refcnt_lcore[slave];
1132
1133         if (tref != refcnt_lcore[master])
1134                 rte_panic("refernced mbufs: %u, freed mbufs: %u\n",
1135                           tref, refcnt_lcore[master]);
1136
1137         rte_mempool_dump(stdout, refcnt_pool);
1138         rte_ring_dump(stdout, refcnt_mbuf_ring);
1139
1140         ret = 0;
1141
1142 err:
1143         rte_mempool_free(refcnt_pool);
1144         rte_ring_free(refcnt_mbuf_ring);
1145         return ret;
1146 #else
1147         return 0;
1148 #endif
1149 }
1150
1151 #include <unistd.h>
1152 #include <sys/wait.h>
1153
1154 /* use fork() to test mbuf errors panic */
1155 static int
1156 verify_mbuf_check_panics(struct rte_mbuf *buf)
1157 {
1158         int pid;
1159         int status;
1160
1161         pid = fork();
1162
1163         if (pid == 0) {
1164                 rte_mbuf_sanity_check(buf, 1); /* should panic */
1165                 exit(0);  /* return normally if it doesn't panic */
1166         } else if (pid < 0){
1167                 printf("Fork Failed\n");
1168                 return -1;
1169         }
1170         wait(&status);
1171         if(status == 0)
1172                 return -1;
1173
1174         return 0;
1175 }
1176
1177 static int
1178 test_failing_mbuf_sanity_check(struct rte_mempool *pktmbuf_pool)
1179 {
1180         struct rte_mbuf *buf;
1181         struct rte_mbuf badbuf;
1182
1183         printf("Checking rte_mbuf_sanity_check for failure conditions\n");
1184
1185         /* get a good mbuf to use to make copies */
1186         buf = rte_pktmbuf_alloc(pktmbuf_pool);
1187         if (buf == NULL)
1188                 return -1;
1189         printf("Checking good mbuf initially\n");
1190         if (verify_mbuf_check_panics(buf) != -1)
1191                 return -1;
1192
1193         printf("Now checking for error conditions\n");
1194
1195         if (verify_mbuf_check_panics(NULL)) {
1196                 printf("Error with NULL mbuf test\n");
1197                 return -1;
1198         }
1199
1200         badbuf = *buf;
1201         badbuf.pool = NULL;
1202         if (verify_mbuf_check_panics(&badbuf)) {
1203                 printf("Error with bad-pool mbuf test\n");
1204                 return -1;
1205         }
1206
1207         badbuf = *buf;
1208         badbuf.buf_iova = 0;
1209         if (verify_mbuf_check_panics(&badbuf)) {
1210                 printf("Error with bad-physaddr mbuf test\n");
1211                 return -1;
1212         }
1213
1214         badbuf = *buf;
1215         badbuf.buf_addr = NULL;
1216         if (verify_mbuf_check_panics(&badbuf)) {
1217                 printf("Error with bad-addr mbuf test\n");
1218                 return -1;
1219         }
1220
1221         badbuf = *buf;
1222         badbuf.refcnt = 0;
1223         if (verify_mbuf_check_panics(&badbuf)) {
1224                 printf("Error with bad-refcnt(0) mbuf test\n");
1225                 return -1;
1226         }
1227
1228         badbuf = *buf;
1229         badbuf.refcnt = UINT16_MAX;
1230         if (verify_mbuf_check_panics(&badbuf)) {
1231                 printf("Error with bad-refcnt(MAX) mbuf test\n");
1232                 return -1;
1233         }
1234
1235         return 0;
1236 }
1237
1238 static int
1239 test_mbuf_linearize(struct rte_mempool *pktmbuf_pool, int pkt_len,
1240                     int nb_segs)
1241 {
1242
1243         struct rte_mbuf *m = NULL, *mbuf = NULL;
1244         uint8_t *data;
1245         int data_len = 0;
1246         int remain;
1247         int seg, seg_len;
1248         int i;
1249
1250         if (pkt_len < 1) {
1251                 printf("Packet size must be 1 or more (is %d)\n", pkt_len);
1252                 return -1;
1253         }
1254
1255         if (nb_segs < 1) {
1256                 printf("Number of segments must be 1 or more (is %d)\n",
1257                                 nb_segs);
1258                 return -1;
1259         }
1260
1261         seg_len = pkt_len / nb_segs;
1262         if (seg_len == 0)
1263                 seg_len = 1;
1264
1265         remain = pkt_len;
1266
1267         /* Create chained mbuf_src and fill it generated data */
1268         for (seg = 0; remain > 0; seg++) {
1269
1270                 m = rte_pktmbuf_alloc(pktmbuf_pool);
1271                 if (m == NULL) {
1272                         printf("Cannot create segment for source mbuf");
1273                         goto fail;
1274                 }
1275
1276                 /* Make sure if tailroom is zeroed */
1277                 memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
1278                                 rte_pktmbuf_tailroom(m));
1279
1280                 data_len = remain;
1281                 if (data_len > seg_len)
1282                         data_len = seg_len;
1283
1284                 data = (uint8_t *)rte_pktmbuf_append(m, data_len);
1285                 if (data == NULL) {
1286                         printf("Cannot append %d bytes to the mbuf\n",
1287                                         data_len);
1288                         goto fail;
1289                 }
1290
1291                 for (i = 0; i < data_len; i++)
1292                         data[i] = (seg * seg_len + i) % 0x0ff;
1293
1294                 if (seg == 0)
1295                         mbuf = m;
1296                 else
1297                         rte_pktmbuf_chain(mbuf, m);
1298
1299                 remain -= data_len;
1300         }
1301
1302         /* Create destination buffer to store coalesced data */
1303         if (rte_pktmbuf_linearize(mbuf)) {
1304                 printf("Mbuf linearization failed\n");
1305                 goto fail;
1306         }
1307
1308         if (!rte_pktmbuf_is_contiguous(mbuf)) {
1309                 printf("Source buffer should be contiguous after "
1310                                 "linearization\n");
1311                 goto fail;
1312         }
1313
1314         data = rte_pktmbuf_mtod(mbuf, uint8_t *);
1315
1316         for (i = 0; i < pkt_len; i++)
1317                 if (data[i] != (i % 0x0ff)) {
1318                         printf("Incorrect data in linearized mbuf\n");
1319                         goto fail;
1320                 }
1321
1322         rte_pktmbuf_free(mbuf);
1323         return 0;
1324
1325 fail:
1326         if (mbuf)
1327                 rte_pktmbuf_free(mbuf);
1328         return -1;
1329 }
1330
1331 static int
1332 test_mbuf_linearize_check(struct rte_mempool *pktmbuf_pool)
1333 {
1334         struct test_mbuf_array {
1335                 int size;
1336                 int nb_segs;
1337         } mbuf_array[] = {
1338                         { 128, 1 },
1339                         { 64, 64 },
1340                         { 512, 10 },
1341                         { 250, 11 },
1342                         { 123, 8 },
1343         };
1344         unsigned int i;
1345
1346         printf("Test mbuf linearize API\n");
1347
1348         for (i = 0; i < RTE_DIM(mbuf_array); i++)
1349                 if (test_mbuf_linearize(pktmbuf_pool, mbuf_array[i].size,
1350                                 mbuf_array[i].nb_segs)) {
1351                         printf("Test failed for %d, %d\n", mbuf_array[i].size,
1352                                         mbuf_array[i].nb_segs);
1353                         return -1;
1354                 }
1355
1356         return 0;
1357 }
1358
1359 /*
1360  * Helper function for test_tx_ofload
1361  */
1362 static inline void
1363 set_tx_offload(struct rte_mbuf *mb, uint64_t il2, uint64_t il3, uint64_t il4,
1364         uint64_t tso, uint64_t ol3, uint64_t ol2)
1365 {
1366         mb->l2_len = il2;
1367         mb->l3_len = il3;
1368         mb->l4_len = il4;
1369         mb->tso_segsz = tso;
1370         mb->outer_l3_len = ol3;
1371         mb->outer_l2_len = ol2;
1372 }
1373
1374 static int
1375 test_tx_offload(void)
1376 {
1377         struct rte_mbuf *mb;
1378         uint64_t tm, v1, v2;
1379         size_t sz;
1380         uint32_t i;
1381
1382         static volatile struct {
1383                 uint16_t l2;
1384                 uint16_t l3;
1385                 uint16_t l4;
1386                 uint16_t tso;
1387         } txof;
1388
1389         const uint32_t num = 0x10000;
1390
1391         txof.l2 = rte_rand() % (1 <<  RTE_MBUF_L2_LEN_BITS);
1392         txof.l3 = rte_rand() % (1 <<  RTE_MBUF_L3_LEN_BITS);
1393         txof.l4 = rte_rand() % (1 <<  RTE_MBUF_L4_LEN_BITS);
1394         txof.tso = rte_rand() % (1 <<   RTE_MBUF_TSO_SEGSZ_BITS);
1395
1396         printf("%s started, tx_offload = {\n"
1397                 "\tl2_len=%#hx,\n"
1398                 "\tl3_len=%#hx,\n"
1399                 "\tl4_len=%#hx,\n"
1400                 "\ttso_segsz=%#hx,\n"
1401                 "\touter_l3_len=%#x,\n"
1402                 "\touter_l2_len=%#x,\n"
1403                 "};\n",
1404                 __func__,
1405                 txof.l2, txof.l3, txof.l4, txof.tso, txof.l3, txof.l2);
1406
1407         sz = sizeof(*mb) * num;
1408         mb = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
1409         if (mb == NULL) {
1410                 printf("%s failed, out of memory\n", __func__);
1411                 return -ENOMEM;
1412         }
1413
1414         memset(mb, 0, sz);
1415         tm = rte_rdtsc_precise();
1416
1417         for (i = 0; i != num; i++)
1418                 set_tx_offload(mb + i, txof.l2, txof.l3, txof.l4,
1419                         txof.tso, txof.l3, txof.l2);
1420
1421         tm = rte_rdtsc_precise() - tm;
1422         printf("%s set tx_offload by bit-fields: %u iterations, %"
1423                 PRIu64 " cycles, %#Lf cycles/iter\n",
1424                 __func__, num, tm, (long double)tm / num);
1425
1426         v1 = mb[rte_rand() % num].tx_offload;
1427
1428         memset(mb, 0, sz);
1429         tm = rte_rdtsc_precise();
1430
1431         for (i = 0; i != num; i++)
1432                 mb[i].tx_offload = rte_mbuf_tx_offload(txof.l2, txof.l3,
1433                         txof.l4, txof.tso, txof.l3, txof.l2, 0);
1434
1435         tm = rte_rdtsc_precise() - tm;
1436         printf("%s set raw tx_offload: %u iterations, %"
1437                 PRIu64 " cycles, %#Lf cycles/iter\n",
1438                 __func__, num, tm, (long double)tm / num);
1439
1440         v2 = mb[rte_rand() % num].tx_offload;
1441
1442         rte_free(mb);
1443
1444         printf("%s finished\n"
1445                 "expected tx_offload value: 0x%" PRIx64 ";\n"
1446                 "rte_mbuf_tx_offload value: 0x%" PRIx64 ";\n",
1447                 __func__, v1, v2);
1448
1449         return (v1 == v2) ? 0 : -EINVAL;
1450 }
1451
1452 static int
1453 test_mbuf(void)
1454 {
1455         int ret = -1;
1456         struct rte_mempool *pktmbuf_pool = NULL;
1457         struct rte_mempool *pktmbuf_pool2 = NULL;
1458
1459
1460         RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != RTE_CACHE_LINE_MIN_SIZE * 2);
1461
1462         /* create pktmbuf pool if it does not exist */
1463         pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
1464                         NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
1465
1466         if (pktmbuf_pool == NULL) {
1467                 printf("cannot allocate mbuf pool\n");
1468                 goto err;
1469         }
1470
1471         /* create a specific pktmbuf pool with a priv_size != 0 and no data
1472          * room size */
1473         pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
1474                         NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
1475
1476         if (pktmbuf_pool2 == NULL) {
1477                 printf("cannot allocate mbuf pool\n");
1478                 goto err;
1479         }
1480
1481         /* test multiple mbuf alloc */
1482         if (test_pktmbuf_pool(pktmbuf_pool) < 0) {
1483                 printf("test_mbuf_pool() failed\n");
1484                 goto err;
1485         }
1486
1487         /* do it another time to check that all mbufs were freed */
1488         if (test_pktmbuf_pool(pktmbuf_pool) < 0) {
1489                 printf("test_mbuf_pool() failed (2)\n");
1490                 goto err;
1491         }
1492
1493         /* test bulk mbuf alloc and free */
1494         if (test_pktmbuf_pool_bulk() < 0) {
1495                 printf("test_pktmbuf_pool_bulk() failed\n");
1496                 goto err;
1497         }
1498
1499         /* test that the pointer to the data on a packet mbuf is set properly */
1500         if (test_pktmbuf_pool_ptr(pktmbuf_pool) < 0) {
1501                 printf("test_pktmbuf_pool_ptr() failed\n");
1502                 goto err;
1503         }
1504
1505         /* test data manipulation in mbuf */
1506         if (test_one_pktmbuf(pktmbuf_pool) < 0) {
1507                 printf("test_one_mbuf() failed\n");
1508                 goto err;
1509         }
1510
1511
1512         /*
1513          * do it another time, to check that allocation reinitialize
1514          * the mbuf correctly
1515          */
1516         if (test_one_pktmbuf(pktmbuf_pool) < 0) {
1517                 printf("test_one_mbuf() failed (2)\n");
1518                 goto err;
1519         }
1520
1521         if (test_pktmbuf_with_non_ascii_data(pktmbuf_pool) < 0) {
1522                 printf("test_pktmbuf_with_non_ascii_data() failed\n");
1523                 goto err;
1524         }
1525
1526         /* test free pktmbuf segment one by one */
1527         if (test_pktmbuf_free_segment(pktmbuf_pool) < 0) {
1528                 printf("test_pktmbuf_free_segment() failed.\n");
1529                 goto err;
1530         }
1531
1532         if (testclone_testupdate_testdetach(pktmbuf_pool) < 0) {
1533                 printf("testclone_and_testupdate() failed \n");
1534                 goto err;
1535         }
1536
1537         if (test_pktmbuf_copy(pktmbuf_pool) < 0) {
1538                 printf("test_pktmbuf_copy() failed\n");
1539                 goto err;
1540         }
1541
1542         if (test_attach_from_different_pool(pktmbuf_pool, pktmbuf_pool2) < 0) {
1543                 printf("test_attach_from_different_pool() failed\n");
1544                 goto err;
1545         }
1546
1547         if (test_refcnt_mbuf() < 0) {
1548                 printf("test_refcnt_mbuf() failed \n");
1549                 goto err;
1550         }
1551
1552         if (test_failing_mbuf_sanity_check(pktmbuf_pool) < 0) {
1553                 printf("test_failing_mbuf_sanity_check() failed\n");
1554                 goto err;
1555         }
1556
1557         if (test_mbuf_linearize_check(pktmbuf_pool) < 0) {
1558                 printf("test_mbuf_linearize_check() failed\n");
1559                 goto err;
1560         }
1561
1562         if (test_tx_offload() < 0) {
1563                 printf("test_tx_offload() failed\n");
1564                 goto err;
1565         }
1566
1567         ret = 0;
1568 err:
1569         rte_mempool_free(pktmbuf_pool);
1570         rte_mempool_free(pktmbuf_pool2);
1571         return ret;
1572 }
1573
1574 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);