mbuf: replace data pointer by an offset
[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_tailq.h>
52 #include <rte_eal.h>
53 #include <rte_per_lcore.h>
54 #include <rte_lcore.h>
55 #include <rte_atomic.h>
56 #include <rte_branch_prediction.h>
57 #include <rte_ring.h>
58 #include <rte_mempool.h>
59 #include <rte_mbuf.h>
60 #include <rte_random.h>
61 #include <rte_cycles.h>
62
63 #include "test.h"
64
65 #define MBUF_SIZE               2048
66 #define NB_MBUF                 128
67 #define MBUF_TEST_DATA_LEN      1464
68 #define MBUF_TEST_DATA_LEN2     50
69 #define MBUF_TEST_HDR1_LEN      20
70 #define MBUF_TEST_HDR2_LEN      30
71 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
72
73 #define REFCNT_MAX_ITER         64
74 #define REFCNT_MAX_TIMEOUT      10
75 #define REFCNT_MAX_REF          (RTE_MAX_LCORE)
76 #define REFCNT_MBUF_NUM         64
77 #define REFCNT_MBUF_SIZE        (sizeof (struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
78 #define REFCNT_RING_SIZE        (REFCNT_MBUF_NUM * REFCNT_MAX_REF)
79
80 #define MAKE_STRING(x)          # x
81
82 static struct rte_mempool *pktmbuf_pool = NULL;
83
84 #if defined RTE_MBUF_REFCNT  && defined 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  */
128
129 #define GOTO_FAIL(str, ...) do {                                        \
130                 printf("mbuf test FAILED (l.%d): <" str ">\n",          \
131                        __LINE__,  ##__VA_ARGS__);                       \
132                 goto fail;                                              \
133 } while(0)
134
135 /*
136  * test data manipulation in mbuf with non-ascii data
137  */
138 static int
139 test_pktmbuf_with_non_ascii_data(void)
140 {
141         struct rte_mbuf *m = NULL;
142         char *data;
143
144         m = rte_pktmbuf_alloc(pktmbuf_pool);
145         if (m == NULL)
146                 GOTO_FAIL("Cannot allocate mbuf");
147         if (rte_pktmbuf_pkt_len(m) != 0)
148                 GOTO_FAIL("Bad length");
149
150         data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN);
151         if (data == NULL)
152                 GOTO_FAIL("Cannot append data");
153         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
154                 GOTO_FAIL("Bad pkt length");
155         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
156                 GOTO_FAIL("Bad data length");
157         memset(data, 0xff, rte_pktmbuf_pkt_len(m));
158         if (!rte_pktmbuf_is_contiguous(m))
159                 GOTO_FAIL("Buffer should be continuous");
160         rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN);
161
162         rte_pktmbuf_free(m);
163
164         return 0;
165
166 fail:
167         if(m) {
168                 rte_pktmbuf_free(m);
169         }
170         return -1;
171 }
172
173 /*
174  * test data manipulation in mbuf
175  */
176 static int
177 test_one_pktmbuf(void)
178 {
179         struct rte_mbuf *m = NULL;
180         char *data, *data2, *hdr;
181         unsigned i;
182
183         printf("Test pktmbuf API\n");
184
185         /* alloc a mbuf */
186
187         m = rte_pktmbuf_alloc(pktmbuf_pool);
188         if (m == NULL)
189                 GOTO_FAIL("Cannot allocate mbuf");
190         if (rte_pktmbuf_pkt_len(m) != 0)
191                 GOTO_FAIL("Bad length");
192
193         rte_pktmbuf_dump(stdout, m, 0);
194
195         /* append data */
196
197         data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN);
198         if (data == NULL)
199                 GOTO_FAIL("Cannot append data");
200         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
201                 GOTO_FAIL("Bad pkt length");
202         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
203                 GOTO_FAIL("Bad data length");
204         memset(data, 0x66, rte_pktmbuf_pkt_len(m));
205         if (!rte_pktmbuf_is_contiguous(m))
206                 GOTO_FAIL("Buffer should be continuous");
207         rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN);
208         rte_pktmbuf_dump(stdout, m, 2*MBUF_TEST_DATA_LEN);
209
210         /* this append should fail */
211
212         data2 = rte_pktmbuf_append(m, (uint16_t)(rte_pktmbuf_tailroom(m) + 1));
213         if (data2 != NULL)
214                 GOTO_FAIL("Append should not succeed");
215
216         /* append some more data */
217
218         data2 = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
219         if (data2 == NULL)
220                 GOTO_FAIL("Cannot append data");
221         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2)
222                 GOTO_FAIL("Bad pkt length");
223         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2)
224                 GOTO_FAIL("Bad data length");
225         if (!rte_pktmbuf_is_contiguous(m))
226                 GOTO_FAIL("Buffer should be continuous");
227
228         /* trim data at the end of mbuf */
229
230         if (rte_pktmbuf_trim(m, MBUF_TEST_DATA_LEN2) < 0)
231                 GOTO_FAIL("Cannot trim data");
232         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
233                 GOTO_FAIL("Bad pkt length");
234         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
235                 GOTO_FAIL("Bad data length");
236         if (!rte_pktmbuf_is_contiguous(m))
237                 GOTO_FAIL("Buffer should be continuous");
238
239         /* this trim should fail */
240
241         if (rte_pktmbuf_trim(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) == 0)
242                 GOTO_FAIL("trim should not succeed");
243
244         /* prepend one header */
245
246         hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR1_LEN);
247         if (hdr == NULL)
248                 GOTO_FAIL("Cannot prepend");
249         if (data - hdr != MBUF_TEST_HDR1_LEN)
250                 GOTO_FAIL("Prepend failed");
251         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN)
252                 GOTO_FAIL("Bad pkt length");
253         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN)
254                 GOTO_FAIL("Bad data length");
255         if (!rte_pktmbuf_is_contiguous(m))
256                 GOTO_FAIL("Buffer should be continuous");
257         memset(hdr, 0x55, MBUF_TEST_HDR1_LEN);
258
259         /* prepend another header */
260
261         hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR2_LEN);
262         if (hdr == NULL)
263                 GOTO_FAIL("Cannot prepend");
264         if (data - hdr != MBUF_TEST_ALL_HDRS_LEN)
265                 GOTO_FAIL("Prepend failed");
266         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN)
267                 GOTO_FAIL("Bad pkt length");
268         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN)
269                 GOTO_FAIL("Bad data length");
270         if (!rte_pktmbuf_is_contiguous(m))
271                 GOTO_FAIL("Buffer should be continuous");
272         memset(hdr, 0x55, MBUF_TEST_HDR2_LEN);
273
274         rte_mbuf_sanity_check(m, 1);
275         rte_mbuf_sanity_check(m, 0);
276         rte_pktmbuf_dump(stdout, m, 0);
277
278         /* this prepend should fail */
279
280         hdr = rte_pktmbuf_prepend(m, (uint16_t)(rte_pktmbuf_headroom(m) + 1));
281         if (hdr != NULL)
282                 GOTO_FAIL("prepend should not succeed");
283
284         /* remove data at beginning of mbuf (adj) */
285
286         if (data != rte_pktmbuf_adj(m, MBUF_TEST_ALL_HDRS_LEN))
287                 GOTO_FAIL("rte_pktmbuf_adj failed");
288         if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN)
289                 GOTO_FAIL("Bad pkt length");
290         if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN)
291                 GOTO_FAIL("Bad data length");
292         if (!rte_pktmbuf_is_contiguous(m))
293                 GOTO_FAIL("Buffer should be continuous");
294
295         /* this adj should fail */
296
297         if (rte_pktmbuf_adj(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) != NULL)
298                 GOTO_FAIL("rte_pktmbuf_adj should not succeed");
299
300         /* check data */
301
302         if (!rte_pktmbuf_is_contiguous(m))
303                 GOTO_FAIL("Buffer should be continuous");
304
305         for (i=0; i<MBUF_TEST_DATA_LEN; i++) {
306                 if (data[i] != 0x66)
307                         GOTO_FAIL("Data corrupted at offset %u", i);
308         }
309
310         /* free mbuf */
311
312         rte_pktmbuf_free(m);
313         m = NULL;
314         return 0;
315
316 fail:
317         if (m)
318                 rte_pktmbuf_free(m);
319         return -1;
320 }
321
322 static int
323 testclone_testupdate_testdetach(void)
324 {
325 #ifndef RTE_MBUF_REFCNT
326         return 0;
327 #else
328         struct rte_mbuf *mc = NULL;
329         struct rte_mbuf *clone = NULL;
330
331         /* alloc a mbuf */
332
333         mc = rte_pktmbuf_alloc(pktmbuf_pool);
334         if (mc == NULL)
335                 GOTO_FAIL("ooops not allocating mbuf");
336
337         if (rte_pktmbuf_pkt_len(mc) != 0)
338                 GOTO_FAIL("Bad length");
339
340
341         /* clone the allocated mbuf */
342         clone = rte_pktmbuf_clone(mc, pktmbuf_pool);
343         if (clone == NULL)
344                 GOTO_FAIL("cannot clone data\n");
345         rte_pktmbuf_free(clone);
346
347         mc->next = rte_pktmbuf_alloc(pktmbuf_pool);
348         if(mc->next == NULL)
349                 GOTO_FAIL("Next Pkt Null\n");
350
351         clone = rte_pktmbuf_clone(mc, pktmbuf_pool);
352         if (clone == NULL)
353                 GOTO_FAIL("cannot clone data\n");
354
355         /* free mbuf */
356         rte_pktmbuf_free(mc);
357         rte_pktmbuf_free(clone);
358         mc = NULL;
359         clone = NULL;
360         return 0;
361
362 fail:
363         if (mc)
364                 rte_pktmbuf_free(mc);
365         return -1;
366 #endif /* RTE_MBUF_REFCNT */
367 }
368 #undef GOTO_FAIL
369
370
371
372 /*
373  * test allocation and free of mbufs
374  */
375 static int
376 test_pktmbuf_pool(void)
377 {
378         unsigned i;
379         struct rte_mbuf *m[NB_MBUF];
380         int ret = 0;
381
382         for (i=0; i<NB_MBUF; i++)
383                 m[i] = NULL;
384
385         /* alloc NB_MBUF mbufs */
386         for (i=0; i<NB_MBUF; i++) {
387                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
388                 if (m[i] == NULL) {
389                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
390                         ret = -1;
391                 }
392         }
393         struct rte_mbuf *extra = NULL;
394         extra = rte_pktmbuf_alloc(pktmbuf_pool);
395         if(extra != NULL) {
396                 printf("Error pool not empty");
397                 ret = -1;
398         }
399 #ifdef RTE_MBUF_REFCNT
400         extra = rte_pktmbuf_clone(m[0], pktmbuf_pool);
401         if(extra != NULL) {
402                 printf("Error pool not empty");
403                 ret = -1;
404         }
405 #endif
406         /* free them */
407         for (i=0; i<NB_MBUF; i++) {
408                 if (m[i] != NULL)
409                         rte_pktmbuf_free(m[i]);
410         }
411
412         return ret;
413 }
414
415 /*
416  * test that the pointer to the data on a packet mbuf is set properly
417  */
418 static int
419 test_pktmbuf_pool_ptr(void)
420 {
421         unsigned i;
422         struct rte_mbuf *m[NB_MBUF];
423         int ret = 0;
424
425         for (i=0; i<NB_MBUF; i++)
426                 m[i] = NULL;
427
428         /* alloc NB_MBUF mbufs */
429         for (i=0; i<NB_MBUF; i++) {
430                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
431                 if (m[i] == NULL) {
432                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
433                         ret = -1;
434                 }
435                 m[i]->data_off += 64;
436         }
437
438         /* free them */
439         for (i=0; i<NB_MBUF; i++) {
440                 if (m[i] != NULL)
441                         rte_pktmbuf_free(m[i]);
442         }
443
444         for (i=0; i<NB_MBUF; i++)
445                 m[i] = NULL;
446
447         /* alloc NB_MBUF mbufs */
448         for (i=0; i<NB_MBUF; i++) {
449                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
450                 if (m[i] == NULL) {
451                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
452                         ret = -1;
453                 }
454                 if (m[i]->data_off != RTE_PKTMBUF_HEADROOM) {
455                         printf("invalid data_off\n");
456                         ret = -1;
457                 }
458         }
459
460         /* free them */
461         for (i=0; i<NB_MBUF; i++) {
462                 if (m[i] != NULL)
463                         rte_pktmbuf_free(m[i]);
464         }
465
466         return ret;
467 }
468
469 static int
470 test_pktmbuf_free_segment(void)
471 {
472         unsigned i;
473         struct rte_mbuf *m[NB_MBUF];
474         int ret = 0;
475
476         for (i=0; i<NB_MBUF; i++)
477                 m[i] = NULL;
478
479         /* alloc NB_MBUF mbufs */
480         for (i=0; i<NB_MBUF; i++) {
481                 m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
482                 if (m[i] == NULL) {
483                         printf("rte_pktmbuf_alloc() failed (%u)\n", i);
484                         ret = -1;
485                 }
486         }
487
488         /* free them */
489         for (i=0; i<NB_MBUF; i++) {
490                 if (m[i] != NULL) {
491                         struct rte_mbuf *mb, *mt;
492
493                         mb = m[i];
494                         while(mb != NULL) {
495                                 mt = mb;
496                                 mb = mb->next;
497                                 rte_pktmbuf_free_seg(mt);
498                         }
499                 }
500         }
501
502         return ret;
503 }
504
505 /*
506  * Stress test for rte_mbuf atomic refcnt.
507  * Implies that:
508  * RTE_MBUF_REFCNT and RTE_MBUF_REFCNT_ATOMIC are both defined.
509  * For more efficency, recomended to run with RTE_LIBRTE_MBUF_DEBUG defined.
510  */
511
512 #if defined RTE_MBUF_REFCNT  && defined RTE_MBUF_REFCNT_ATOMIC
513
514 static int
515 test_refcnt_slave(__attribute__((unused)) void *arg)
516 {
517         unsigned lcore, free;
518         void *mp = 0;
519
520         lcore = rte_lcore_id();
521         printf("%s started at lcore %u\n", __func__, lcore);
522
523         free = 0;
524         while (refcnt_stop_slaves == 0) {
525                 if (rte_ring_dequeue(refcnt_mbuf_ring, &mp) == 0) {
526                         free++;
527                         rte_pktmbuf_free((struct rte_mbuf *)mp);
528                 }
529         }
530
531         refcnt_lcore[lcore] += free;
532         printf("%s finished at lcore %u, "
533                "number of freed mbufs: %u\n",
534                __func__, lcore, free);
535         return (0);
536 }
537
538 static void
539 test_refcnt_iter(unsigned lcore, unsigned iter)
540 {
541         uint16_t ref;
542         unsigned i, n, tref, wn;
543         struct rte_mbuf *m;
544
545         tref = 0;
546
547         /* For each mbuf in the pool:
548          * - allocate mbuf,
549          * - increment it's reference up to N+1,
550          * - enqueue it N times into the ring for slave cores to free.
551          */
552         for (i = 0, n = rte_mempool_count(refcnt_pool);
553             i != n && (m = rte_pktmbuf_alloc(refcnt_pool)) != NULL;
554             i++) {
555                 ref = RTE_MAX(rte_rand() % REFCNT_MAX_REF, 1UL);
556                 tref += ref;
557                 if ((ref & 1) != 0) {
558                         rte_pktmbuf_refcnt_update(m, ref);
559                         while (ref-- != 0)
560                                 rte_ring_enqueue(refcnt_mbuf_ring, m);
561                 } else {
562                         while (ref-- != 0) {
563                                 rte_pktmbuf_refcnt_update(m, 1);
564                                 rte_ring_enqueue(refcnt_mbuf_ring, m);
565                         }
566                 }
567                 rte_pktmbuf_free(m);
568         }
569
570         if (i != n)
571                 rte_panic("(lcore=%u, iter=%u): was able to allocate only "
572                           "%u from %u mbufs\n", lcore, iter, i, n);
573
574         /* wait till slave lcores  will consume all mbufs */
575         while (!rte_ring_empty(refcnt_mbuf_ring))
576                 ;
577
578         /* check that all mbufs are back into mempool by now */
579         for (wn = 0; wn != REFCNT_MAX_TIMEOUT; wn++) {
580                 if ((i = rte_mempool_count(refcnt_pool)) == n) {
581                         refcnt_lcore[lcore] += tref;
582                         printf("%s(lcore=%u, iter=%u) completed, "
583                             "%u references processed\n",
584                             __func__, lcore, iter, tref);
585                         return;
586                 }
587                 rte_delay_ms(1000);
588         }
589
590         rte_panic("(lcore=%u, iter=%u): after %us only "
591                   "%u of %u mbufs left free\n", lcore, iter, wn, i, n);
592 }
593
594 static int
595 test_refcnt_master(void)
596 {
597         unsigned i, lcore;
598
599         lcore = rte_lcore_id();
600         printf("%s started at lcore %u\n", __func__, lcore);
601
602         for (i = 0; i != REFCNT_MAX_ITER; i++)
603                 test_refcnt_iter(lcore, i);
604
605         refcnt_stop_slaves = 1;
606         rte_wmb();
607
608         printf("%s finished at lcore %u\n", __func__, lcore);
609         return (0);
610 }
611
612 #endif
613
614 static int
615 test_refcnt_mbuf(void)
616 {
617 #if defined RTE_MBUF_REFCNT  && defined RTE_MBUF_REFCNT_ATOMIC
618
619         unsigned lnum, master, slave, tref;
620
621
622         if ((lnum = rte_lcore_count()) == 1) {
623                 printf("skipping %s, number of lcores: %u is not enough\n",
624                     __func__, lnum);
625                 return (0);
626         }
627
628         printf("starting %s, at %u lcores\n", __func__, lnum);
629
630         /* create refcnt pool & ring if they don't exist */
631
632         if (refcnt_pool == NULL &&
633                         (refcnt_pool = rte_mempool_create(
634                         MAKE_STRING(refcnt_pool),
635                         REFCNT_MBUF_NUM, REFCNT_MBUF_SIZE, 0,
636                         sizeof(struct rte_pktmbuf_pool_private),
637                         rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
638                         SOCKET_ID_ANY, 0)) == NULL) {
639                 printf("%s: cannot allocate " MAKE_STRING(refcnt_pool) "\n",
640                     __func__);
641                 return (-1);
642         }
643
644         if (refcnt_mbuf_ring == NULL &&
645                         (refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring",
646                         REFCNT_RING_SIZE, SOCKET_ID_ANY,
647                         RING_F_SP_ENQ)) == NULL) {
648                 printf("%s: cannot allocate " MAKE_STRING(refcnt_mbuf_ring)
649                     "\n", __func__);
650                 return (-1);
651         }
652
653         refcnt_stop_slaves = 0;
654         memset(refcnt_lcore, 0, sizeof (refcnt_lcore));
655
656         rte_eal_mp_remote_launch(test_refcnt_slave, NULL, SKIP_MASTER);
657
658         test_refcnt_master();
659
660         rte_eal_mp_wait_lcore();
661
662         /* check that we porcessed all references */
663         tref = 0;
664         master = rte_get_master_lcore();
665
666         RTE_LCORE_FOREACH_SLAVE(slave)
667                 tref += refcnt_lcore[slave];
668
669         if (tref != refcnt_lcore[master])
670                 rte_panic("refernced mbufs: %u, freed mbufs: %u\n",
671                           tref, refcnt_lcore[master]);
672
673         rte_mempool_dump(stdout, refcnt_pool);
674         rte_ring_dump(stdout, refcnt_mbuf_ring);
675
676 #endif
677         return (0);
678 }
679
680 #ifdef RTE_EXEC_ENV_BAREMETAL
681
682 /* baremetal - don't test failing sanity checks */
683 static int
684 test_failing_mbuf_sanity_check(void)
685 {
686         return 0;
687 }
688
689 #else
690
691 #include <unistd.h>
692 #include <sys/wait.h>
693
694 /* linuxapp - use fork() to test mbuf errors panic */
695 static int
696 verify_mbuf_check_panics(struct rte_mbuf *buf)
697 {
698         int pid;
699         int status;
700
701         pid = fork();
702
703         if (pid == 0) {
704                 rte_mbuf_sanity_check(buf, 1); /* should panic */
705                 exit(0);  /* return normally if it doesn't panic */
706         } else if (pid < 0){
707                 printf("Fork Failed\n");
708                 return -1;
709         }
710         wait(&status);
711         if(status == 0)
712                 return -1;
713
714         return 0;
715 }
716
717 static int
718 test_failing_mbuf_sanity_check(void)
719 {
720         struct rte_mbuf *buf;
721         struct rte_mbuf badbuf;
722
723         printf("Checking rte_mbuf_sanity_check for failure conditions\n");
724
725         /* get a good mbuf to use to make copies */
726         buf = rte_pktmbuf_alloc(pktmbuf_pool);
727         if (buf == NULL)
728                 return -1;
729         printf("Checking good mbuf initially\n");
730         if (verify_mbuf_check_panics(buf) != -1)
731                 return -1;
732
733         printf("Now checking for error conditions\n");
734
735         if (verify_mbuf_check_panics(NULL)) {
736                 printf("Error with NULL mbuf test\n");
737                 return -1;
738         }
739
740         badbuf = *buf;
741         badbuf.pool = NULL;
742         if (verify_mbuf_check_panics(&badbuf)) {
743                 printf("Error with bad-pool mbuf test\n");
744                 return -1;
745         }
746
747         badbuf = *buf;
748         badbuf.buf_physaddr = 0;
749         if (verify_mbuf_check_panics(&badbuf)) {
750                 printf("Error with bad-physaddr mbuf test\n");
751                 return -1;
752         }
753
754         badbuf = *buf;
755         badbuf.buf_addr = NULL;
756         if (verify_mbuf_check_panics(&badbuf)) {
757                 printf("Error with bad-addr mbuf test\n");
758                 return -1;
759         }
760
761 #ifdef RTE_MBUF_REFCNT
762         badbuf = *buf;
763         badbuf.refcnt = 0;
764         if (verify_mbuf_check_panics(&badbuf)) {
765                 printf("Error with bad-refcnt(0) mbuf test\n");
766                 return -1;
767         }
768
769         badbuf = *buf;
770         badbuf.refcnt = UINT16_MAX;
771         if (verify_mbuf_check_panics(&badbuf)) {
772                 printf("Error with bad-refcnt(MAX) mbuf test\n");
773                 return -1;
774         }
775 #endif
776
777         return 0;
778 }
779 #endif
780
781
782 static int
783 test_mbuf(void)
784 {
785         RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != 64);
786
787         /* create pktmbuf pool if it does not exist */
788         if (pktmbuf_pool == NULL) {
789                 pktmbuf_pool =
790                         rte_mempool_create("test_pktmbuf_pool", NB_MBUF,
791                                            MBUF_SIZE, 32,
792                                            sizeof(struct rte_pktmbuf_pool_private),
793                                            rte_pktmbuf_pool_init, NULL,
794                                            rte_pktmbuf_init, NULL,
795                                            SOCKET_ID_ANY, 0);
796         }
797
798         if (pktmbuf_pool == NULL) {
799                 printf("cannot allocate mbuf pool\n");
800                 return -1;
801         }
802
803         /* test multiple mbuf alloc */
804         if (test_pktmbuf_pool() < 0) {
805                 printf("test_mbuf_pool() failed\n");
806                 return -1;
807         }
808
809         /* do it another time to check that all mbufs were freed */
810         if (test_pktmbuf_pool() < 0) {
811                 printf("test_mbuf_pool() failed (2)\n");
812                 return -1;
813         }
814
815         /* test that the pointer to the data on a packet mbuf is set properly */
816         if (test_pktmbuf_pool_ptr() < 0) {
817                 printf("test_pktmbuf_pool_ptr() failed\n");
818                 return -1;
819         }
820
821         /* test data manipulation in mbuf */
822         if (test_one_pktmbuf() < 0) {
823                 printf("test_one_mbuf() failed\n");
824                 return -1;
825         }
826
827
828         /*
829          * do it another time, to check that allocation reinitialize
830          * the mbuf correctly
831          */
832         if (test_one_pktmbuf() < 0) {
833                 printf("test_one_mbuf() failed (2)\n");
834                 return -1;
835         }
836
837         if (test_pktmbuf_with_non_ascii_data() < 0) {
838                 printf("test_pktmbuf_with_non_ascii_data() failed\n");
839                 return -1;
840         }
841
842         /* test free pktmbuf segment one by one */
843         if (test_pktmbuf_free_segment() < 0) {
844                 printf("test_pktmbuf_free_segment() failed.\n");
845                 return -1;
846         }
847
848         if (testclone_testupdate_testdetach()<0){
849                 printf("testclone_and_testupdate() failed \n");
850                 return -1;
851         }
852
853         if (test_refcnt_mbuf()<0){
854                 printf("test_refcnt_mbuf() failed \n");
855                 return -1;
856         }
857
858         if (test_failing_mbuf_sanity_check() < 0) {
859                 printf("test_failing_mbuf_sanity_check() failed\n");
860                 return -1;
861         }
862         return 0;
863 }
864
865 static struct test_command mbuf_cmd = {
866         .command = "mbuf_autotest",
867         .callback = test_mbuf,
868 };
869 REGISTER_TEST_COMMAND(mbuf_cmd);