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