1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 */
4
5 #include "spdk/stdinc.h"
6 #include "spdk_internal/cunit.h"
7 #include "spdk_internal/mock.h"
8 #include "common/lib/test_env.c"
9 #include "rdma_utils/rdma_utils.c"
10
11 DEFINE_STUB(spdk_mem_map_alloc, struct spdk_mem_map *, (uint64_t default_translation,
12 const struct spdk_mem_map_ops *ops, void *cb_ctx), NULL);
13 DEFINE_STUB_V(spdk_mem_map_free, (struct spdk_mem_map **pmap));
14 DEFINE_STUB(spdk_mem_map_set_translation, int, (struct spdk_mem_map *map, uint64_t vaddr,
15 uint64_t size, uint64_t translation), 0);
16 DEFINE_STUB(spdk_mem_map_clear_translation, int, (struct spdk_mem_map *map, uint64_t vaddr,
17 uint64_t size), 0);
18 DEFINE_STUB(spdk_mem_map_translate, uint64_t, (const struct spdk_mem_map *map, uint64_t vaddr,
19 uint64_t *size), 0);
20 DEFINE_STUB(spdk_memory_domain_create, int, (struct spdk_memory_domain **_domain,
21 enum spdk_dma_device_type type,
22 struct spdk_memory_domain_ctx *ctx, const char *id), 0);
23 DEFINE_STUB_V(spdk_memory_domain_destroy, (struct spdk_memory_domain *domain));
24
25 struct ut_rdma_device {
26 struct ibv_context *context;
27 bool removed;
28 TAILQ_ENTRY(ut_rdma_device) tailq;
29 };
30
31 static TAILQ_HEAD(, ut_rdma_device) g_ut_dev_list = TAILQ_HEAD_INITIALIZER(g_ut_dev_list);
32
33 struct ibv_context **
rdma_get_devices(int * num_devices)34 rdma_get_devices(int *num_devices)
35 {
36 struct ibv_context **ctx_list;
37 struct ut_rdma_device *ut_dev;
38 int num_ut_devs = 0;
39 int i = 0;
40
41 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) {
42 if (!ut_dev->removed) {
43 num_ut_devs++;
44 }
45 }
46
47 ctx_list = malloc(sizeof(*ctx_list) * (num_ut_devs + 1));
48 SPDK_CU_ASSERT_FATAL(ctx_list);
49
50 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) {
51 if (!ut_dev->removed) {
52 ctx_list[i++] = ut_dev->context;
53 }
54 }
55 ctx_list[i] = NULL;
56
57 if (num_devices) {
58 *num_devices = num_ut_devs;
59 }
60
61 return ctx_list;
62 }
63
64 void
rdma_free_devices(struct ibv_context ** list)65 rdma_free_devices(struct ibv_context **list)
66 {
67 free(list);
68 }
69
70 struct ibv_pd *
ibv_alloc_pd(struct ibv_context * context)71 ibv_alloc_pd(struct ibv_context *context)
72 {
73 struct ibv_pd *pd;
74 struct ut_rdma_device *ut_dev;
75
76 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) {
77 if (ut_dev->context == context && !ut_dev->removed) {
78 break;
79 }
80 }
81
82 if (!ut_dev) {
83 return NULL;
84 }
85
86 pd = calloc(1, sizeof(*pd));
87 SPDK_CU_ASSERT_FATAL(pd);
88
89 pd->context = context;
90
91 return pd;
92 }
93
94 int
ibv_dealloc_pd(struct ibv_pd * pd)95 ibv_dealloc_pd(struct ibv_pd *pd)
96 {
97 free(pd);
98
99 return 0;
100 }
101
102 static struct ut_rdma_device *
ut_rdma_add_dev(struct ibv_context * context)103 ut_rdma_add_dev(struct ibv_context *context)
104 {
105 struct ut_rdma_device *ut_dev;
106
107 ut_dev = calloc(1, sizeof(*ut_dev));
108 if (!ut_dev) {
109 return NULL;
110 }
111
112 ut_dev->context = context;
113 TAILQ_INSERT_TAIL(&g_ut_dev_list, ut_dev, tailq);
114
115 return ut_dev;
116 }
117
118 static void
ut_rdma_remove_dev(struct ut_rdma_device * ut_dev)119 ut_rdma_remove_dev(struct ut_rdma_device *ut_dev)
120 {
121 TAILQ_REMOVE(&g_ut_dev_list, ut_dev, tailq);
122 free(ut_dev);
123 }
124
125 static struct rdma_utils_device *
_rdma_get_dev(struct ibv_context * context)126 _rdma_get_dev(struct ibv_context *context)
127 {
128 struct rdma_utils_device *dev;
129
130 TAILQ_FOREACH(dev, &g_dev_list, tailq) {
131 if (dev->context == context) {
132 break;
133 }
134 }
135
136 return dev;
137 }
138
139 static void
test_spdk_rdma_pd(void)140 test_spdk_rdma_pd(void)
141 {
142 struct ut_rdma_device *ut_dev0, *ut_dev1, *ut_dev2;
143 struct ibv_pd *pd1, *pd1_1, *pd2;
144
145 ut_dev0 = ut_rdma_add_dev((struct ibv_context *)0xface);
146 SPDK_CU_ASSERT_FATAL(ut_dev0 != NULL);
147
148 ut_dev1 = ut_rdma_add_dev((struct ibv_context *)0xc0ffee);
149 SPDK_CU_ASSERT_FATAL(ut_dev1 != NULL);
150
151 ut_dev2 = ut_rdma_add_dev((struct ibv_context *)0xf00d);
152 SPDK_CU_ASSERT_FATAL(ut_dev2 != NULL);
153
154 /* There are ut_dev0 and ut_dev1. */
155 ut_dev2->removed = true;
156
157 /* Call spdk_rdma_get_pd() to non-existent ut_dev2. */
158 pd2 = spdk_rdma_utils_get_pd(ut_dev2->context);
159
160 /* Then, spdk_rdma_utils_get_pd() should return NULL and g_dev_list should have dev0 and dev1. */
161 CU_ASSERT(pd2 == NULL);
162 CU_ASSERT(_rdma_get_dev(ut_dev0->context) != NULL);
163 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL);
164 CU_ASSERT(_rdma_get_dev(ut_dev2->context) == NULL);
165
166 /* Remove ut_dev0 and add ut_dev2. */
167 ut_dev0->removed = true;
168 ut_dev2->removed = false;
169
170 /* Call spdk_rdma_utils_get_pd() to ut_dev1. */
171 pd1 = spdk_rdma_utils_get_pd(ut_dev1->context);
172
173 /* Then, spdk_rdma_utils_get_pd() should return pd1 and g_dev_list should have dev1 and dev2. */
174 CU_ASSERT(pd1 != NULL);
175 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL);
176 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL);
177 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL);
178
179 /* Remove ut_dev1. */
180 ut_dev1->removed = true;
181
182 /* Call spdk_rdma_utils_get_pd() again to ut_dev1 which does not exist anymore. */
183 pd1_1 = spdk_rdma_utils_get_pd(ut_dev1->context);
184
185 /* Then, spdk_rdma_utils_get_pd() should return NULL and g_dev_list should still have dev1. */
186 CU_ASSERT(pd1_1 == NULL);
187 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL);
188 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL);
189 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL);
190
191 /* Call spdk_rdma_utils_put_pd() to pd1. */
192 spdk_rdma_utils_put_pd(pd1);
193
194 /* Then, dev1 should be removed from g_dev_list. */
195 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL);
196 CU_ASSERT(_rdma_get_dev(ut_dev1->context) == NULL);
197 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL);
198
199 /* Call spdk_rdma_utils_get_pd() to ut_dev2. */
200 pd2 = spdk_rdma_utils_get_pd(ut_dev2->context);
201
202 /* spdk_rdma_utils_get_pd() should succeed and g_dev_list should still have dev2
203 * even after spdk_rdma_utils_put_pd() is called to pd2.
204 */
205 CU_ASSERT(pd2 != NULL);
206
207 spdk_rdma_utils_put_pd(pd2);
208
209 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL);
210 CU_ASSERT(_rdma_get_dev(ut_dev1->context) == NULL);
211 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL);
212
213 _rdma_utils_fini();
214
215 ut_rdma_remove_dev(ut_dev0);
216 ut_rdma_remove_dev(ut_dev1);
217 ut_rdma_remove_dev(ut_dev2);
218 }
219
220 int
main(int argc,char ** argv)221 main(int argc, char **argv)
222 {
223 CU_pSuite suite = NULL;
224 unsigned int num_failures;
225
226 CU_initialize_registry();
227
228 suite = CU_add_suite("rdma_common", NULL, NULL);
229 CU_ADD_TEST(suite, test_spdk_rdma_pd);
230
231 num_failures = spdk_ut_run_tests(argc, argv, NULL);
232 CU_cleanup_registry();
233 return num_failures;
234 }
235