xref: /f-stack/dpdk/app/test/test_external_mem.c (revision 4418919f)
1*4418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
2*4418919fSjohnjiang  * Copyright(c) 2018 Intel Corporation
3*4418919fSjohnjiang  */
4*4418919fSjohnjiang 
5*4418919fSjohnjiang #include <errno.h>
6*4418919fSjohnjiang #include <stdio.h>
7*4418919fSjohnjiang #include <stdlib.h>
8*4418919fSjohnjiang #include <string.h>
9*4418919fSjohnjiang #include <fcntl.h>
10*4418919fSjohnjiang #include <sys/mman.h>
11*4418919fSjohnjiang #include <sys/wait.h>
12*4418919fSjohnjiang 
13*4418919fSjohnjiang #include <rte_common.h>
14*4418919fSjohnjiang #include <rte_debug.h>
15*4418919fSjohnjiang #include <rte_eal.h>
16*4418919fSjohnjiang #include <rte_errno.h>
17*4418919fSjohnjiang #include <rte_malloc.h>
18*4418919fSjohnjiang #include <rte_ring.h>
19*4418919fSjohnjiang #include <rte_string_fns.h>
20*4418919fSjohnjiang 
21*4418919fSjohnjiang #include "test.h"
22*4418919fSjohnjiang 
23*4418919fSjohnjiang #define EXTERNAL_MEM_SZ (RTE_PGSIZE_4K << 10) /* 4M of data */
24*4418919fSjohnjiang 
25*4418919fSjohnjiang static int
check_mem(void * addr,rte_iova_t * iova,size_t pgsz,int n_pages)26*4418919fSjohnjiang check_mem(void *addr, rte_iova_t *iova, size_t pgsz, int n_pages)
27*4418919fSjohnjiang {
28*4418919fSjohnjiang 	int i;
29*4418919fSjohnjiang 
30*4418919fSjohnjiang 	/* check that we can get this memory from EAL now */
31*4418919fSjohnjiang 	for (i = 0; i < n_pages; i++) {
32*4418919fSjohnjiang 		const struct rte_memseg_list *msl;
33*4418919fSjohnjiang 		const struct rte_memseg *ms;
34*4418919fSjohnjiang 		void *cur = RTE_PTR_ADD(addr, pgsz * i);
35*4418919fSjohnjiang 		rte_iova_t expected_iova;
36*4418919fSjohnjiang 
37*4418919fSjohnjiang 		msl = rte_mem_virt2memseg_list(cur);
38*4418919fSjohnjiang 		if (!msl->external) {
39*4418919fSjohnjiang 			printf("%s():%i: Memseg list is not marked as external\n",
40*4418919fSjohnjiang 				__func__, __LINE__);
41*4418919fSjohnjiang 			return -1;
42*4418919fSjohnjiang 		}
43*4418919fSjohnjiang 
44*4418919fSjohnjiang 		ms = rte_mem_virt2memseg(cur, msl);
45*4418919fSjohnjiang 		if (ms == NULL) {
46*4418919fSjohnjiang 			printf("%s():%i: Failed to retrieve memseg for external mem\n",
47*4418919fSjohnjiang 				__func__, __LINE__);
48*4418919fSjohnjiang 			return -1;
49*4418919fSjohnjiang 		}
50*4418919fSjohnjiang 		if (ms->addr != cur) {
51*4418919fSjohnjiang 			printf("%s():%i: VA mismatch\n", __func__, __LINE__);
52*4418919fSjohnjiang 			return -1;
53*4418919fSjohnjiang 		}
54*4418919fSjohnjiang 		expected_iova = (iova == NULL) ? RTE_BAD_IOVA : iova[i];
55*4418919fSjohnjiang 		if (ms->iova != expected_iova) {
56*4418919fSjohnjiang 			printf("%s():%i: IOVA mismatch\n", __func__, __LINE__);
57*4418919fSjohnjiang 			return -1;
58*4418919fSjohnjiang 		}
59*4418919fSjohnjiang 	}
60*4418919fSjohnjiang 	return 0;
61*4418919fSjohnjiang }
62*4418919fSjohnjiang 
63*4418919fSjohnjiang static int
test_malloc_invalid_param(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)64*4418919fSjohnjiang test_malloc_invalid_param(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
65*4418919fSjohnjiang 		int n_pages)
66*4418919fSjohnjiang {
67*4418919fSjohnjiang 	static const char * const names[] = {
68*4418919fSjohnjiang 		NULL, /* NULL name */
69*4418919fSjohnjiang 		"",   /* empty name */
70*4418919fSjohnjiang 		"this heap name is definitely way too long to be valid"
71*4418919fSjohnjiang 	};
72*4418919fSjohnjiang 	const char *valid_name = "valid heap name";
73*4418919fSjohnjiang 	unsigned int i;
74*4418919fSjohnjiang 
75*4418919fSjohnjiang 	/* check invalid name handling */
76*4418919fSjohnjiang 	for (i = 0; i < RTE_DIM(names); i++) {
77*4418919fSjohnjiang 		const char *name = names[i];
78*4418919fSjohnjiang 
79*4418919fSjohnjiang 		/* these calls may fail for other reasons, so check errno */
80*4418919fSjohnjiang 		if (rte_malloc_heap_create(name) >= 0 || rte_errno != EINVAL) {
81*4418919fSjohnjiang 			printf("%s():%i: Created heap with invalid name\n",
82*4418919fSjohnjiang 					__func__, __LINE__);
83*4418919fSjohnjiang 			goto fail;
84*4418919fSjohnjiang 		}
85*4418919fSjohnjiang 
86*4418919fSjohnjiang 		if (rte_malloc_heap_destroy(name) >= 0 || rte_errno != EINVAL) {
87*4418919fSjohnjiang 			printf("%s():%i: Destroyed heap with invalid name\n",
88*4418919fSjohnjiang 					__func__, __LINE__);
89*4418919fSjohnjiang 			goto fail;
90*4418919fSjohnjiang 		}
91*4418919fSjohnjiang 
92*4418919fSjohnjiang 		if (rte_malloc_heap_get_socket(name) >= 0 ||
93*4418919fSjohnjiang 				rte_errno != EINVAL) {
94*4418919fSjohnjiang 			printf("%s():%i: Found socket for heap with invalid name\n",
95*4418919fSjohnjiang 					__func__, __LINE__);
96*4418919fSjohnjiang 			goto fail;
97*4418919fSjohnjiang 		}
98*4418919fSjohnjiang 
99*4418919fSjohnjiang 		if (rte_malloc_heap_memory_add(name, addr, len,
100*4418919fSjohnjiang 				NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
101*4418919fSjohnjiang 			printf("%s():%i: Added memory to heap with invalid name\n",
102*4418919fSjohnjiang 					__func__, __LINE__);
103*4418919fSjohnjiang 			goto fail;
104*4418919fSjohnjiang 		}
105*4418919fSjohnjiang 		if (rte_malloc_heap_memory_remove(name, addr, len) >= 0 ||
106*4418919fSjohnjiang 				rte_errno != EINVAL) {
107*4418919fSjohnjiang 			printf("%s():%i: Removed memory from heap with invalid name\n",
108*4418919fSjohnjiang 					__func__, __LINE__);
109*4418919fSjohnjiang 			goto fail;
110*4418919fSjohnjiang 		}
111*4418919fSjohnjiang 
112*4418919fSjohnjiang 		if (rte_malloc_heap_memory_attach(name, addr, len) >= 0 ||
113*4418919fSjohnjiang 				rte_errno != EINVAL) {
114*4418919fSjohnjiang 			printf("%s():%i: Attached memory to heap with invalid name\n",
115*4418919fSjohnjiang 				__func__, __LINE__);
116*4418919fSjohnjiang 			goto fail;
117*4418919fSjohnjiang 		}
118*4418919fSjohnjiang 		if (rte_malloc_heap_memory_detach(name, addr, len) >= 0 ||
119*4418919fSjohnjiang 				rte_errno != EINVAL) {
120*4418919fSjohnjiang 			printf("%s():%i: Detached memory from heap with invalid name\n",
121*4418919fSjohnjiang 				__func__, __LINE__);
122*4418919fSjohnjiang 			goto fail;
123*4418919fSjohnjiang 		}
124*4418919fSjohnjiang 	}
125*4418919fSjohnjiang 
126*4418919fSjohnjiang 	/* do same as above, but with a valid heap name */
127*4418919fSjohnjiang 
128*4418919fSjohnjiang 	/* skip create call */
129*4418919fSjohnjiang 	if (rte_malloc_heap_destroy(valid_name) >= 0 || rte_errno != ENOENT) {
130*4418919fSjohnjiang 		printf("%s():%i: Destroyed heap with invalid name\n",
131*4418919fSjohnjiang 			__func__, __LINE__);
132*4418919fSjohnjiang 		goto fail;
133*4418919fSjohnjiang 	}
134*4418919fSjohnjiang 	if (rte_malloc_heap_get_socket(valid_name) >= 0 ||
135*4418919fSjohnjiang 			rte_errno != ENOENT) {
136*4418919fSjohnjiang 		printf("%s():%i: Found socket for heap with invalid name\n",
137*4418919fSjohnjiang 				__func__, __LINE__);
138*4418919fSjohnjiang 		goto fail;
139*4418919fSjohnjiang 	}
140*4418919fSjohnjiang 
141*4418919fSjohnjiang 	/* these calls may fail for other reasons, so check errno */
142*4418919fSjohnjiang 	if (rte_malloc_heap_memory_add(valid_name, addr, len,
143*4418919fSjohnjiang 			NULL, 0, pgsz) >= 0 || rte_errno != ENOENT) {
144*4418919fSjohnjiang 		printf("%s():%i: Added memory to non-existent heap\n",
145*4418919fSjohnjiang 			__func__, __LINE__);
146*4418919fSjohnjiang 		goto fail;
147*4418919fSjohnjiang 	}
148*4418919fSjohnjiang 	if (rte_malloc_heap_memory_remove(valid_name, addr, len) >= 0 ||
149*4418919fSjohnjiang 			rte_errno != ENOENT) {
150*4418919fSjohnjiang 		printf("%s():%i: Removed memory from non-existent heap\n",
151*4418919fSjohnjiang 			__func__, __LINE__);
152*4418919fSjohnjiang 		goto fail;
153*4418919fSjohnjiang 	}
154*4418919fSjohnjiang 
155*4418919fSjohnjiang 	if (rte_malloc_heap_memory_attach(valid_name, addr, len) >= 0 ||
156*4418919fSjohnjiang 			rte_errno != ENOENT) {
157*4418919fSjohnjiang 		printf("%s():%i: Attached memory to non-existent heap\n",
158*4418919fSjohnjiang 			__func__, __LINE__);
159*4418919fSjohnjiang 		goto fail;
160*4418919fSjohnjiang 	}
161*4418919fSjohnjiang 	if (rte_malloc_heap_memory_detach(valid_name, addr, len) >= 0 ||
162*4418919fSjohnjiang 			rte_errno != ENOENT) {
163*4418919fSjohnjiang 		printf("%s():%i: Detached memory from non-existent heap\n",
164*4418919fSjohnjiang 			__func__, __LINE__);
165*4418919fSjohnjiang 		goto fail;
166*4418919fSjohnjiang 	}
167*4418919fSjohnjiang 
168*4418919fSjohnjiang 	/* create a valid heap but test other invalid parameters */
169*4418919fSjohnjiang 	if (rte_malloc_heap_create(valid_name) != 0) {
170*4418919fSjohnjiang 		printf("%s():%i: Failed to create valid heap\n",
171*4418919fSjohnjiang 			__func__, __LINE__);
172*4418919fSjohnjiang 		goto fail;
173*4418919fSjohnjiang 	}
174*4418919fSjohnjiang 
175*4418919fSjohnjiang 	/* zero length */
176*4418919fSjohnjiang 	if (rte_malloc_heap_memory_add(valid_name, addr, 0,
177*4418919fSjohnjiang 			NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
178*4418919fSjohnjiang 		printf("%s():%i: Added memory with invalid parameters\n",
179*4418919fSjohnjiang 			__func__, __LINE__);
180*4418919fSjohnjiang 		goto fail;
181*4418919fSjohnjiang 	}
182*4418919fSjohnjiang 
183*4418919fSjohnjiang 	if (rte_malloc_heap_memory_remove(valid_name, addr, 0) >= 0 ||
184*4418919fSjohnjiang 			rte_errno != EINVAL) {
185*4418919fSjohnjiang 		printf("%s():%i: Removed memory with invalid parameters\n",
186*4418919fSjohnjiang 			__func__, __LINE__);
187*4418919fSjohnjiang 		goto fail;
188*4418919fSjohnjiang 	}
189*4418919fSjohnjiang 
190*4418919fSjohnjiang 	if (rte_malloc_heap_memory_attach(valid_name, addr, 0) >= 0 ||
191*4418919fSjohnjiang 			rte_errno != EINVAL) {
192*4418919fSjohnjiang 		printf("%s():%i: Attached memory with invalid parameters\n",
193*4418919fSjohnjiang 			__func__, __LINE__);
194*4418919fSjohnjiang 		goto fail;
195*4418919fSjohnjiang 	}
196*4418919fSjohnjiang 	if (rte_malloc_heap_memory_detach(valid_name, addr, 0) >= 0 ||
197*4418919fSjohnjiang 			rte_errno != EINVAL) {
198*4418919fSjohnjiang 		printf("%s():%i: Detached memory with invalid parameters\n",
199*4418919fSjohnjiang 			__func__, __LINE__);
200*4418919fSjohnjiang 		goto fail;
201*4418919fSjohnjiang 	}
202*4418919fSjohnjiang 
203*4418919fSjohnjiang 	/* zero address */
204*4418919fSjohnjiang 	if (rte_malloc_heap_memory_add(valid_name, NULL, len,
205*4418919fSjohnjiang 			NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
206*4418919fSjohnjiang 		printf("%s():%i: Added memory with invalid parameters\n",
207*4418919fSjohnjiang 			__func__, __LINE__);
208*4418919fSjohnjiang 		goto fail;
209*4418919fSjohnjiang 	}
210*4418919fSjohnjiang 
211*4418919fSjohnjiang 	if (rte_malloc_heap_memory_remove(valid_name, NULL, len) >= 0 ||
212*4418919fSjohnjiang 			rte_errno != EINVAL) {
213*4418919fSjohnjiang 		printf("%s():%i: Removed memory with invalid parameters\n",
214*4418919fSjohnjiang 			__func__, __LINE__);
215*4418919fSjohnjiang 		goto fail;
216*4418919fSjohnjiang 	}
217*4418919fSjohnjiang 
218*4418919fSjohnjiang 	if (rte_malloc_heap_memory_attach(valid_name, NULL, len) >= 0 ||
219*4418919fSjohnjiang 			rte_errno != EINVAL) {
220*4418919fSjohnjiang 		printf("%s():%i: Attached memory with invalid parameters\n",
221*4418919fSjohnjiang 			__func__, __LINE__);
222*4418919fSjohnjiang 		goto fail;
223*4418919fSjohnjiang 	}
224*4418919fSjohnjiang 	if (rte_malloc_heap_memory_detach(valid_name, NULL, len) >= 0 ||
225*4418919fSjohnjiang 			rte_errno != EINVAL) {
226*4418919fSjohnjiang 		printf("%s():%i: Detached memory with invalid parameters\n",
227*4418919fSjohnjiang 			__func__, __LINE__);
228*4418919fSjohnjiang 		goto fail;
229*4418919fSjohnjiang 	}
230*4418919fSjohnjiang 
231*4418919fSjohnjiang 	/* the following tests are only valid if IOVA table is not NULL */
232*4418919fSjohnjiang 	if (iova != NULL) {
233*4418919fSjohnjiang 		/* wrong page count */
234*4418919fSjohnjiang 		if (rte_malloc_heap_memory_add(valid_name, addr, len,
235*4418919fSjohnjiang 				iova, 0, pgsz) >= 0 || rte_errno != EINVAL) {
236*4418919fSjohnjiang 			printf("%s():%i: Added memory with invalid parameters\n",
237*4418919fSjohnjiang 				__func__, __LINE__);
238*4418919fSjohnjiang 			goto fail;
239*4418919fSjohnjiang 		}
240*4418919fSjohnjiang 		if (rte_malloc_heap_memory_add(valid_name, addr, len,
241*4418919fSjohnjiang 				iova, n_pages - 1, pgsz) >= 0 ||
242*4418919fSjohnjiang 				rte_errno != EINVAL) {
243*4418919fSjohnjiang 			printf("%s():%i: Added memory with invalid parameters\n",
244*4418919fSjohnjiang 				__func__, __LINE__);
245*4418919fSjohnjiang 			goto fail;
246*4418919fSjohnjiang 		}
247*4418919fSjohnjiang 		if (rte_malloc_heap_memory_add(valid_name, addr, len,
248*4418919fSjohnjiang 				iova, n_pages + 1, pgsz) >= 0 ||
249*4418919fSjohnjiang 				rte_errno != EINVAL) {
250*4418919fSjohnjiang 			printf("%s():%i: Added memory with invalid parameters\n",
251*4418919fSjohnjiang 				__func__, __LINE__);
252*4418919fSjohnjiang 			goto fail;
253*4418919fSjohnjiang 		}
254*4418919fSjohnjiang 	}
255*4418919fSjohnjiang 
256*4418919fSjohnjiang 	/* tests passed, destroy heap */
257*4418919fSjohnjiang 	if (rte_malloc_heap_destroy(valid_name) != 0) {
258*4418919fSjohnjiang 		printf("%s():%i: Failed to destroy valid heap\n",
259*4418919fSjohnjiang 			__func__, __LINE__);
260*4418919fSjohnjiang 		goto fail;
261*4418919fSjohnjiang 	}
262*4418919fSjohnjiang 	return 0;
263*4418919fSjohnjiang fail:
264*4418919fSjohnjiang 	rte_malloc_heap_destroy(valid_name);
265*4418919fSjohnjiang 	return -1;
266*4418919fSjohnjiang }
267*4418919fSjohnjiang 
268*4418919fSjohnjiang static int
test_malloc_basic(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)269*4418919fSjohnjiang test_malloc_basic(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
270*4418919fSjohnjiang 		int n_pages)
271*4418919fSjohnjiang {
272*4418919fSjohnjiang 	const char *heap_name = "heap";
273*4418919fSjohnjiang 	void *ptr = NULL;
274*4418919fSjohnjiang 	int socket_id;
275*4418919fSjohnjiang 	const struct rte_memzone *mz = NULL, *contig_mz = NULL;
276*4418919fSjohnjiang 
277*4418919fSjohnjiang 	/* create heap */
278*4418919fSjohnjiang 	if (rte_malloc_heap_create(heap_name) != 0) {
279*4418919fSjohnjiang 		printf("%s():%i: Failed to create malloc heap\n",
280*4418919fSjohnjiang 			__func__, __LINE__);
281*4418919fSjohnjiang 		goto fail;
282*4418919fSjohnjiang 	}
283*4418919fSjohnjiang 
284*4418919fSjohnjiang 	/* get socket ID corresponding to this heap */
285*4418919fSjohnjiang 	socket_id = rte_malloc_heap_get_socket(heap_name);
286*4418919fSjohnjiang 	if (socket_id < 0) {
287*4418919fSjohnjiang 		printf("%s():%i: cannot find socket for external heap\n",
288*4418919fSjohnjiang 			__func__, __LINE__);
289*4418919fSjohnjiang 		goto fail;
290*4418919fSjohnjiang 	}
291*4418919fSjohnjiang 
292*4418919fSjohnjiang 	/* heap is empty, so any allocation should fail */
293*4418919fSjohnjiang 	ptr = rte_malloc_socket("EXTMEM", 64, 0, socket_id);
294*4418919fSjohnjiang 	if (ptr != NULL) {
295*4418919fSjohnjiang 		printf("%s():%i: Allocated from empty heap\n", __func__,
296*4418919fSjohnjiang 			__LINE__);
297*4418919fSjohnjiang 		goto fail;
298*4418919fSjohnjiang 	}
299*4418919fSjohnjiang 
300*4418919fSjohnjiang 	/* add memory to heap */
301*4418919fSjohnjiang 	if (rte_malloc_heap_memory_add(heap_name, addr, len,
302*4418919fSjohnjiang 			iova, n_pages, pgsz) != 0) {
303*4418919fSjohnjiang 		printf("%s():%i: Failed to add memory to heap\n",
304*4418919fSjohnjiang 			__func__, __LINE__);
305*4418919fSjohnjiang 		goto fail;
306*4418919fSjohnjiang 	}
307*4418919fSjohnjiang 
308*4418919fSjohnjiang 	/* check if memory is accessible from EAL */
309*4418919fSjohnjiang 	if (check_mem(addr, iova, pgsz, n_pages) < 0)
310*4418919fSjohnjiang 		goto fail;
311*4418919fSjohnjiang 
312*4418919fSjohnjiang 	/* allocate - this now should succeed */
313*4418919fSjohnjiang 	ptr = rte_malloc_socket("EXTMEM", 64, 0, socket_id);
314*4418919fSjohnjiang 	if (ptr == NULL) {
315*4418919fSjohnjiang 		printf("%s():%i: Failed to allocate from external heap\n",
316*4418919fSjohnjiang 			__func__, __LINE__);
317*4418919fSjohnjiang 		goto fail;
318*4418919fSjohnjiang 	}
319*4418919fSjohnjiang 
320*4418919fSjohnjiang 	/* check if address is in expected range */
321*4418919fSjohnjiang 	if (ptr < addr || ptr >= RTE_PTR_ADD(addr, len)) {
322*4418919fSjohnjiang 		printf("%s():%i: Allocated from unexpected address space\n",
323*4418919fSjohnjiang 			__func__, __LINE__);
324*4418919fSjohnjiang 		goto fail;
325*4418919fSjohnjiang 	}
326*4418919fSjohnjiang 
327*4418919fSjohnjiang 	/* we've allocated something - removing memory should fail */
328*4418919fSjohnjiang 	if (rte_malloc_heap_memory_remove(heap_name, addr, len) >= 0 ||
329*4418919fSjohnjiang 			rte_errno != EBUSY) {
330*4418919fSjohnjiang 		printf("%s():%i: Removing memory succeeded when memory is not free\n",
331*4418919fSjohnjiang 			__func__, __LINE__);
332*4418919fSjohnjiang 		goto fail;
333*4418919fSjohnjiang 	}
334*4418919fSjohnjiang 	if (rte_malloc_heap_destroy(heap_name) >= 0 || rte_errno != EBUSY) {
335*4418919fSjohnjiang 		printf("%s():%i: Destroying heap succeeded when memory is not free\n",
336*4418919fSjohnjiang 			__func__, __LINE__);
337*4418919fSjohnjiang 		goto fail;
338*4418919fSjohnjiang 	}
339*4418919fSjohnjiang 
340*4418919fSjohnjiang 	/* try allocating a memzone */
341*4418919fSjohnjiang 	mz = rte_memzone_reserve("heap_test", pgsz * 2, socket_id, 0);
342*4418919fSjohnjiang 	if (mz == NULL) {
343*4418919fSjohnjiang 		printf("%s():%i: Failed to reserve memzone\n",
344*4418919fSjohnjiang 			__func__, __LINE__);
345*4418919fSjohnjiang 		goto fail;
346*4418919fSjohnjiang 	}
347*4418919fSjohnjiang 	/* try allocating an IOVA-contiguous memzone - this should succeed
348*4418919fSjohnjiang 	 * if we've set up a contiguous IOVA table, and fail if we haven't.
349*4418919fSjohnjiang 	 */
350*4418919fSjohnjiang 	contig_mz = rte_memzone_reserve("heap_test_contig", pgsz * 2, socket_id,
351*4418919fSjohnjiang 			RTE_MEMZONE_IOVA_CONTIG);
352*4418919fSjohnjiang 	if ((iova == NULL) != (contig_mz == NULL)) {
353*4418919fSjohnjiang 		printf("%s():%i: Failed to reserve memzone\n",
354*4418919fSjohnjiang 			__func__, __LINE__);
355*4418919fSjohnjiang 		goto fail;
356*4418919fSjohnjiang 	}
357*4418919fSjohnjiang 
358*4418919fSjohnjiang 	rte_malloc_dump_stats(stdout, NULL);
359*4418919fSjohnjiang 	rte_malloc_dump_heaps(stdout);
360*4418919fSjohnjiang 
361*4418919fSjohnjiang 	/* free memory - removing it should now succeed */
362*4418919fSjohnjiang 	rte_free(ptr);
363*4418919fSjohnjiang 	ptr = NULL;
364*4418919fSjohnjiang 
365*4418919fSjohnjiang 	rte_memzone_free(mz);
366*4418919fSjohnjiang 	mz = NULL;
367*4418919fSjohnjiang 	rte_memzone_free(contig_mz);
368*4418919fSjohnjiang 	contig_mz = NULL;
369*4418919fSjohnjiang 
370*4418919fSjohnjiang 	if (rte_malloc_heap_memory_remove(heap_name, addr, len) != 0) {
371*4418919fSjohnjiang 		printf("%s():%i: Removing memory from heap failed\n",
372*4418919fSjohnjiang 			__func__, __LINE__);
373*4418919fSjohnjiang 		goto fail;
374*4418919fSjohnjiang 	}
375*4418919fSjohnjiang 	if (rte_malloc_heap_destroy(heap_name) != 0) {
376*4418919fSjohnjiang 		printf("%s():%i: Destroying heap failed\n",
377*4418919fSjohnjiang 			__func__, __LINE__);
378*4418919fSjohnjiang 		goto fail;
379*4418919fSjohnjiang 	}
380*4418919fSjohnjiang 
381*4418919fSjohnjiang 	return 0;
382*4418919fSjohnjiang fail:
383*4418919fSjohnjiang 	rte_memzone_free(contig_mz);
384*4418919fSjohnjiang 	rte_memzone_free(mz);
385*4418919fSjohnjiang 	rte_free(ptr);
386*4418919fSjohnjiang 	/* even if something failed, attempt to clean up */
387*4418919fSjohnjiang 	rte_malloc_heap_memory_remove(heap_name, addr, len);
388*4418919fSjohnjiang 	rte_malloc_heap_destroy(heap_name);
389*4418919fSjohnjiang 
390*4418919fSjohnjiang 	return -1;
391*4418919fSjohnjiang }
392*4418919fSjohnjiang 
393*4418919fSjohnjiang static int
test_extmem_invalid_param(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)394*4418919fSjohnjiang test_extmem_invalid_param(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
395*4418919fSjohnjiang 		int n_pages)
396*4418919fSjohnjiang {
397*4418919fSjohnjiang 	/* these calls may fail for other reasons, so check errno */
398*4418919fSjohnjiang 	if (rte_extmem_unregister(addr, len) >= 0 ||
399*4418919fSjohnjiang 			rte_errno != ENOENT) {
400*4418919fSjohnjiang 		printf("%s():%i: Unregistered non-existent memory\n",
401*4418919fSjohnjiang 			__func__, __LINE__);
402*4418919fSjohnjiang 		return -1;
403*4418919fSjohnjiang 	}
404*4418919fSjohnjiang 
405*4418919fSjohnjiang 	if (rte_extmem_attach(addr, len) >= 0 ||
406*4418919fSjohnjiang 			rte_errno != ENOENT) {
407*4418919fSjohnjiang 		printf("%s():%i: Attached to non-existent memory\n",
408*4418919fSjohnjiang 			__func__, __LINE__);
409*4418919fSjohnjiang 		return -1;
410*4418919fSjohnjiang 	}
411*4418919fSjohnjiang 	if (rte_extmem_attach(addr, len) >= 0 ||
412*4418919fSjohnjiang 			rte_errno != ENOENT) {
413*4418919fSjohnjiang 		printf("%s():%i: Detached from non-existent memory\n",
414*4418919fSjohnjiang 			__func__, __LINE__);
415*4418919fSjohnjiang 		return -1;
416*4418919fSjohnjiang 	}
417*4418919fSjohnjiang 
418*4418919fSjohnjiang 	/* zero length */
419*4418919fSjohnjiang 	if (rte_extmem_register(addr, 0, NULL, 0, pgsz) >= 0 ||
420*4418919fSjohnjiang 			rte_errno != EINVAL) {
421*4418919fSjohnjiang 		printf("%s():%i: Registered memory with invalid parameters\n",
422*4418919fSjohnjiang 			__func__, __LINE__);
423*4418919fSjohnjiang 		return -1;
424*4418919fSjohnjiang 	}
425*4418919fSjohnjiang 
426*4418919fSjohnjiang 	if (rte_extmem_unregister(addr, 0) >= 0 ||
427*4418919fSjohnjiang 			rte_errno != EINVAL) {
428*4418919fSjohnjiang 		printf("%s():%i: Unregistered memory with invalid parameters\n",
429*4418919fSjohnjiang 			__func__, __LINE__);
430*4418919fSjohnjiang 		return -1;
431*4418919fSjohnjiang 	}
432*4418919fSjohnjiang 
433*4418919fSjohnjiang 	if (rte_extmem_attach(addr, 0) >= 0 ||
434*4418919fSjohnjiang 			rte_errno != EINVAL) {
435*4418919fSjohnjiang 		printf("%s():%i: Attached memory with invalid parameters\n",
436*4418919fSjohnjiang 			__func__, __LINE__);
437*4418919fSjohnjiang 		return -1;
438*4418919fSjohnjiang 	}
439*4418919fSjohnjiang 	if (rte_extmem_attach(addr, 0) >= 0 ||
440*4418919fSjohnjiang 			rte_errno != EINVAL) {
441*4418919fSjohnjiang 		printf("%s():%i: Detached memory with invalid parameters\n",
442*4418919fSjohnjiang 			__func__, __LINE__);
443*4418919fSjohnjiang 		return -1;
444*4418919fSjohnjiang 	}
445*4418919fSjohnjiang 
446*4418919fSjohnjiang 	/* zero address */
447*4418919fSjohnjiang 	if (rte_extmem_register(NULL, len, NULL, 0, pgsz) >= 0 ||
448*4418919fSjohnjiang 			rte_errno != EINVAL) {
449*4418919fSjohnjiang 		printf("%s():%i: Registered memory with invalid parameters\n",
450*4418919fSjohnjiang 			__func__, __LINE__);
451*4418919fSjohnjiang 		return -1;
452*4418919fSjohnjiang 	}
453*4418919fSjohnjiang 
454*4418919fSjohnjiang 	if (rte_extmem_unregister(NULL, len) >= 0 ||
455*4418919fSjohnjiang 			rte_errno != EINVAL) {
456*4418919fSjohnjiang 		printf("%s():%i: Unregistered memory with invalid parameters\n",
457*4418919fSjohnjiang 			__func__, __LINE__);
458*4418919fSjohnjiang 		return -1;
459*4418919fSjohnjiang 	}
460*4418919fSjohnjiang 
461*4418919fSjohnjiang 	if (rte_extmem_attach(NULL, len) >= 0 ||
462*4418919fSjohnjiang 			rte_errno != EINVAL) {
463*4418919fSjohnjiang 		printf("%s():%i: Attached memory with invalid parameters\n",
464*4418919fSjohnjiang 			__func__, __LINE__);
465*4418919fSjohnjiang 		return -1;
466*4418919fSjohnjiang 	}
467*4418919fSjohnjiang 	if (rte_extmem_attach(NULL, len) >= 0 ||
468*4418919fSjohnjiang 			rte_errno != EINVAL) {
469*4418919fSjohnjiang 		printf("%s():%i: Detached memory with invalid parameters\n",
470*4418919fSjohnjiang 			__func__, __LINE__);
471*4418919fSjohnjiang 		return -1;
472*4418919fSjohnjiang 	}
473*4418919fSjohnjiang 
474*4418919fSjohnjiang 	/* the following tests are only valid if IOVA table is not NULL */
475*4418919fSjohnjiang 	if (iova != NULL) {
476*4418919fSjohnjiang 		/* wrong page count */
477*4418919fSjohnjiang 		if (rte_extmem_register(addr, len,
478*4418919fSjohnjiang 				iova, 0, pgsz) >= 0 || rte_errno != EINVAL) {
479*4418919fSjohnjiang 			printf("%s():%i: Registered memory with invalid parameters\n",
480*4418919fSjohnjiang 				__func__, __LINE__);
481*4418919fSjohnjiang 			return -1;
482*4418919fSjohnjiang 		}
483*4418919fSjohnjiang 		if (rte_extmem_register(addr, len,
484*4418919fSjohnjiang 				iova, n_pages - 1, pgsz) >= 0 ||
485*4418919fSjohnjiang 				rte_errno != EINVAL) {
486*4418919fSjohnjiang 			printf("%s():%i: Registered memory with invalid parameters\n",
487*4418919fSjohnjiang 				__func__, __LINE__);
488*4418919fSjohnjiang 			return -1;
489*4418919fSjohnjiang 		}
490*4418919fSjohnjiang 		if (rte_extmem_register(addr, len,
491*4418919fSjohnjiang 				iova, n_pages + 1, pgsz) >= 0 ||
492*4418919fSjohnjiang 				rte_errno != EINVAL) {
493*4418919fSjohnjiang 			printf("%s():%i: Registered memory with invalid parameters\n",
494*4418919fSjohnjiang 				__func__, __LINE__);
495*4418919fSjohnjiang 			return -1;
496*4418919fSjohnjiang 		}
497*4418919fSjohnjiang 	}
498*4418919fSjohnjiang 
499*4418919fSjohnjiang 	return 0;
500*4418919fSjohnjiang }
501*4418919fSjohnjiang 
502*4418919fSjohnjiang static int
test_extmem_basic(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)503*4418919fSjohnjiang test_extmem_basic(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
504*4418919fSjohnjiang 		int n_pages)
505*4418919fSjohnjiang {
506*4418919fSjohnjiang 	/* register memory */
507*4418919fSjohnjiang 	if (rte_extmem_register(addr, len, iova, n_pages, pgsz) != 0) {
508*4418919fSjohnjiang 		printf("%s():%i: Failed to register memory\n",
509*4418919fSjohnjiang 			__func__, __LINE__);
510*4418919fSjohnjiang 		goto fail;
511*4418919fSjohnjiang 	}
512*4418919fSjohnjiang 
513*4418919fSjohnjiang 	/* check if memory is accessible from EAL */
514*4418919fSjohnjiang 	if (check_mem(addr, iova, pgsz, n_pages) < 0)
515*4418919fSjohnjiang 		goto fail;
516*4418919fSjohnjiang 
517*4418919fSjohnjiang 	if (rte_extmem_unregister(addr, len) != 0) {
518*4418919fSjohnjiang 		printf("%s():%i: Removing memory from heap failed\n",
519*4418919fSjohnjiang 			__func__, __LINE__);
520*4418919fSjohnjiang 		goto fail;
521*4418919fSjohnjiang 	}
522*4418919fSjohnjiang 
523*4418919fSjohnjiang 	return 0;
524*4418919fSjohnjiang fail:
525*4418919fSjohnjiang 	/* even if something failed, attempt to clean up */
526*4418919fSjohnjiang 	rte_extmem_unregister(addr, len);
527*4418919fSjohnjiang 
528*4418919fSjohnjiang 	return -1;
529*4418919fSjohnjiang }
530*4418919fSjohnjiang 
531*4418919fSjohnjiang /* we need to test attach/detach in secondary processes. */
532*4418919fSjohnjiang static int
test_external_mem(void)533*4418919fSjohnjiang test_external_mem(void)
534*4418919fSjohnjiang {
535*4418919fSjohnjiang 	size_t len = EXTERNAL_MEM_SZ;
536*4418919fSjohnjiang 	size_t pgsz = RTE_PGSIZE_4K;
537*4418919fSjohnjiang 	rte_iova_t iova[len / pgsz];
538*4418919fSjohnjiang 	void *addr;
539*4418919fSjohnjiang 	int ret, n_pages;
540*4418919fSjohnjiang 	int i;
541*4418919fSjohnjiang 
542*4418919fSjohnjiang 	/* create external memory area */
543*4418919fSjohnjiang 	n_pages = RTE_DIM(iova);
544*4418919fSjohnjiang 	addr = mmap(NULL, len, PROT_WRITE | PROT_READ,
545*4418919fSjohnjiang 			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
546*4418919fSjohnjiang 	if (addr == MAP_FAILED) {
547*4418919fSjohnjiang 		printf("%s():%i: Failed to create dummy memory area\n",
548*4418919fSjohnjiang 			__func__, __LINE__);
549*4418919fSjohnjiang 		return -1;
550*4418919fSjohnjiang 	}
551*4418919fSjohnjiang 	for (i = 0; i < n_pages; i++) {
552*4418919fSjohnjiang 		/* arbitrary IOVA */
553*4418919fSjohnjiang 		rte_iova_t tmp = 0x100000000 + i * pgsz;
554*4418919fSjohnjiang 		iova[i] = tmp;
555*4418919fSjohnjiang 	}
556*4418919fSjohnjiang 
557*4418919fSjohnjiang 	/* test external heap memory */
558*4418919fSjohnjiang 	ret = test_malloc_invalid_param(addr, len, pgsz, iova, n_pages);
559*4418919fSjohnjiang 	ret |= test_malloc_basic(addr, len, pgsz, iova, n_pages);
560*4418919fSjohnjiang 	/* when iova table is NULL, everything should still work */
561*4418919fSjohnjiang 	ret |= test_malloc_invalid_param(addr, len, pgsz, NULL, n_pages);
562*4418919fSjohnjiang 	ret |= test_malloc_basic(addr, len, pgsz, NULL, n_pages);
563*4418919fSjohnjiang 
564*4418919fSjohnjiang 	/* test non-heap memory */
565*4418919fSjohnjiang 	ret |= test_extmem_invalid_param(addr, len, pgsz, iova, n_pages);
566*4418919fSjohnjiang 	ret |= test_extmem_basic(addr, len, pgsz, iova, n_pages);
567*4418919fSjohnjiang 	/* when iova table is NULL, everything should still work */
568*4418919fSjohnjiang 	ret |= test_extmem_invalid_param(addr, len, pgsz, NULL, n_pages);
569*4418919fSjohnjiang 	ret |= test_extmem_basic(addr, len, pgsz, NULL, n_pages);
570*4418919fSjohnjiang 
571*4418919fSjohnjiang 	munmap(addr, len);
572*4418919fSjohnjiang 
573*4418919fSjohnjiang 	return ret;
574*4418919fSjohnjiang }
575*4418919fSjohnjiang 
576*4418919fSjohnjiang REGISTER_TEST_COMMAND(external_mem_autotest, test_external_mem);
577