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