test/security: add inline inbound IPsec cases
[dpdk.git] / app / test / test_malloc.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2019 Intel Corporation
3  */
4
5 #include "test.h"
6
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #ifndef RTE_EXEC_ENV_WINDOWS
14 #include <sys/mman.h>
15 #endif
16 #include <sys/queue.h>
17 #include <unistd.h>
18
19 #include <rte_common.h>
20 #include <rte_memory.h>
21 #include <rte_per_lcore.h>
22 #include <rte_launch.h>
23 #include <rte_eal.h>
24 #include <rte_lcore.h>
25 #include <rte_malloc.h>
26 #include <rte_cycles.h>
27 #include <rte_random.h>
28 #include <rte_string_fns.h>
29
30 #define N 10000
31
32 static int
33 is_mem_on_socket(int32_t socket);
34
35 static int32_t
36 addr_to_socket(void *addr);
37
38 /*
39  * Malloc
40  * ======
41  *
42  * Allocate some dynamic memory from heap (3 areas). Check that areas
43  * don't overlap and that alignment constraints match. This test is
44  * done many times on different lcores simultaneously.
45  */
46
47 /* Test if memory overlaps: return 1 if true, or 0 if false. */
48 static int
49 is_memory_overlap(void *p1, size_t len1, void *p2, size_t len2)
50 {
51         uintptr_t ptr1 = (uintptr_t)p1;
52         uintptr_t ptr2 = (uintptr_t)p2;
53
54         if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1)
55                 return 1;
56         else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2)
57                 return 1;
58         return 0;
59 }
60
61 static int
62 is_aligned(void *p, int align)
63 {
64         uintptr_t addr = (uintptr_t)p;
65         unsigned mask = align - 1;
66
67         if (addr & mask)
68                 return 0;
69         return 1;
70 }
71
72 static int
73 test_align_overlap_per_lcore(__rte_unused void *arg)
74 {
75         const unsigned align1 = 8,
76                         align2 = 64,
77                         align3 = 2048;
78         unsigned i,j;
79         void *p1 = NULL, *p2 = NULL, *p3 = NULL;
80         int ret = 0;
81
82         for (i = 0; i < N; i++) {
83                 p1 = rte_zmalloc("dummy", 1000, align1);
84                 if (!p1){
85                         printf("rte_zmalloc returned NULL (i=%u)\n", i);
86                         ret = -1;
87                         break;
88                 }
89                 for(j = 0; j < 1000 ; j++) {
90                         if( *(char *)p1 != 0) {
91                                 printf("rte_zmalloc didn't zero the allocated memory\n");
92                                 ret = -1;
93                         }
94                 }
95                 p2 = rte_malloc("dummy", 1000, align2);
96                 if (!p2){
97                         printf("rte_malloc returned NULL (i=%u)\n", i);
98                         ret = -1;
99                         rte_free(p1);
100                         break;
101                 }
102                 p3 = rte_malloc("dummy", 1000, align3);
103                 if (!p3){
104                         printf("rte_malloc returned NULL (i=%u)\n", i);
105                         ret = -1;
106                         rte_free(p1);
107                         rte_free(p2);
108                         break;
109                 }
110                 if (is_memory_overlap(p1, 1000, p2, 1000)) {
111                         printf("p1 and p2 overlaps\n");
112                         ret = -1;
113                 }
114                 if (is_memory_overlap(p2, 1000, p3, 1000)) {
115                         printf("p2 and p3 overlaps\n");
116                         ret = -1;
117                 }
118                 if (is_memory_overlap(p1, 1000, p3, 1000)) {
119                         printf("p1 and p3 overlaps\n");
120                         ret = -1;
121                 }
122                 if (!is_aligned(p1, align1)) {
123                         printf("p1 is not aligned\n");
124                         ret = -1;
125                 }
126                 if (!is_aligned(p2, align2)) {
127                         printf("p2 is not aligned\n");
128                         ret = -1;
129                 }
130                 if (!is_aligned(p3, align3)) {
131                         printf("p3 is not aligned\n");
132                         ret = -1;
133                 }
134                 rte_free(p1);
135                 rte_free(p2);
136                 rte_free(p3);
137         }
138         rte_malloc_dump_stats(stdout, "dummy");
139
140         return ret;
141 }
142
143 static int
144 test_reordered_free_per_lcore(__rte_unused void *arg)
145 {
146         const unsigned align1 = 8,
147                         align2 = 64,
148                         align3 = 2048;
149         unsigned i,j;
150         void *p1, *p2, *p3;
151         int ret = 0;
152
153         for (i = 0; i < 30; i++) {
154                 p1 = rte_zmalloc("dummy", 1000, align1);
155                 if (!p1){
156                         printf("rte_zmalloc returned NULL (i=%u)\n", i);
157                         ret = -1;
158                         break;
159                 }
160                 for(j = 0; j < 1000 ; j++) {
161                         if( *(char *)p1 != 0) {
162                                 printf("rte_zmalloc didn't zero the allocated memory\n");
163                                 ret = -1;
164                         }
165                 }
166                 /* use calloc to allocate 1000 16-byte items this time */
167                 p2 = rte_calloc("dummy", 1000, 16, align2);
168                 /* for third request use regular malloc again */
169                 p3 = rte_malloc("dummy", 1000, align3);
170                 if (!p2 || !p3){
171                         printf("rte_malloc returned NULL (i=%u)\n", i);
172                         ret = -1;
173                         break;
174                 }
175                 if (is_memory_overlap(p1, 1000, p2, 1000)) {
176                         printf("p1 and p2 overlaps\n");
177                         ret = -1;
178                 }
179                 if (is_memory_overlap(p2, 1000, p3, 1000)) {
180                         printf("p2 and p3 overlaps\n");
181                         ret = -1;
182                 }
183                 if (is_memory_overlap(p1, 1000, p3, 1000)) {
184                         printf("p1 and p3 overlaps\n");
185                         ret = -1;
186                 }
187                 if (!is_aligned(p1, align1)) {
188                         printf("p1 is not aligned\n");
189                         ret = -1;
190                 }
191                 if (!is_aligned(p2, align2)) {
192                         printf("p2 is not aligned\n");
193                         ret = -1;
194                 }
195                 if (!is_aligned(p3, align3)) {
196                         printf("p3 is not aligned\n");
197                         ret = -1;
198                 }
199                 /* try freeing in every possible order */
200                 switch (i%6){
201                 case 0:
202                         rte_free(p1);
203                         rte_free(p2);
204                         rte_free(p3);
205                         break;
206                 case 1:
207                         rte_free(p1);
208                         rte_free(p3);
209                         rte_free(p2);
210                         break;
211                 case 2:
212                         rte_free(p2);
213                         rte_free(p1);
214                         rte_free(p3);
215                         break;
216                 case 3:
217                         rte_free(p2);
218                         rte_free(p3);
219                         rte_free(p1);
220                         break;
221                 case 4:
222                         rte_free(p3);
223                         rte_free(p1);
224                         rte_free(p2);
225                         break;
226                 case 5:
227                         rte_free(p3);
228                         rte_free(p2);
229                         rte_free(p1);
230                         break;
231                 }
232         }
233         rte_malloc_dump_stats(stdout, "dummy");
234
235         return ret;
236 }
237
238 /* test function inside the malloc lib*/
239 static int
240 test_str_to_size(void)
241 {
242         struct {
243                 const char *str;
244                 uint64_t value;
245         } test_values[] =
246         {{ "5G", (uint64_t)5 * 1024 * 1024 *1024 },
247                         {"0x20g", (uint64_t)0x20 * 1024 * 1024 *1024},
248                         {"10M", 10 * 1024 * 1024},
249                         {"050m", 050 * 1024 * 1024},
250                         {"8K", 8 * 1024},
251                         {"15k", 15 * 1024},
252                         {"0200", 0200},
253                         {"0x103", 0x103},
254                         {"432", 432},
255                         {"-1", 0}, /* negative values return 0 */
256                         {"  -2", 0},
257                         {"  -3MB", 0},
258                         {"18446744073709551616", 0} /* ULLONG_MAX + 1 == out of range*/
259         };
260         unsigned i;
261         for (i = 0; i < RTE_DIM(test_values); i++)
262                 if (rte_str_to_size(test_values[i].str) != test_values[i].value)
263                         return -1;
264         return 0;
265 }
266
267 static int
268 test_multi_alloc_statistics(void)
269 {
270         int socket = 0;
271         struct rte_malloc_socket_stats pre_stats, post_stats ,first_stats, second_stats;
272         size_t size = 2048;
273         int align = 1024;
274         int overhead = 0;
275
276         /* Dynamically calculate the overhead by allocating one cacheline and
277          * then comparing what was allocated from the heap.
278          */
279         rte_malloc_get_socket_stats(socket, &pre_stats);
280
281         void *dummy = rte_malloc_socket(NULL, RTE_CACHE_LINE_SIZE, 0, socket);
282         if (dummy == NULL)
283                 return -1;
284
285         rte_malloc_get_socket_stats(socket, &post_stats);
286
287         /* after subtracting cache line, remainder is overhead */
288         overhead = post_stats.heap_allocsz_bytes - pre_stats.heap_allocsz_bytes;
289         overhead -= RTE_CACHE_LINE_SIZE;
290
291         rte_free(dummy);
292
293         /* Now start the real tests */
294         rte_malloc_get_socket_stats(socket, &pre_stats);
295
296         void *p1 = rte_malloc_socket("stats", size , align, socket);
297         if (!p1)
298                 return -1;
299         rte_free(p1);
300         rte_malloc_dump_stats(stdout, "stats");
301
302         rte_malloc_get_socket_stats(socket,&post_stats);
303         /* Check statistics reported are correct */
304         /* All post stats should be equal to pre stats after alloc freed */
305         if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) &&
306                         (post_stats.heap_freesz_bytes!=pre_stats.heap_freesz_bytes) &&
307                         (post_stats.heap_allocsz_bytes!=pre_stats.heap_allocsz_bytes)&&
308                         (post_stats.alloc_count!=pre_stats.alloc_count)&&
309                         (post_stats.free_count!=pre_stats.free_count)) {
310                 printf("Malloc statistics are incorrect - freed alloc\n");
311                 return -1;
312         }
313         /* Check two consecutive allocations */
314         size = 1024;
315         align = 0;
316         rte_malloc_get_socket_stats(socket,&pre_stats);
317         void *p2 = rte_malloc_socket("add", size ,align, socket);
318         if (!p2)
319                 return -1;
320         rte_malloc_get_socket_stats(socket,&first_stats);
321
322         void *p3 = rte_malloc_socket("add2", size,align, socket);
323         if (!p3)
324                 return -1;
325
326         rte_malloc_get_socket_stats(socket,&second_stats);
327
328         rte_free(p2);
329         rte_free(p3);
330
331         /* After freeing both allocations check stats return to original */
332         rte_malloc_get_socket_stats(socket, &post_stats);
333
334         if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) {
335                 printf("Incorrect heap statistics: Total size \n");
336                 return -1;
337         }
338         /* Check allocated size is equal to two additions plus overhead */
339         if(second_stats.heap_allocsz_bytes !=
340                         size + overhead + first_stats.heap_allocsz_bytes) {
341                 printf("Incorrect heap statistics: Allocated size \n");
342                 return -1;
343         }
344         /* Check that allocation count increments correctly i.e. +1 */
345         if (second_stats.alloc_count != first_stats.alloc_count + 1) {
346                 printf("Incorrect heap statistics: Allocated count \n");
347                 return -1;
348         }
349
350         if (second_stats.free_count != first_stats.free_count){
351                 printf("Incorrect heap statistics: Free count \n");
352                 return -1;
353         }
354
355         /* Make sure that we didn't touch our greatest chunk: 2 * 11M)  */
356         if (post_stats.greatest_free_size != pre_stats.greatest_free_size) {
357                 printf("Incorrect heap statistics: Greatest free size \n");
358                 return -1;
359         }
360         /* Free size must equal the original free size minus the new allocation*/
361         if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) {
362                 printf("Incorrect heap statistics: Free size \n");
363                 return -1;
364         }
365
366         if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) &&
367                         (post_stats.heap_freesz_bytes!=pre_stats.heap_freesz_bytes) &&
368                         (post_stats.heap_allocsz_bytes!=pre_stats.heap_allocsz_bytes)&&
369                         (post_stats.alloc_count!=pre_stats.alloc_count)&&
370                         (post_stats.free_count!=pre_stats.free_count)) {
371                 printf("Malloc statistics are incorrect - freed alloc\n");
372                 return -1;
373         }
374         return 0;
375 }
376
377 #ifdef RTE_EXEC_ENV_WINDOWS
378 static int
379 test_realloc(void)
380 {
381         return TEST_SKIPPED;
382 }
383 #else
384
385 static int
386 test_realloc_socket(int socket)
387 {
388         const char hello_str[] = "Hello, world!";
389         const unsigned size1 = 1024;
390         const unsigned size2 = size1 + 1024;
391         const unsigned size3 = size2;
392         const unsigned size4 = size3 + 1024;
393
394         /* test data is the same even if element is moved*/
395         char *ptr1 = rte_zmalloc_socket(
396                         NULL, size1, RTE_CACHE_LINE_SIZE, socket);
397         if (!ptr1){
398                 printf("NULL pointer returned from rte_zmalloc\n");
399                 return -1;
400         }
401         strlcpy(ptr1, hello_str, size1);
402         char *ptr2 = rte_realloc_socket(
403                         ptr1, size2, RTE_CACHE_LINE_SIZE, socket);
404         if (!ptr2){
405                 rte_free(ptr1);
406                 printf("NULL pointer returned from rte_realloc\n");
407                 return -1;
408         }
409         if (ptr1 == ptr2){
410                 printf("unexpected - ptr1 == ptr2\n");
411         }
412         if (strcmp(ptr2, hello_str) != 0){
413                 printf("Error - lost data from pointed area\n");
414                 rte_free(ptr2);
415                 return -1;
416         }
417         unsigned i;
418         for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++)
419                 if (ptr2[i] != 0){
420                         printf("Bad data in realloc\n");
421                         rte_free(ptr2);
422                         return -1;
423                 }
424         /* now allocate third element, free the second
425          * and resize third. It should not move. (ptr1 is now invalid)
426          */
427         char *ptr3 = rte_zmalloc_socket(
428                         NULL, size3, RTE_CACHE_LINE_SIZE, socket);
429         if (!ptr3){
430                 printf("NULL pointer returned from rte_zmalloc\n");
431                 rte_free(ptr2);
432                 return -1;
433         }
434         for (i = 0; i < size3; i++)
435                 if (ptr3[i] != 0){
436                         printf("Bad data in zmalloc\n");
437                         rte_free(ptr3);
438                         rte_free(ptr2);
439                         return -1;
440                 }
441         rte_free(ptr2);
442         /* first resize to half the size of the freed block */
443         char *ptr4 = rte_realloc_socket(
444                         ptr3, size4, RTE_CACHE_LINE_SIZE, socket);
445         if (!ptr4){
446                 printf("NULL pointer returned from rte_realloc\n");
447                 rte_free(ptr3);
448                 return -1;
449         }
450         if (ptr3 != ptr4){
451                 printf("Unexpected - ptr4 != ptr3\n");
452                 rte_free(ptr4);
453                 return -1;
454         }
455         /* now resize again to the full size of the freed block */
456         ptr4 = rte_realloc_socket(ptr3, size3 + size2 + size1,
457                         RTE_CACHE_LINE_SIZE, socket);
458         if (ptr3 != ptr4){
459                 printf("Unexpected - ptr4 != ptr3 on second resize\n");
460                 rte_free(ptr4);
461                 return -1;
462         }
463         rte_free(ptr4);
464
465         /* now try a resize to a smaller size, see if it works */
466         const unsigned size5 = 1024;
467         const unsigned size6 = size5 / 2;
468         char *ptr5 = rte_malloc_socket(
469                         NULL, size5, RTE_CACHE_LINE_SIZE, socket);
470         if (!ptr5){
471                 printf("NULL pointer returned from rte_malloc\n");
472                 return -1;
473         }
474         char *ptr6 = rte_realloc_socket(
475                         ptr5, size6, RTE_CACHE_LINE_SIZE, socket);
476         if (!ptr6){
477                 printf("NULL pointer returned from rte_realloc\n");
478                 rte_free(ptr5);
479                 return -1;
480         }
481         if (ptr5 != ptr6){
482                 printf("Error, resizing to a smaller size moved data\n");
483                 rte_free(ptr6);
484                 return -1;
485         }
486         rte_free(ptr6);
487
488         /* check for behaviour changing alignment */
489         const unsigned size7 = 1024;
490         const unsigned orig_align = RTE_CACHE_LINE_SIZE;
491         unsigned new_align = RTE_CACHE_LINE_SIZE * 2;
492         char *ptr7 = rte_malloc_socket(NULL, size7, orig_align, socket);
493         if (!ptr7){
494                 printf("NULL pointer returned from rte_malloc\n");
495                 return -1;
496         }
497         /* calc an alignment we don't already have */
498         while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7)
499                 new_align *= 2;
500         char *ptr8 = rte_realloc_socket(ptr7, size7, new_align, socket);
501         if (!ptr8){
502                 printf("NULL pointer returned from rte_realloc\n");
503                 rte_free(ptr7);
504                 return -1;
505         }
506         if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){
507                 printf("Failure to re-align data\n");
508                 rte_free(ptr8);
509                 return -1;
510         }
511         rte_free(ptr8);
512
513         /* test behaviour when there is a free block after current one,
514          * but its not big enough
515          */
516         unsigned size9 = 1024, size10 = 1024;
517         unsigned size11 = size9 + size10 + 256;
518         char *ptr9 = rte_malloc_socket(
519                         NULL, size9, RTE_CACHE_LINE_SIZE, socket);
520         if (!ptr9){
521                 printf("NULL pointer returned from rte_malloc\n");
522                 return -1;
523         }
524         char *ptr10 = rte_malloc_socket(
525                         NULL, size10, RTE_CACHE_LINE_SIZE, socket);
526         if (!ptr10){
527                 printf("NULL pointer returned from rte_malloc\n");
528                 return -1;
529         }
530         rte_free(ptr9);
531         char *ptr11 = rte_realloc_socket(
532                         ptr10, size11, RTE_CACHE_LINE_SIZE, socket);
533         if (!ptr11){
534                 printf("NULL pointer returned from rte_realloc\n");
535                 rte_free(ptr10);
536                 return -1;
537         }
538         if (ptr11 == ptr10){
539                 printf("Error, unexpected that realloc has not created new buffer\n");
540                 rte_free(ptr11);
541                 return -1;
542         }
543         rte_free(ptr11);
544
545         /* check we don't crash if we pass null to realloc
546          * We should get a malloc of the size requested*/
547         const size_t size12 = 1024;
548         size_t size12_check;
549         char *ptr12 = rte_realloc_socket(
550                         NULL, size12, RTE_CACHE_LINE_SIZE, socket);
551         if (!ptr12){
552                 printf("NULL pointer returned from rte_realloc\n");
553                 return -1;
554         }
555         if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
556                         size12_check != size12){
557                 rte_free(ptr12);
558                 return -1;
559         }
560         rte_free(ptr12);
561
562         /* do the same, but for regular memory */
563         ptr12 = rte_realloc(NULL, size12, RTE_CACHE_LINE_SIZE);
564         if (!ptr12) {
565                 printf("NULL pointer returned from rte_realloc\n");
566                 return -1;
567         }
568         if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
569                         size12_check != size12) {
570                 rte_free(ptr12);
571                 return -1;
572         }
573         rte_free(ptr12);
574
575         return 0;
576 }
577
578 static int
579 test_realloc_numa(void)
580 {
581         /* check realloc_socket part */
582         int32_t socket_count = 0, socket_allocated, socket;
583         void *ptr1, *ptr2;
584         int ret = -1;
585         size_t size = 1024;
586
587         ptr1 = NULL;
588         for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
589                 if (is_mem_on_socket(socket)) {
590                         int j = 2;
591
592                         socket_count++;
593                         while (j--) {
594                                 /* j == 1 -> resizing */
595                                 ptr2 = rte_realloc_socket(ptr1, size,
596                                                           RTE_CACHE_LINE_SIZE,
597                                                           socket);
598                                 if (ptr2 == NULL) {
599                                         printf("NULL pointer returned from rte_realloc_socket\n");
600                                         goto end;
601                                 }
602
603                                 ptr1 = ptr2;
604                                 socket_allocated = addr_to_socket(ptr2);
605                                 if (socket_allocated != socket) {
606                                         printf("Requested socket (%d) doesn't mach allocated one (%d)\n",
607                                                socket, socket_allocated);
608                                         goto end;
609                                 }
610                                 size += RTE_CACHE_LINE_SIZE;
611                         }
612                 }
613         }
614
615         /* Print warning if only a single socket, but don't fail the test */
616         if (socket_count < 2)
617                 printf("WARNING: realloc_socket test needs memory on multiple sockets!\n");
618
619         ret = 0;
620 end:
621         rte_free(ptr1);
622         return ret;
623 }
624
625 static int
626 test_realloc(void)
627 {
628         const char *heap_name = "realloc_heap";
629         int realloc_heap_socket;
630         unsigned int mem_sz = 1U << 13; /* 8K */
631         unsigned int page_sz = sysconf(_SC_PAGESIZE);
632         void *mem;
633         int ret;
634
635         /* page size may be bigger than total mem size, so adjust */
636         mem_sz = RTE_MAX(mem_sz, page_sz);
637
638         /*
639          * the realloc tests depend on specific layout of underlying memory, so
640          * to prevent accidental failures to do fragmented main heap, we will
641          * do all of our tests on an artificially created memory.
642          */
643         if (rte_malloc_heap_create(heap_name) != 0) {
644                 printf("Failed to create external heap\n");
645                 ret = -1;
646                 goto end;
647         }
648         realloc_heap_socket = rte_malloc_heap_get_socket(heap_name);
649
650         mem = mmap(NULL, mem_sz, PROT_READ | PROT_WRITE,
651                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
652         if (mem == MAP_FAILED) {
653                 printf("Failed to allocate memory for external heap\n");
654                 ret = -1;
655                 goto heap_destroy;
656         }
657
658         if (rte_malloc_heap_memory_add(
659                         heap_name, mem, mem_sz, NULL, 0, page_sz) != 0) {
660                 printf("Failed to add memory to external heap\n");
661                 ret = -1;
662                 goto mem_free;
663         }
664
665         /* run the socket-bound tests */
666         ret = test_realloc_socket(realloc_heap_socket);
667         if (ret != 0)
668                 goto mem_remove;
669
670         /* now, run the NUMA node tests */
671         ret = test_realloc_numa();
672
673 mem_remove:
674         rte_malloc_heap_memory_remove(heap_name, mem, mem_sz);
675 mem_free:
676         munmap(mem, mem_sz);
677 heap_destroy:
678         rte_malloc_heap_destroy(heap_name);
679 end:
680         return ret;
681 }
682
683 #endif /* !RTE_EXEC_ENV_WINDOWS */
684
685 static int
686 test_random_alloc_free(void *_ __rte_unused)
687 {
688         struct mem_list {
689                 struct mem_list *next;
690                 char data[0];
691         } *list_head = NULL;
692         unsigned i;
693         unsigned count = 0;
694
695         rte_srand((unsigned)rte_rdtsc());
696
697         for (i = 0; i < N; i++){
698                 unsigned free_mem = 0;
699                 size_t allocated_size;
700                 while (!free_mem){
701                         const unsigned mem_size = sizeof(struct mem_list) + \
702                                         rte_rand() % (64 * 1024);
703                         const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
704                         struct mem_list *entry = rte_malloc(NULL,
705                                         mem_size, align);
706                         if (entry == NULL)
707                                 return -1;
708                         if (RTE_PTR_ALIGN(entry, align)!= entry)
709                                 return -1;
710                         if (rte_malloc_validate(entry, &allocated_size) == -1
711                                         || allocated_size < mem_size)
712                                 return -1;
713                         memset(entry->data, rte_lcore_id(),
714                                         mem_size - sizeof(*entry));
715                         entry->next = list_head;
716                         if (rte_malloc_validate(entry, NULL) == -1)
717                                 return -1;
718                         list_head = entry;
719
720                         count++;
721                         /* switch to freeing the memory with a 20% probability */
722                         free_mem = ((rte_rand() % 10) >= 8);
723                 }
724                 while (list_head){
725                         struct mem_list *entry = list_head;
726                         list_head = list_head->next;
727                         rte_free(entry);
728                 }
729         }
730         printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
731         return 0;
732 }
733
734 #define err_return() do { \
735         printf("%s: %d - Error\n", __func__, __LINE__); \
736         goto err_return; \
737 } while (0)
738
739 static int
740 test_rte_malloc_validate(void)
741 {
742         const size_t request_size = 1024;
743         size_t allocated_size;
744         char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE);
745 #ifdef RTE_MALLOC_DEBUG
746         int retval;
747         char *over_write_vals = NULL;
748 #endif
749
750         if (data_ptr == NULL) {
751                 printf("%s: %d - Allocation error\n", __func__, __LINE__);
752                 return -1;
753         }
754
755         /* check that a null input returns -1 */
756         if (rte_malloc_validate(NULL, NULL) != -1)
757                 err_return();
758
759         /* check that we get ok on a valid pointer */
760         if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
761                 err_return();
762
763         /* check that the returned size is ok */
764         if (allocated_size < request_size)
765                 err_return();
766
767 #ifdef RTE_MALLOC_DEBUG
768
769         /****** change the header to be bad */
770         char save_buf[64];
771         over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf));
772         /* first save the data as a backup before overwriting it */
773         memcpy(save_buf, over_write_vals, sizeof(save_buf));
774         memset(over_write_vals, 1, sizeof(save_buf));
775         /* then run validate */
776         retval = rte_malloc_validate(data_ptr, NULL);
777         /* finally restore the data again */
778         memcpy(over_write_vals, save_buf, sizeof(save_buf));
779         /* check we previously had an error */
780         if (retval != -1)
781                 err_return();
782
783         /* check all ok again */
784         if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
785                 err_return();
786
787         /**** change the trailer to be bad */
788         over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size);
789         /* first save the data as a backup before overwriting it */
790         memcpy(save_buf, over_write_vals, sizeof(save_buf));
791         memset(over_write_vals, 1, sizeof(save_buf));
792         /* then run validate */
793         retval = rte_malloc_validate(data_ptr, NULL);
794         /* finally restore the data again */
795         memcpy(over_write_vals, save_buf, sizeof(save_buf));
796         if (retval != -1)
797                 err_return();
798
799         /* check all ok again */
800         if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
801                 err_return();
802 #endif
803
804         rte_free(data_ptr);
805         return 0;
806
807 err_return:
808         /*clean up */
809         rte_free(data_ptr);
810         return -1;
811 }
812
813 static int
814 test_zero_aligned_alloc(void)
815 {
816         char *p1 = rte_malloc(NULL,1024, 0);
817         if (!p1)
818                 goto err_return;
819         if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE))
820                 goto err_return;
821         rte_free(p1);
822         return 0;
823
824 err_return:
825         /*clean up */
826         rte_free(p1);
827         return -1;
828 }
829
830 static int
831 test_malloc_bad_params(void)
832 {
833         const char *type = NULL;
834         size_t size = 0;
835         unsigned align = RTE_CACHE_LINE_SIZE;
836
837         /* rte_malloc expected to return null with inappropriate size */
838         char *bad_ptr = rte_malloc(type, size, align);
839         if (bad_ptr != NULL)
840                 goto err_return;
841
842         /* rte_realloc expected to return null with inappropriate size */
843         bad_ptr = rte_realloc(NULL, size, align);
844         if (bad_ptr != NULL)
845                 goto err_return;
846
847         /* rte_malloc expected to return null with inappropriate alignment */
848         align = 17;
849         size = 1024;
850
851         bad_ptr = rte_malloc(type, size, align);
852         if (bad_ptr != NULL)
853                 goto err_return;
854
855         /* rte_realloc expected to return null with inappropriate alignment */
856         bad_ptr = rte_realloc(NULL, size, align);
857         if (bad_ptr != NULL)
858                 goto err_return;
859
860 #if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
861         /* this test can not be built, will get trapped at compile time! */
862 #else
863         /* rte_malloc expected to return null with size will cause overflow */
864         align = RTE_CACHE_LINE_SIZE;
865         size = (size_t)-8;
866
867         bad_ptr = rte_malloc(type, size, align);
868         if (bad_ptr != NULL)
869                 goto err_return;
870
871         bad_ptr = rte_realloc(NULL, size, align);
872         if (bad_ptr != NULL)
873                 goto err_return;
874 #endif
875         return 0;
876
877 err_return:
878         /* clean up pointer */
879         rte_free(bad_ptr);
880         return -1;
881 }
882
883 static int
884 check_socket_mem(const struct rte_memseg_list *msl, void *arg)
885 {
886         int32_t *socket = arg;
887
888         if (msl->external)
889                 return 0;
890
891         return *socket == msl->socket_id;
892 }
893
894 /* Check if memory is available on a specific socket */
895 static int
896 is_mem_on_socket(int32_t socket)
897 {
898         return rte_memseg_list_walk(check_socket_mem, &socket);
899 }
900
901
902 /*
903  * Find what socket a memory address is on. Only works for addresses within
904  * memsegs, not heap or stack...
905  */
906 static int32_t
907 addr_to_socket(void * addr)
908 {
909         const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
910         return ms == NULL ? -1 : ms->socket_id;
911
912 }
913
914 /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
915 static int
916 test_alloc_single_socket(int32_t socket)
917 {
918         const char *type = NULL;
919         const size_t size = 10;
920         const unsigned align = 0;
921         char *mem = NULL;
922         int32_t desired_socket = (socket == SOCKET_ID_ANY) ?
923                         (int32_t)rte_socket_id() : socket;
924
925         /* Test rte_calloc_socket() */
926         mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
927         if (mem == NULL)
928                 return -1;
929         if (addr_to_socket(mem) != desired_socket) {
930                 rte_free(mem);
931                 return -1;
932         }
933         rte_free(mem);
934
935         /* Test rte_malloc_socket() */
936         mem = rte_malloc_socket(type, size, align, socket);
937         if (mem == NULL)
938                 return -1;
939         if (addr_to_socket(mem) != desired_socket) {
940                 return -1;
941         }
942         rte_free(mem);
943
944         /* Test rte_zmalloc_socket() */
945         mem = rte_zmalloc_socket(type, size, align, socket);
946         if (mem == NULL)
947                 return -1;
948         if (addr_to_socket(mem) != desired_socket) {
949                 rte_free(mem);
950                 return -1;
951         }
952         rte_free(mem);
953
954         return 0;
955 }
956
957 static int
958 test_alloc_socket(void)
959 {
960         unsigned socket_count = 0;
961         unsigned i;
962
963         if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
964                 return -1;
965
966         for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
967                 if (is_mem_on_socket(i)) {
968                         socket_count++;
969                         if (test_alloc_single_socket(i) < 0) {
970                                 printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
971                                                 i);
972                                 return -1;
973                         }
974                 }
975                 else {
976                         if (test_alloc_single_socket(i) == 0) {
977                                 printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
978                                                 i);
979                                 return -1;
980                         }
981                 }
982         }
983
984         /* Print warning if only a single socket, but don't fail the test */
985         if (socket_count < 2) {
986                 printf("WARNING: alloc_socket test needs memory on multiple sockets!\n");
987         }
988
989         return 0;
990 }
991
992 static int
993 test_malloc(void)
994 {
995         unsigned lcore_id;
996         int ret = 0;
997
998         if (test_str_to_size() < 0){
999                 printf("test_str_to_size() failed\n");
1000                 return -1;
1001         }
1002         else printf("test_str_to_size() passed\n");
1003
1004         if (test_zero_aligned_alloc() < 0){
1005                 printf("test_zero_aligned_alloc() failed\n");
1006                 return -1;
1007         }
1008         else printf("test_zero_aligned_alloc() passed\n");
1009
1010         if (test_malloc_bad_params() < 0){
1011                 printf("test_malloc_bad_params() failed\n");
1012                 return -1;
1013         }
1014         else printf("test_malloc_bad_params() passed\n");
1015
1016         if (test_realloc() < 0){
1017                 printf("test_realloc() failed\n");
1018                 return -1;
1019         }
1020         else printf("test_realloc() passed\n");
1021
1022         /*----------------------------*/
1023         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1024                 rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
1025         }
1026
1027         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1028                 if (rte_eal_wait_lcore(lcore_id) < 0)
1029                         ret = -1;
1030         }
1031         if (ret < 0){
1032                 printf("test_align_overlap_per_lcore() failed\n");
1033                 return ret;
1034         }
1035         else printf("test_align_overlap_per_lcore() passed\n");
1036
1037         /*----------------------------*/
1038         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1039                 rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
1040         }
1041
1042         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1043                 if (rte_eal_wait_lcore(lcore_id) < 0)
1044                         ret = -1;
1045         }
1046         if (ret < 0){
1047                 printf("test_reordered_free_per_lcore() failed\n");
1048                 return ret;
1049         }
1050         else printf("test_reordered_free_per_lcore() passed\n");
1051
1052         /*----------------------------*/
1053         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1054                 rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
1055         }
1056
1057         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1058                 if (rte_eal_wait_lcore(lcore_id) < 0)
1059                         ret = -1;
1060         }
1061         if (ret < 0){
1062                 printf("test_random_alloc_free() failed\n");
1063                 return ret;
1064         }
1065         else printf("test_random_alloc_free() passed\n");
1066
1067         /*----------------------------*/
1068         ret = test_rte_malloc_validate();
1069         if (ret < 0){
1070                 printf("test_rte_malloc_validate() failed\n");
1071                 return ret;
1072         }
1073         else printf("test_rte_malloc_validate() passed\n");
1074
1075         ret = test_alloc_socket();
1076         if (ret < 0){
1077                 printf("test_alloc_socket() failed\n");
1078                 return ret;
1079         }
1080         else printf("test_alloc_socket() passed\n");
1081
1082         ret = test_multi_alloc_statistics();
1083         if (ret < 0) {
1084                 printf("test_multi_alloc_statistics() failed\n");
1085                 return ret;
1086         }
1087         else
1088                 printf("test_multi_alloc_statistics() passed\n");
1089
1090         return 0;
1091 }
1092
1093 REGISTER_TEST_COMMAND(malloc_autotest, test_malloc);