test/mem: refactor and rename functions
[dpdk.git] / test / test / test_external_mem.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <fcntl.h>
10 #include <sys/mman.h>
11 #include <sys/wait.h>
12
13 #include <rte_common.h>
14 #include <rte_debug.h>
15 #include <rte_eal.h>
16 #include <rte_errno.h>
17 #include <rte_malloc.h>
18 #include <rte_ring.h>
19 #include <rte_string_fns.h>
20
21 #include "test.h"
22
23 #define EXTERNAL_MEM_SZ (RTE_PGSIZE_4K << 10) /* 4M of data */
24
25 static int
26 check_mem(void *addr, rte_iova_t *iova, size_t pgsz, int n_pages)
27 {
28         int i;
29
30         /* check that we can get this memory from EAL now */
31         for (i = 0; i < n_pages; i++) {
32                 const struct rte_memseg *ms;
33                 void *cur = RTE_PTR_ADD(addr, pgsz * i);
34
35                 ms = rte_mem_virt2memseg(cur, NULL);
36                 if (ms == NULL) {
37                         printf("%s():%i: Failed to retrieve memseg for external mem\n",
38                                 __func__, __LINE__);
39                         return -1;
40                 }
41                 if (ms->addr != cur) {
42                         printf("%s():%i: VA mismatch\n", __func__, __LINE__);
43                         return -1;
44                 }
45                 if (ms->iova != iova[i]) {
46                         printf("%s():%i: IOVA mismatch\n", __func__, __LINE__);
47                         return -1;
48                 }
49         }
50         return 0;
51 }
52
53 static int
54 test_malloc_invalid_param(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
55                 int n_pages)
56 {
57         static const char * const names[] = {
58                 NULL, /* NULL name */
59                 "",   /* empty name */
60                 "this heap name is definitely way too long to be valid"
61         };
62         const char *valid_name = "valid heap name";
63         unsigned int i;
64
65         /* check invalid name handling */
66         for (i = 0; i < RTE_DIM(names); i++) {
67                 const char *name = names[i];
68
69                 /* these calls may fail for other reasons, so check errno */
70                 if (rte_malloc_heap_create(name) >= 0 || rte_errno != EINVAL) {
71                         printf("%s():%i: Created heap with invalid name\n",
72                                         __func__, __LINE__);
73                         goto fail;
74                 }
75
76                 if (rte_malloc_heap_destroy(name) >= 0 || rte_errno != EINVAL) {
77                         printf("%s():%i: Destroyed heap with invalid name\n",
78                                         __func__, __LINE__);
79                         goto fail;
80                 }
81
82                 if (rte_malloc_heap_get_socket(name) >= 0 ||
83                                 rte_errno != EINVAL) {
84                         printf("%s():%i: Found socket for heap with invalid name\n",
85                                         __func__, __LINE__);
86                         goto fail;
87                 }
88
89                 if (rte_malloc_heap_memory_add(name, addr, len,
90                                 NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
91                         printf("%s():%i: Added memory to heap with invalid name\n",
92                                         __func__, __LINE__);
93                         goto fail;
94                 }
95                 if (rte_malloc_heap_memory_remove(name, addr, len) >= 0 ||
96                                 rte_errno != EINVAL) {
97                         printf("%s():%i: Removed memory from heap with invalid name\n",
98                                         __func__, __LINE__);
99                         goto fail;
100                 }
101
102                 if (rte_malloc_heap_memory_attach(name, addr, len) >= 0 ||
103                                 rte_errno != EINVAL) {
104                         printf("%s():%i: Attached memory to heap with invalid name\n",
105                                 __func__, __LINE__);
106                         goto fail;
107                 }
108                 if (rte_malloc_heap_memory_detach(name, addr, len) >= 0 ||
109                                 rte_errno != EINVAL) {
110                         printf("%s():%i: Detached memory from heap with invalid name\n",
111                                 __func__, __LINE__);
112                         goto fail;
113                 }
114         }
115
116         /* do same as above, but with a valid heap name */
117
118         /* skip create call */
119         if (rte_malloc_heap_destroy(valid_name) >= 0 || rte_errno != ENOENT) {
120                 printf("%s():%i: Destroyed heap with invalid name\n",
121                         __func__, __LINE__);
122                 goto fail;
123         }
124         if (rte_malloc_heap_get_socket(valid_name) >= 0 ||
125                         rte_errno != ENOENT) {
126                 printf("%s():%i: Found socket for heap with invalid name\n",
127                                 __func__, __LINE__);
128                 goto fail;
129         }
130
131         /* these calls may fail for other reasons, so check errno */
132         if (rte_malloc_heap_memory_add(valid_name, addr, len,
133                         NULL, 0, pgsz) >= 0 || rte_errno != ENOENT) {
134                 printf("%s():%i: Added memory to non-existent heap\n",
135                         __func__, __LINE__);
136                 goto fail;
137         }
138         if (rte_malloc_heap_memory_remove(valid_name, addr, len) >= 0 ||
139                         rte_errno != ENOENT) {
140                 printf("%s():%i: Removed memory from non-existent heap\n",
141                         __func__, __LINE__);
142                 goto fail;
143         }
144
145         if (rte_malloc_heap_memory_attach(valid_name, addr, len) >= 0 ||
146                         rte_errno != ENOENT) {
147                 printf("%s():%i: Attached memory to non-existent heap\n",
148                         __func__, __LINE__);
149                 goto fail;
150         }
151         if (rte_malloc_heap_memory_detach(valid_name, addr, len) >= 0 ||
152                         rte_errno != ENOENT) {
153                 printf("%s():%i: Detached memory from non-existent heap\n",
154                         __func__, __LINE__);
155                 goto fail;
156         }
157
158         /* create a valid heap but test other invalid parameters */
159         if (rte_malloc_heap_create(valid_name) != 0) {
160                 printf("%s():%i: Failed to create valid heap\n",
161                         __func__, __LINE__);
162                 goto fail;
163         }
164
165         /* zero length */
166         if (rte_malloc_heap_memory_add(valid_name, addr, 0,
167                         NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
168                 printf("%s():%i: Added memory with invalid parameters\n",
169                         __func__, __LINE__);
170                 goto fail;
171         }
172
173         if (rte_malloc_heap_memory_remove(valid_name, addr, 0) >= 0 ||
174                         rte_errno != EINVAL) {
175                 printf("%s():%i: Removed memory with invalid parameters\n",
176                         __func__, __LINE__);
177                 goto fail;
178         }
179
180         if (rte_malloc_heap_memory_attach(valid_name, addr, 0) >= 0 ||
181                         rte_errno != EINVAL) {
182                 printf("%s():%i: Attached memory with invalid parameters\n",
183                         __func__, __LINE__);
184                 goto fail;
185         }
186         if (rte_malloc_heap_memory_detach(valid_name, addr, 0) >= 0 ||
187                         rte_errno != EINVAL) {
188                 printf("%s():%i: Detached memory with invalid parameters\n",
189                         __func__, __LINE__);
190                 goto fail;
191         }
192
193         /* zero address */
194         if (rte_malloc_heap_memory_add(valid_name, NULL, len,
195                         NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
196                 printf("%s():%i: Added memory with invalid parameters\n",
197                         __func__, __LINE__);
198                 goto fail;
199         }
200
201         if (rte_malloc_heap_memory_remove(valid_name, NULL, len) >= 0 ||
202                         rte_errno != EINVAL) {
203                 printf("%s():%i: Removed memory with invalid parameters\n",
204                         __func__, __LINE__);
205                 goto fail;
206         }
207
208         if (rte_malloc_heap_memory_attach(valid_name, NULL, len) >= 0 ||
209                         rte_errno != EINVAL) {
210                 printf("%s():%i: Attached memory with invalid parameters\n",
211                         __func__, __LINE__);
212                 goto fail;
213         }
214         if (rte_malloc_heap_memory_detach(valid_name, NULL, len) >= 0 ||
215                         rte_errno != EINVAL) {
216                 printf("%s():%i: Detached memory with invalid parameters\n",
217                         __func__, __LINE__);
218                 goto fail;
219         }
220
221         /* wrong page count */
222         if (rte_malloc_heap_memory_add(valid_name, addr, len,
223                         iova, 0, pgsz) >= 0 || rte_errno != EINVAL) {
224                 printf("%s():%i: Added memory with invalid parameters\n",
225                         __func__, __LINE__);
226                 goto fail;
227         }
228         if (rte_malloc_heap_memory_add(valid_name, addr, len,
229                         iova, n_pages - 1, pgsz) >= 0 || rte_errno != EINVAL) {
230                 printf("%s():%i: Added memory with invalid parameters\n",
231                         __func__, __LINE__);
232                 goto fail;
233         }
234         if (rte_malloc_heap_memory_add(valid_name, addr, len,
235                         iova, n_pages + 1, pgsz) >= 0 || rte_errno != EINVAL) {
236                 printf("%s():%i: Added memory with invalid parameters\n",
237                         __func__, __LINE__);
238                 goto fail;
239         }
240
241         /* tests passed, destroy heap */
242         if (rte_malloc_heap_destroy(valid_name) != 0) {
243                 printf("%s():%i: Failed to destroy valid heap\n",
244                         __func__, __LINE__);
245                 goto fail;
246         }
247         return 0;
248 fail:
249         rte_malloc_heap_destroy(valid_name);
250         return -1;
251 }
252
253 static int
254 test_malloc_basic(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
255                 int n_pages)
256 {
257         const char *heap_name = "heap";
258         void *ptr = NULL;
259         int socket_id;
260         const struct rte_memzone *mz = NULL;
261
262         /* create heap */
263         if (rte_malloc_heap_create(heap_name) != 0) {
264                 printf("%s():%i: Failed to create malloc heap\n",
265                         __func__, __LINE__);
266                 goto fail;
267         }
268
269         /* get socket ID corresponding to this heap */
270         socket_id = rte_malloc_heap_get_socket(heap_name);
271         if (socket_id < 0) {
272                 printf("%s():%i: cannot find socket for external heap\n",
273                         __func__, __LINE__);
274                 goto fail;
275         }
276
277         /* heap is empty, so any allocation should fail */
278         ptr = rte_malloc_socket("EXTMEM", 64, 0, socket_id);
279         if (ptr != NULL) {
280                 printf("%s():%i: Allocated from empty heap\n", __func__,
281                         __LINE__);
282                 goto fail;
283         }
284
285         /* add memory to heap */
286         if (rte_malloc_heap_memory_add(heap_name, addr, len,
287                         iova, n_pages, pgsz) != 0) {
288                 printf("%s():%i: Failed to add memory to heap\n",
289                         __func__, __LINE__);
290                 goto fail;
291         }
292
293         /* check if memory is accessible from EAL */
294         if (check_mem(addr, iova, pgsz, n_pages) < 0)
295                 goto fail;
296
297         /* allocate - this now should succeed */
298         ptr = rte_malloc_socket("EXTMEM", 64, 0, socket_id);
299         if (ptr == NULL) {
300                 printf("%s():%i: Failed to allocate from external heap\n",
301                         __func__, __LINE__);
302                 goto fail;
303         }
304
305         /* check if address is in expected range */
306         if (ptr < addr || ptr >= RTE_PTR_ADD(addr, len)) {
307                 printf("%s():%i: Allocated from unexpected address space\n",
308                         __func__, __LINE__);
309                 goto fail;
310         }
311
312         /* we've allocated something - removing memory should fail */
313         if (rte_malloc_heap_memory_remove(heap_name, addr, len) >= 0 ||
314                         rte_errno != EBUSY) {
315                 printf("%s():%i: Removing memory succeeded when memory is not free\n",
316                         __func__, __LINE__);
317                 goto fail;
318         }
319         if (rte_malloc_heap_destroy(heap_name) >= 0 || rte_errno != EBUSY) {
320                 printf("%s():%i: Destroying heap succeeded when memory is not free\n",
321                         __func__, __LINE__);
322                 goto fail;
323         }
324
325         /* try allocating an IOVA-contiguous memzone - this should succeed
326          * because we've set up a contiguous IOVA table.
327          */
328         mz = rte_memzone_reserve("heap_test", pgsz * 2, socket_id,
329                         RTE_MEMZONE_IOVA_CONTIG);
330         if (mz == NULL) {
331                 printf("%s():%i: Failed to reserve memzone\n",
332                         __func__, __LINE__);
333                 goto fail;
334         }
335
336         rte_malloc_dump_stats(stdout, NULL);
337         rte_malloc_dump_heaps(stdout);
338
339         /* free memory - removing it should now succeed */
340         rte_free(ptr);
341         ptr = NULL;
342
343         rte_memzone_free(mz);
344         mz = NULL;
345
346         if (rte_malloc_heap_memory_remove(heap_name, addr, len) != 0) {
347                 printf("%s():%i: Removing memory from heap failed\n",
348                         __func__, __LINE__);
349                 goto fail;
350         }
351         if (rte_malloc_heap_destroy(heap_name) != 0) {
352                 printf("%s():%i: Destroying heap failed\n",
353                         __func__, __LINE__);
354                 goto fail;
355         }
356
357         return 0;
358 fail:
359         rte_memzone_free(mz);
360         rte_free(ptr);
361         /* even if something failed, attempt to clean up */
362         rte_malloc_heap_memory_remove(heap_name, addr, len);
363         rte_malloc_heap_destroy(heap_name);
364
365         return -1;
366 }
367
368 /* we need to test attach/detach in secondary processes. */
369 static int
370 test_external_mem(void)
371 {
372         size_t len = EXTERNAL_MEM_SZ;
373         size_t pgsz = RTE_PGSIZE_4K;
374         rte_iova_t iova[len / pgsz];
375         void *addr;
376         int ret, n_pages;
377         int i;
378
379         /* create external memory area */
380         n_pages = RTE_DIM(iova);
381         addr = mmap(NULL, len, PROT_WRITE | PROT_READ,
382                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
383         if (addr == MAP_FAILED) {
384                 printf("%s():%i: Failed to create dummy memory area\n",
385                         __func__, __LINE__);
386                 return -1;
387         }
388         for (i = 0; i < n_pages; i++) {
389                 /* arbitrary IOVA */
390                 rte_iova_t tmp = 0x100000000 + i * pgsz;
391                 iova[i] = tmp;
392         }
393
394         ret = test_malloc_invalid_param(addr, len, pgsz, iova, n_pages);
395         ret |= test_malloc_basic(addr, len, pgsz, iova, n_pages);
396
397         munmap(addr, len);
398
399         return ret;
400 }
401
402 REGISTER_TEST_COMMAND(external_mem_autotest, test_external_mem);