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