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