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