app/test: check cloning a clone
[dpdk.git] / app / 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 #define REFCNT_MAX_ITER         64
73 #define REFCNT_MAX_TIMEOUT      10
74 #define REFCNT_MAX_REF          (RTE_MAX_LCORE)
75 #define REFCNT_MBUF_NUM         64
76 #define REFCNT_RING_SIZE        (REFCNT_MBUF_NUM * REFCNT_MAX_REF)
77
78 #define MAGIC_DATA              0x42424242
79
80 #define MAKE_STRING(x)          # x
81
82 static struct rte_mempool *pktmbuf_pool = NULL;
83
84 #ifdef RTE_MBUF_REFCNT_ATOMIC
85
86 static struct rte_mempool *refcnt_pool = NULL;
87 static struct rte_ring *refcnt_mbuf_ring = NULL;
88 static volatile uint32_t refcnt_stop_slaves;
89 static unsigned refcnt_lcore[RTE_MAX_LCORE];
90
91 #endif
92
93 /*
94  * MBUF
95  * ====
96  *
97  * #. Allocate a mbuf pool.
98  *
99  *    - The pool contains NB_MBUF elements, where each mbuf is MBUF_SIZE
100  *      bytes long.
101  *
102  * #. Test multiple allocations of mbufs from this pool.
103  *
104  *    - Allocate NB_MBUF and store pointers in a table.
105  *    - If an allocation fails, return an error.
106  *    - Free all these mbufs.
107  *    - Repeat the same test to check that mbufs were freed correctly.
108  *
109  * #. Test data manipulation in pktmbuf.
110  *
111  *    - Alloc an mbuf.
112  *    - Append data using rte_pktmbuf_append().
113  *    - Test for error in rte_pktmbuf_append() when len is too large.
114  *    - Trim data at the end of mbuf using rte_pktmbuf_trim().
115  *    - Test for error in rte_pktmbuf_trim() when len is too large.
116  *    - Prepend a header using rte_pktmbuf_prepend().
117  *    - Test for error in rte_pktmbuf_prepend() when len is too large.
118  *    - Remove data at the beginning of mbuf using rte_pktmbuf_adj().
119  *    - Test for error in rte_pktmbuf_adj() when len is too large.
120  *    - Check that appended data is not corrupt.
121  *    - Free the mbuf.
122  *    - Between all these tests, check data_len and pkt_len, and
123  *      that the mbuf is contiguous.
124  *    - Repeat the test to check that allocation operations
125  *      reinitialize the mbuf correctly.
126  *
127  * #. Test packet cloning
128  *    - Clone a mbuf and verify the data
129  *    - Clone the cloned mbuf and verify the data
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(void)
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(void)
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(void)
327 {
328         struct rte_mbuf *m = NULL;
329         struct rte_mbuf *clone = NULL;
330         struct rte_mbuf *clone2 = NULL;
331         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, 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, 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, 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, uint32_t *);
375         if (*data != MAGIC_DATA)
376                 GOTO_FAIL("invalid data in clone\n");
377
378         data = rte_pktmbuf_mtod(clone->next, 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, uint32_t *);
395         if (*data != MAGIC_DATA)
396                 GOTO_FAIL("invalid data in clone2\n");
397
398         data = rte_pktmbuf_mtod(clone2->next, 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 #undef GOTO_FAIL
429
430
431
432 /*
433  * test allocation and free of mbufs
434  */
435 static int
436 test_pktmbuf_pool(void)
437 {
438         unsigned i;
439         struct rte_mbuf *m[NB_MBUF];
440         int ret = 0;
441
442         for (i=0; i<NB_MBUF; i++)
443                 m[i] = NULL;
444
445         /* alloc NB_MBUF mbufs */
446         for (i=0; i<NB_MBUF; i++) {
447                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
448                 if (m[i] == NULL) {
449                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
450                         ret = -1;
451                 }
452         }
453         struct rte_mbuf *extra = NULL;
454         extra = rte_pktmbuf_alloc(pktmbuf_pool);
455         if(extra != NULL) {
456                 printf("Error pool not empty");
457                 ret = -1;
458         }
459         extra = rte_pktmbuf_clone(m[0], pktmbuf_pool);
460         if(extra != NULL) {
461                 printf("Error pool not empty");
462                 ret = -1;
463         }
464         /* free them */
465         for (i=0; i<NB_MBUF; i++) {
466                 if (m[i] != NULL)
467                         rte_pktmbuf_free(m[i]);
468         }
469
470         return ret;
471 }
472
473 /*
474  * test that the pointer to the data on a packet mbuf is set properly
475  */
476 static int
477 test_pktmbuf_pool_ptr(void)
478 {
479         unsigned i;
480         struct rte_mbuf *m[NB_MBUF];
481         int ret = 0;
482
483         for (i=0; i<NB_MBUF; i++)
484                 m[i] = NULL;
485
486         /* alloc NB_MBUF mbufs */
487         for (i=0; i<NB_MBUF; i++) {
488                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
489                 if (m[i] == NULL) {
490                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
491                         ret = -1;
492                 }
493                 m[i]->data_off += 64;
494         }
495
496         /* free them */
497         for (i=0; i<NB_MBUF; i++) {
498                 if (m[i] != NULL)
499                         rte_pktmbuf_free(m[i]);
500         }
501
502         for (i=0; i<NB_MBUF; i++)
503                 m[i] = NULL;
504
505         /* alloc NB_MBUF mbufs */
506         for (i=0; i<NB_MBUF; i++) {
507                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
508                 if (m[i] == NULL) {
509                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
510                         ret = -1;
511                 }
512                 if (m[i]->data_off != RTE_PKTMBUF_HEADROOM) {
513                         printf("invalid data_off\n");
514                         ret = -1;
515                 }
516         }
517
518         /* free them */
519         for (i=0; i<NB_MBUF; i++) {
520                 if (m[i] != NULL)
521                         rte_pktmbuf_free(m[i]);
522         }
523
524         return ret;
525 }
526
527 static int
528 test_pktmbuf_free_segment(void)
529 {
530         unsigned i;
531         struct rte_mbuf *m[NB_MBUF];
532         int ret = 0;
533
534         for (i=0; i<NB_MBUF; i++)
535                 m[i] = NULL;
536
537         /* alloc NB_MBUF mbufs */
538         for (i=0; i<NB_MBUF; i++) {
539                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
540                 if (m[i] == NULL) {
541                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
542                         ret = -1;
543                 }
544         }
545
546         /* free them */
547         for (i=0; i<NB_MBUF; i++) {
548                 if (m[i] != NULL) {
549                         struct rte_mbuf *mb, *mt;
550
551                         mb = m[i];
552                         while(mb != NULL) {
553                                 mt = mb;
554                                 mb = mb->next;
555                                 rte_pktmbuf_free_seg(mt);
556                         }
557                 }
558         }
559
560         return ret;
561 }
562
563 /*
564  * Stress test for rte_mbuf atomic refcnt.
565  * Implies that RTE_MBUF_REFCNT_ATOMIC is defined.
566  * For more efficency, recomended to run with RTE_LIBRTE_MBUF_DEBUG defined.
567  */
568
569 #ifdef RTE_MBUF_REFCNT_ATOMIC
570
571 static int
572 test_refcnt_slave(__attribute__((unused)) void *arg)
573 {
574         unsigned lcore, free;
575         void *mp = 0;
576
577         lcore = rte_lcore_id();
578         printf("%s started at lcore %u\n", __func__, lcore);
579
580         free = 0;
581         while (refcnt_stop_slaves == 0) {
582                 if (rte_ring_dequeue(refcnt_mbuf_ring, &mp) == 0) {
583                         free++;
584                         rte_pktmbuf_free((struct rte_mbuf *)mp);
585                 }
586         }
587
588         refcnt_lcore[lcore] += free;
589         printf("%s finished at lcore %u, "
590                "number of freed mbufs: %u\n",
591                __func__, lcore, free);
592         return (0);
593 }
594
595 static void
596 test_refcnt_iter(unsigned lcore, unsigned iter)
597 {
598         uint16_t ref;
599         unsigned i, n, tref, wn;
600         struct rte_mbuf *m;
601
602         tref = 0;
603
604         /* For each mbuf in the pool:
605          * - allocate mbuf,
606          * - increment it's reference up to N+1,
607          * - enqueue it N times into the ring for slave cores to free.
608          */
609         for (i = 0, n = rte_mempool_count(refcnt_pool);
610             i != n && (m = rte_pktmbuf_alloc(refcnt_pool)) != NULL;
611             i++) {
612                 ref = RTE_MAX(rte_rand() % REFCNT_MAX_REF, 1UL);
613                 tref += ref;
614                 if ((ref & 1) != 0) {
615                         rte_pktmbuf_refcnt_update(m, ref);
616                         while (ref-- != 0)
617                                 rte_ring_enqueue(refcnt_mbuf_ring, m);
618                 } else {
619                         while (ref-- != 0) {
620                                 rte_pktmbuf_refcnt_update(m, 1);
621                                 rte_ring_enqueue(refcnt_mbuf_ring, m);
622                         }
623                 }
624                 rte_pktmbuf_free(m);
625         }
626
627         if (i != n)
628                 rte_panic("(lcore=%u, iter=%u): was able to allocate only "
629                           "%u from %u mbufs\n", lcore, iter, i, n);
630
631         /* wait till slave lcores  will consume all mbufs */
632         while (!rte_ring_empty(refcnt_mbuf_ring))
633                 ;
634
635         /* check that all mbufs are back into mempool by now */
636         for (wn = 0; wn != REFCNT_MAX_TIMEOUT; wn++) {
637                 if ((i = rte_mempool_count(refcnt_pool)) == n) {
638                         refcnt_lcore[lcore] += tref;
639                         printf("%s(lcore=%u, iter=%u) completed, "
640                             "%u references processed\n",
641                             __func__, lcore, iter, tref);
642                         return;
643                 }
644                 rte_delay_ms(1000);
645         }
646
647         rte_panic("(lcore=%u, iter=%u): after %us only "
648                   "%u of %u mbufs left free\n", lcore, iter, wn, i, n);
649 }
650
651 static int
652 test_refcnt_master(void)
653 {
654         unsigned i, lcore;
655
656         lcore = rte_lcore_id();
657         printf("%s started at lcore %u\n", __func__, lcore);
658
659         for (i = 0; i != REFCNT_MAX_ITER; i++)
660                 test_refcnt_iter(lcore, i);
661
662         refcnt_stop_slaves = 1;
663         rte_wmb();
664
665         printf("%s finished at lcore %u\n", __func__, lcore);
666         return (0);
667 }
668
669 #endif
670
671 static int
672 test_refcnt_mbuf(void)
673 {
674 #ifdef RTE_MBUF_REFCNT_ATOMIC
675
676         unsigned lnum, master, slave, tref;
677
678
679         if ((lnum = rte_lcore_count()) == 1) {
680                 printf("skipping %s, number of lcores: %u is not enough\n",
681                     __func__, lnum);
682                 return (0);
683         }
684
685         printf("starting %s, at %u lcores\n", __func__, lnum);
686
687         /* create refcnt pool & ring if they don't exist */
688
689         if (refcnt_pool == NULL &&
690                         (refcnt_pool = rte_pktmbuf_pool_create(
691                                 MAKE_STRING(refcnt_pool),
692                                 REFCNT_MBUF_NUM, 0, 0, 0,
693                                 SOCKET_ID_ANY)) == NULL) {
694                 printf("%s: cannot allocate " MAKE_STRING(refcnt_pool) "\n",
695                     __func__);
696                 return (-1);
697         }
698
699         if (refcnt_mbuf_ring == NULL &&
700                         (refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring",
701                         REFCNT_RING_SIZE, SOCKET_ID_ANY,
702                         RING_F_SP_ENQ)) == NULL) {
703                 printf("%s: cannot allocate " MAKE_STRING(refcnt_mbuf_ring)
704                     "\n", __func__);
705                 return (-1);
706         }
707
708         refcnt_stop_slaves = 0;
709         memset(refcnt_lcore, 0, sizeof (refcnt_lcore));
710
711         rte_eal_mp_remote_launch(test_refcnt_slave, NULL, SKIP_MASTER);
712
713         test_refcnt_master();
714
715         rte_eal_mp_wait_lcore();
716
717         /* check that we porcessed all references */
718         tref = 0;
719         master = rte_get_master_lcore();
720
721         RTE_LCORE_FOREACH_SLAVE(slave)
722                 tref += refcnt_lcore[slave];
723
724         if (tref != refcnt_lcore[master])
725                 rte_panic("refernced mbufs: %u, freed mbufs: %u\n",
726                           tref, refcnt_lcore[master]);
727
728         rte_mempool_dump(stdout, refcnt_pool);
729         rte_ring_dump(stdout, refcnt_mbuf_ring);
730
731 #endif
732         return (0);
733 }
734
735 #include <unistd.h>
736 #include <sys/wait.h>
737
738 /* use fork() to test mbuf errors panic */
739 static int
740 verify_mbuf_check_panics(struct rte_mbuf *buf)
741 {
742         int pid;
743         int status;
744
745         pid = fork();
746
747         if (pid == 0) {
748                 rte_mbuf_sanity_check(buf, 1); /* should panic */
749                 exit(0);  /* return normally if it doesn't panic */
750         } else if (pid < 0){
751                 printf("Fork Failed\n");
752                 return -1;
753         }
754         wait(&status);
755         if(status == 0)
756                 return -1;
757
758         return 0;
759 }
760
761 static int
762 test_failing_mbuf_sanity_check(void)
763 {
764         struct rte_mbuf *buf;
765         struct rte_mbuf badbuf;
766
767         printf("Checking rte_mbuf_sanity_check for failure conditions\n");
768
769         /* get a good mbuf to use to make copies */
770         buf = rte_pktmbuf_alloc(pktmbuf_pool);
771         if (buf == NULL)
772                 return -1;
773         printf("Checking good mbuf initially\n");
774         if (verify_mbuf_check_panics(buf) != -1)
775                 return -1;
776
777         printf("Now checking for error conditions\n");
778
779         if (verify_mbuf_check_panics(NULL)) {
780                 printf("Error with NULL mbuf test\n");
781                 return -1;
782         }
783
784         badbuf = *buf;
785         badbuf.pool = NULL;
786         if (verify_mbuf_check_panics(&badbuf)) {
787                 printf("Error with bad-pool mbuf test\n");
788                 return -1;
789         }
790
791         badbuf = *buf;
792         badbuf.buf_physaddr = 0;
793         if (verify_mbuf_check_panics(&badbuf)) {
794                 printf("Error with bad-physaddr mbuf test\n");
795                 return -1;
796         }
797
798         badbuf = *buf;
799         badbuf.buf_addr = NULL;
800         if (verify_mbuf_check_panics(&badbuf)) {
801                 printf("Error with bad-addr mbuf test\n");
802                 return -1;
803         }
804
805         badbuf = *buf;
806         badbuf.refcnt = 0;
807         if (verify_mbuf_check_panics(&badbuf)) {
808                 printf("Error with bad-refcnt(0) mbuf test\n");
809                 return -1;
810         }
811
812         badbuf = *buf;
813         badbuf.refcnt = UINT16_MAX;
814         if (verify_mbuf_check_panics(&badbuf)) {
815                 printf("Error with bad-refcnt(MAX) mbuf test\n");
816                 return -1;
817         }
818
819         return 0;
820 }
821
822
823 static int
824 test_mbuf(void)
825 {
826         RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != RTE_CACHE_LINE_SIZE * 2);
827
828         /* create pktmbuf pool if it does not exist */
829         if (pktmbuf_pool == NULL) {
830                 pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
831                         NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
832         }
833
834         if (pktmbuf_pool == NULL) {
835                 printf("cannot allocate mbuf pool\n");
836                 return -1;
837         }
838
839         /* test multiple mbuf alloc */
840         if (test_pktmbuf_pool() < 0) {
841                 printf("test_mbuf_pool() failed\n");
842                 return -1;
843         }
844
845         /* do it another time to check that all mbufs were freed */
846         if (test_pktmbuf_pool() < 0) {
847                 printf("test_mbuf_pool() failed (2)\n");
848                 return -1;
849         }
850
851         /* test that the pointer to the data on a packet mbuf is set properly */
852         if (test_pktmbuf_pool_ptr() < 0) {
853                 printf("test_pktmbuf_pool_ptr() failed\n");
854                 return -1;
855         }
856
857         /* test data manipulation in mbuf */
858         if (test_one_pktmbuf() < 0) {
859                 printf("test_one_mbuf() failed\n");
860                 return -1;
861         }
862
863
864         /*
865          * do it another time, to check that allocation reinitialize
866          * the mbuf correctly
867          */
868         if (test_one_pktmbuf() < 0) {
869                 printf("test_one_mbuf() failed (2)\n");
870                 return -1;
871         }
872
873         if (test_pktmbuf_with_non_ascii_data() < 0) {
874                 printf("test_pktmbuf_with_non_ascii_data() failed\n");
875                 return -1;
876         }
877
878         /* test free pktmbuf segment one by one */
879         if (test_pktmbuf_free_segment() < 0) {
880                 printf("test_pktmbuf_free_segment() failed.\n");
881                 return -1;
882         }
883
884         if (testclone_testupdate_testdetach()<0){
885                 printf("testclone_and_testupdate() failed \n");
886                 return -1;
887         }
888
889         if (test_refcnt_mbuf()<0){
890                 printf("test_refcnt_mbuf() failed \n");
891                 return -1;
892         }
893
894         if (test_failing_mbuf_sanity_check() < 0) {
895                 printf("test_failing_mbuf_sanity_check() failed\n");
896                 return -1;
897         }
898         return 0;
899 }
900
901 static struct test_command mbuf_cmd = {
902         .command = "mbuf_autotest",
903         .callback = test_mbuf,
904 };
905 REGISTER_TEST_COMMAND(mbuf_cmd);