xref: /spdk/test/common/lib/test_env.c (revision f8abbede89d30584d2a4f8427b13896f8591b873)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2016 Intel Corporation.
3  *   Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES.
4  *   All rights reserved.
5  */
6 
7 #include "spdk/stdinc.h"
8 
9 #include "spdk_internal/mock.h"
10 
11 #include "spdk/env.h"
12 #include "spdk/queue.h"
13 #include "spdk/util.h"
14 #include "spdk/string.h"
15 
16 static uint32_t g_ut_num_cores;
17 static bool *g_ut_cores;
18 
19 void allocate_cores(uint32_t num_cores);
20 void free_cores(void);
21 
22 DEFINE_STUB(spdk_process_is_primary, bool, (void), true)
23 DEFINE_STUB(spdk_memzone_lookup, void *, (const char *name), NULL)
24 DEFINE_STUB_V(spdk_pci_driver_register, (const char *name, struct spdk_pci_id *id_table,
25 		uint32_t flags));
26 DEFINE_STUB(spdk_pci_nvme_get_driver, struct spdk_pci_driver *, (void), NULL)
27 DEFINE_STUB(spdk_pci_ioat_get_driver, struct spdk_pci_driver *, (void), NULL)
28 DEFINE_STUB(spdk_pci_virtio_get_driver, struct spdk_pci_driver *, (void), NULL)
29 DEFINE_STUB(spdk_env_thread_launch_pinned, int, (uint32_t core, thread_start_fn fn, void *arg), 0);
30 DEFINE_STUB_V(spdk_env_thread_wait_all, (void));
31 DEFINE_STUB_V(spdk_env_opts_init, (struct spdk_env_opts *opts));
32 DEFINE_STUB(spdk_env_init, int, (const struct spdk_env_opts *opts), 0);
33 DEFINE_STUB_V(spdk_env_fini, (void));
34 
35 void
36 allocate_cores(uint32_t num_cores)
37 {
38 	uint32_t i;
39 
40 	g_ut_num_cores = num_cores;
41 
42 	g_ut_cores = calloc(num_cores, sizeof(bool));
43 	assert(g_ut_cores != NULL);
44 
45 	for (i = 0; i < num_cores; i++) {
46 		g_ut_cores[i] = true;
47 	}
48 }
49 
50 void
51 free_cores(void)
52 {
53 	free(g_ut_cores);
54 	g_ut_cores = NULL;
55 	g_ut_num_cores = 0;
56 }
57 
58 static uint32_t
59 ut_get_next_core(uint32_t i)
60 {
61 	i++;
62 
63 	while (i < g_ut_num_cores) {
64 		if (!g_ut_cores[i]) {
65 			i++;
66 			continue;
67 		}
68 		break;
69 	}
70 
71 	if (i < g_ut_num_cores) {
72 		return i;
73 	} else {
74 		return UINT32_MAX;
75 	}
76 }
77 
78 uint32_t
79 spdk_env_get_first_core(void)
80 {
81 	return ut_get_next_core(-1);
82 }
83 
84 uint32_t
85 spdk_env_get_next_core(uint32_t prev_core)
86 {
87 	return ut_get_next_core(prev_core);
88 }
89 
90 uint32_t
91 spdk_env_get_core_count(void)
92 {
93 	return g_ut_num_cores;
94 }
95 
96 uint32_t
97 spdk_env_get_last_core(void)
98 {
99 	uint32_t i;
100 	uint32_t last_core = UINT32_MAX;
101 
102 	SPDK_ENV_FOREACH_CORE(i) {
103 		last_core = i;
104 	}
105 
106 	return last_core;
107 }
108 
109 DEFINE_RETURN_MOCK(spdk_env_get_current_core, uint32_t);
110 uint32_t
111 spdk_env_get_current_core(void)
112 {
113 	HANDLE_RETURN_MOCK(spdk_env_get_current_core);
114 
115 	return UINT32_MAX;
116 }
117 
118 DEFINE_RETURN_MOCK(spdk_env_get_socket_id, uint32_t);
119 uint32_t
120 spdk_env_get_socket_id(uint32_t core)
121 {
122 	HANDLE_RETURN_MOCK(spdk_env_get_socket_id);
123 
124 	return SPDK_ENV_SOCKET_ID_ANY;
125 }
126 
127 /*
128  * These mocks don't use the DEFINE_STUB macros because
129  * their default implementation is more complex.
130  */
131 
132 DEFINE_RETURN_MOCK(spdk_memzone_reserve, void *);
133 void *
134 spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags)
135 {
136 	HANDLE_RETURN_MOCK(spdk_memzone_reserve);
137 
138 	return malloc(len);
139 }
140 
141 DEFINE_RETURN_MOCK(spdk_memzone_reserve_aligned, void *);
142 void *
143 spdk_memzone_reserve_aligned(const char *name, size_t len, int socket_id,
144 			     unsigned flags, unsigned align)
145 {
146 	HANDLE_RETURN_MOCK(spdk_memzone_reserve_aligned);
147 
148 	return malloc(len);
149 }
150 
151 DEFINE_RETURN_MOCK(spdk_malloc, void *);
152 void *
153 spdk_malloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags)
154 {
155 	HANDLE_RETURN_MOCK(spdk_malloc);
156 
157 	void *buf = NULL;
158 
159 	if (size == 0) {
160 		/* Align how mock handles 0 size with rte functions - return NULL.
161 		 * According to posix_memalig docs, if size is 0, then the
162 		 * value placed in *memptr is either NULL or a unique pointer value. */
163 		return NULL;
164 	}
165 
166 	if (align == 0) {
167 		align = 8;
168 	}
169 
170 	if (posix_memalign(&buf, align, size)) {
171 		return NULL;
172 	}
173 	if (phys_addr) {
174 		*phys_addr = (uint64_t)buf;
175 	}
176 
177 	return buf;
178 }
179 
180 DEFINE_RETURN_MOCK(spdk_zmalloc, void *);
181 void *
182 spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags)
183 {
184 	HANDLE_RETURN_MOCK(spdk_zmalloc);
185 
186 	void *buf = spdk_malloc(size, align, phys_addr, -1, 1);
187 
188 	if (buf != NULL) {
189 		memset(buf, 0, size);
190 	}
191 	return buf;
192 }
193 
194 DEFINE_RETURN_MOCK(spdk_dma_malloc, void *);
195 void *
196 spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr)
197 {
198 	HANDLE_RETURN_MOCK(spdk_dma_malloc);
199 
200 	return spdk_malloc(size, align, phys_addr, -1, 1);
201 }
202 
203 DEFINE_RETURN_MOCK(spdk_realloc, void *);
204 void *
205 spdk_realloc(void *buf, size_t size, size_t align)
206 {
207 	HANDLE_RETURN_MOCK(spdk_realloc);
208 
209 	return realloc(buf, size);
210 }
211 
212 DEFINE_RETURN_MOCK(spdk_dma_zmalloc, void *);
213 void *
214 spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr)
215 {
216 	HANDLE_RETURN_MOCK(spdk_dma_zmalloc);
217 
218 	return spdk_zmalloc(size, align, phys_addr, -1, 1);
219 }
220 
221 DEFINE_RETURN_MOCK(spdk_dma_malloc_socket, void *);
222 void *
223 spdk_dma_malloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id)
224 {
225 	HANDLE_RETURN_MOCK(spdk_dma_malloc_socket);
226 
227 	return spdk_dma_malloc(size, align, phys_addr);
228 }
229 
230 DEFINE_RETURN_MOCK(spdk_dma_zmalloc_socket, void *);
231 void *
232 spdk_dma_zmalloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id)
233 {
234 	HANDLE_RETURN_MOCK(spdk_dma_zmalloc_socket);
235 
236 	return spdk_dma_zmalloc(size, align, phys_addr);
237 }
238 
239 DEFINE_RETURN_MOCK(spdk_dma_realloc, void *);
240 void *
241 spdk_dma_realloc(void *buf, size_t size, size_t align, uint64_t *phys_addr)
242 {
243 	HANDLE_RETURN_MOCK(spdk_dma_realloc);
244 
245 	return realloc(buf, size);
246 }
247 
248 void
249 spdk_free(void *buf)
250 {
251 	/* fix for false-positives in *certain* static analysis tools. */
252 	assert((uintptr_t)buf != UINTPTR_MAX);
253 	free(buf);
254 }
255 
256 void
257 spdk_dma_free(void *buf)
258 {
259 	return spdk_free(buf);
260 }
261 
262 #ifndef UNIT_TEST_NO_VTOPHYS
263 DEFINE_RETURN_MOCK(spdk_vtophys, uint64_t);
264 uint64_t
265 spdk_vtophys(const void *buf, uint64_t *size)
266 {
267 	HANDLE_RETURN_MOCK(spdk_vtophys);
268 
269 	return (uintptr_t)buf;
270 }
271 #endif
272 
273 void
274 spdk_memzone_dump(FILE *f)
275 {
276 	return;
277 }
278 
279 DEFINE_RETURN_MOCK(spdk_memzone_free, int);
280 int
281 spdk_memzone_free(const char *name)
282 {
283 	HANDLE_RETURN_MOCK(spdk_memzone_free);
284 
285 	return 0;
286 }
287 
288 struct test_mempool {
289 	size_t	count;
290 	size_t	ele_size;
291 };
292 
293 DEFINE_RETURN_MOCK(spdk_mempool_create, struct spdk_mempool *);
294 struct spdk_mempool *
295 spdk_mempool_create(const char *name, size_t count,
296 		    size_t ele_size, size_t cache_size, int socket_id)
297 {
298 	struct test_mempool *mp;
299 
300 	HANDLE_RETURN_MOCK(spdk_mempool_create);
301 
302 	mp = calloc(1, sizeof(*mp));
303 	if (mp == NULL) {
304 		return NULL;
305 	}
306 
307 	mp->count = count;
308 	mp->ele_size = ele_size;
309 
310 	return (struct spdk_mempool *)mp;
311 }
312 
313 void
314 spdk_mempool_free(struct spdk_mempool *_mp)
315 {
316 	struct test_mempool *mp = (struct test_mempool *)_mp;
317 
318 	free(mp);
319 }
320 
321 DEFINE_RETURN_MOCK(spdk_mempool_get, void *);
322 void *
323 spdk_mempool_get(struct spdk_mempool *_mp)
324 {
325 	struct test_mempool *mp = (struct test_mempool *)_mp;
326 	size_t ele_size = 0x10000;
327 	void *buf;
328 
329 	HANDLE_RETURN_MOCK(spdk_mempool_get);
330 
331 	if (mp && mp->count == 0) {
332 		return NULL;
333 	}
334 
335 	if (mp) {
336 		ele_size = mp->ele_size;
337 	}
338 
339 	if (posix_memalign(&buf, 64, spdk_align32pow2(ele_size))) {
340 		return NULL;
341 	} else {
342 		if (mp) {
343 			mp->count--;
344 		}
345 		return buf;
346 	}
347 }
348 
349 int
350 spdk_mempool_get_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count)
351 {
352 	struct test_mempool *test_mp = (struct test_mempool *)mp;
353 
354 	if (test_mp && test_mp->count < count) {
355 		return -1;
356 	}
357 
358 	for (size_t i = 0; i < count; i++) {
359 		ele_arr[i] = spdk_mempool_get(mp);
360 		if (ele_arr[i] == NULL) {
361 			return -1;
362 		}
363 	}
364 	return 0;
365 }
366 
367 void
368 spdk_mempool_put(struct spdk_mempool *_mp, void *ele)
369 {
370 	struct test_mempool *mp = (struct test_mempool *)_mp;
371 
372 	if (mp) {
373 		mp->count++;
374 	}
375 	free(ele);
376 }
377 
378 void
379 spdk_mempool_put_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count)
380 {
381 	for (size_t i = 0; i < count; i++) {
382 		spdk_mempool_put(mp, ele_arr[i]);
383 	}
384 }
385 
386 DEFINE_RETURN_MOCK(spdk_mempool_count, size_t);
387 size_t
388 spdk_mempool_count(const struct spdk_mempool *_mp)
389 {
390 	struct test_mempool *mp = (struct test_mempool *)_mp;
391 
392 	HANDLE_RETURN_MOCK(spdk_mempool_count);
393 
394 	if (mp) {
395 		return mp->count;
396 	} else {
397 		return 1024;
398 	}
399 }
400 
401 struct spdk_ring_ele {
402 	void *ele;
403 	TAILQ_ENTRY(spdk_ring_ele) link;
404 };
405 
406 struct spdk_ring {
407 	TAILQ_HEAD(, spdk_ring_ele) elements;
408 	pthread_mutex_t lock;
409 	size_t count;
410 };
411 
412 DEFINE_RETURN_MOCK(spdk_ring_create, struct spdk_ring *);
413 struct spdk_ring *
414 spdk_ring_create(enum spdk_ring_type type, size_t count, int socket_id)
415 {
416 	struct spdk_ring *ring;
417 
418 	HANDLE_RETURN_MOCK(spdk_ring_create);
419 
420 	ring = calloc(1, sizeof(*ring));
421 	if (!ring) {
422 		return NULL;
423 	}
424 
425 	if (pthread_mutex_init(&ring->lock, NULL)) {
426 		free(ring);
427 		return NULL;
428 	}
429 
430 	TAILQ_INIT(&ring->elements);
431 	return ring;
432 }
433 
434 void
435 spdk_ring_free(struct spdk_ring *ring)
436 {
437 	struct spdk_ring_ele *ele, *tmp;
438 
439 	if (!ring) {
440 		return;
441 	}
442 
443 	TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) {
444 		free(ele);
445 	}
446 
447 	pthread_mutex_destroy(&ring->lock);
448 	free(ring);
449 }
450 
451 DEFINE_RETURN_MOCK(spdk_ring_enqueue, size_t);
452 size_t
453 spdk_ring_enqueue(struct spdk_ring *ring, void **objs, size_t count,
454 		  size_t *free_space)
455 {
456 	struct spdk_ring_ele *ele;
457 	size_t i;
458 
459 	HANDLE_RETURN_MOCK(spdk_ring_enqueue);
460 
461 	pthread_mutex_lock(&ring->lock);
462 
463 	for (i = 0; i < count; i++) {
464 		ele = calloc(1, sizeof(*ele));
465 		if (!ele) {
466 			break;
467 		}
468 
469 		ele->ele = objs[i];
470 		TAILQ_INSERT_TAIL(&ring->elements, ele, link);
471 		ring->count++;
472 	}
473 
474 	pthread_mutex_unlock(&ring->lock);
475 	return i;
476 }
477 
478 DEFINE_RETURN_MOCK(spdk_ring_dequeue, size_t);
479 size_t
480 spdk_ring_dequeue(struct spdk_ring *ring, void **objs, size_t count)
481 {
482 	struct spdk_ring_ele *ele, *tmp;
483 	size_t i = 0;
484 
485 	HANDLE_RETURN_MOCK(spdk_ring_dequeue);
486 
487 	if (count == 0) {
488 		return 0;
489 	}
490 
491 	pthread_mutex_lock(&ring->lock);
492 
493 	TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) {
494 		TAILQ_REMOVE(&ring->elements, ele, link);
495 		ring->count--;
496 		objs[i] = ele->ele;
497 		free(ele);
498 		i++;
499 		if (i >= count) {
500 			break;
501 		}
502 	}
503 
504 	pthread_mutex_unlock(&ring->lock);
505 	return i;
506 
507 }
508 
509 
510 DEFINE_RETURN_MOCK(spdk_ring_count, size_t);
511 size_t
512 spdk_ring_count(struct spdk_ring *ring)
513 {
514 	HANDLE_RETURN_MOCK(spdk_ring_count);
515 	return ring->count;
516 }
517 
518 DEFINE_RETURN_MOCK(spdk_get_ticks, uint64_t);
519 uint64_t
520 spdk_get_ticks(void)
521 {
522 	HANDLE_RETURN_MOCK(spdk_get_ticks);
523 
524 	return ut_spdk_get_ticks;
525 }
526 
527 DEFINE_RETURN_MOCK(spdk_get_ticks_hz, uint64_t);
528 uint64_t
529 spdk_get_ticks_hz(void)
530 {
531 	HANDLE_RETURN_MOCK(spdk_get_ticks_hz);
532 
533 	return 1000000;
534 }
535 
536 void
537 spdk_delay_us(unsigned int us)
538 {
539 	/* spdk_get_ticks_hz is 1000000, meaning 1 tick per us. */
540 	ut_spdk_get_ticks += us;
541 }
542 
543 #ifndef UNIT_TEST_NO_PCI_ADDR
544 DEFINE_RETURN_MOCK(spdk_pci_addr_parse, int);
545 int
546 spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf)
547 {
548 	unsigned domain, bus, dev, func;
549 
550 	HANDLE_RETURN_MOCK(spdk_pci_addr_parse);
551 
552 	if (addr == NULL || bdf == NULL) {
553 		return -EINVAL;
554 	}
555 
556 	if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) ||
557 	    (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) {
558 		/* Matched a full address - all variables are initialized */
559 	} else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) {
560 		func = 0;
561 	} else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) ||
562 		   (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) {
563 		domain = 0;
564 	} else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) ||
565 		   (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) {
566 		domain = 0;
567 		func = 0;
568 	} else {
569 		return -EINVAL;
570 	}
571 
572 	if (bus > 0xFF || dev > 0x1F || func > 7) {
573 		return -EINVAL;
574 	}
575 
576 	addr->domain = domain;
577 	addr->bus = bus;
578 	addr->dev = dev;
579 	addr->func = func;
580 
581 	return 0;
582 }
583 
584 DEFINE_RETURN_MOCK(spdk_pci_addr_fmt, int);
585 int
586 spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr)
587 {
588 	int rc;
589 
590 	HANDLE_RETURN_MOCK(spdk_pci_addr_fmt);
591 
592 	rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x",
593 		      addr->domain, addr->bus,
594 		      addr->dev, addr->func);
595 
596 	if (rc > 0 && (size_t)rc < sz) {
597 		return 0;
598 	}
599 
600 	return -1;
601 }
602 
603 DEFINE_RETURN_MOCK(spdk_pci_addr_compare, int);
604 int
605 spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2)
606 {
607 	HANDLE_RETURN_MOCK(spdk_pci_addr_compare);
608 
609 	if (a1->domain > a2->domain) {
610 		return 1;
611 	} else if (a1->domain < a2->domain) {
612 		return -1;
613 	} else if (a1->bus > a2->bus) {
614 		return 1;
615 	} else if (a1->bus < a2->bus) {
616 		return -1;
617 	} else if (a1->dev > a2->dev) {
618 		return 1;
619 	} else if (a1->dev < a2->dev) {
620 		return -1;
621 	} else if (a1->func > a2->func) {
622 		return 1;
623 	} else if (a1->func < a2->func) {
624 		return -1;
625 	}
626 
627 	return 0;
628 }
629 #endif
630