Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk_internal/cunit.h"
8 : : #include "nvme/nvme_rdma.c"
9 : : #include "common/lib/nvme/common_stubs.h"
10 : : #include "common/lib/test_rdma.c"
11 : :
12 : 3 : SPDK_LOG_REGISTER_COMPONENT(nvme)
13 : :
14 [ # # ]: 0 : 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 [ # # ]: 0 : DEFINE_STUB(spdk_mem_map_clear_translation, int, (struct spdk_mem_map *map, uint64_t vaddr,
17 : : uint64_t size), 0);
18 : :
19 [ # # ]: 0 : DEFINE_STUB(spdk_mem_map_alloc, struct spdk_mem_map *, (uint64_t default_translation,
20 : : const struct spdk_mem_map_ops *ops, void *cb_ctx), NULL);
21 : 0 : DEFINE_STUB_V(spdk_mem_map_free, (struct spdk_mem_map **pmap));
22 : :
23 [ # # ]: 0 : DEFINE_STUB(nvme_poll_group_connect_qpair, int, (struct spdk_nvme_qpair *qpair), 0);
24 : :
25 : 0 : DEFINE_STUB_V(nvme_qpair_resubmit_requests, (struct spdk_nvme_qpair *qpair, uint32_t num_requests));
26 [ # # ]: 0 : DEFINE_STUB(spdk_nvme_poll_group_process_completions, int64_t, (struct spdk_nvme_poll_group *group,
27 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb), 0);
28 : :
29 [ - + - - ]: 36 : DEFINE_STUB(rdma_ack_cm_event, int, (struct rdma_cm_event *event), 0);
30 : 3 : DEFINE_STUB_V(rdma_free_devices, (struct ibv_context **list));
31 [ - + - - ]: 30 : DEFINE_STUB(fcntl, int, (int fd, int cmd, ...), 0);
32 : 3 : DEFINE_STUB_V(rdma_destroy_event_channel, (struct rdma_event_channel *channel));
33 : :
34 [ # # # # ]: 0 : DEFINE_STUB(ibv_dereg_mr, int, (struct ibv_mr *mr), 0);
35 [ - + - - ]: 6 : DEFINE_STUB(ibv_resize_cq, int, (struct ibv_cq *cq, int cqe), 0);
36 : :
37 [ # # ]: 0 : DEFINE_STUB(spdk_memory_domain_get_context, struct spdk_memory_domain_ctx *,
38 : : (struct spdk_memory_domain *device), NULL);
39 [ # # ]: 0 : DEFINE_STUB(spdk_memory_domain_get_dma_device_type, enum spdk_dma_device_type,
40 : : (struct spdk_memory_domain *device), SPDK_DMA_DEVICE_TYPE_RDMA);
41 : 0 : DEFINE_STUB_V(spdk_memory_domain_destroy, (struct spdk_memory_domain *device));
42 [ # # ]: 0 : DEFINE_STUB(spdk_memory_domain_pull_data, int, (struct spdk_memory_domain *src_domain,
43 : : void *src_domain_ctx, struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov,
44 : : uint32_t dst_iov_cnt, spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg), 0);
45 [ # # ]: 0 : DEFINE_STUB(spdk_rdma_cm_id_get_numa_id, int32_t, (struct rdma_cm_id *cm_id), 0);
46 : :
47 : 0 : DEFINE_STUB_V(spdk_nvme_qpair_print_command, (struct spdk_nvme_qpair *qpair,
48 : : struct spdk_nvme_cmd *cmd));
49 : :
50 : 0 : DEFINE_STUB_V(spdk_nvme_qpair_print_completion, (struct spdk_nvme_qpair *qpair,
51 : : struct spdk_nvme_cpl *cpl));
52 : :
53 [ # # ]: 0 : DEFINE_RETURN_MOCK(spdk_memory_domain_create, int);
54 : : int
55 : 0 : spdk_memory_domain_create(struct spdk_memory_domain **domain, enum spdk_dma_device_type type,
56 : : struct spdk_memory_domain_ctx *ctx, const char *id)
57 : : {
58 : : static struct spdk_memory_domain *__dma_dev = (struct spdk_memory_domain *)0xdeaddead;
59 : :
60 [ # # # # : 0 : HANDLE_RETURN_MOCK(spdk_memory_domain_create);
# # ]
61 : :
62 : 0 : *domain = __dma_dev;
63 : :
64 : 0 : return 0;
65 : : }
66 : :
67 : : static struct spdk_memory_domain_translation_result g_memory_translation_translation = {.size = sizeof(struct spdk_memory_domain_translation_result) };
68 : :
69 [ # # ]: 0 : DEFINE_RETURN_MOCK(spdk_memory_domain_translate_data, int);
70 : : int
71 : 6 : spdk_memory_domain_translate_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
72 : : struct spdk_memory_domain *dst_domain, struct spdk_memory_domain_translation_ctx *dst_domain_ctx,
73 : : void *addr, size_t len, struct spdk_memory_domain_translation_result *result)
74 : : {
75 : :
76 [ - + + + : 6 : HANDLE_RETURN_MOCK(spdk_memory_domain_translate_data);
+ + ]
77 : :
78 [ - + - + ]: 3 : memcpy(result, &g_memory_translation_translation, sizeof(g_memory_translation_translation));
79 : :
80 : 3 : return 0;
81 : : }
82 : :
83 : : /* ibv_reg_mr can be a macro, need to undefine it */
84 : : #ifdef ibv_reg_mr
85 : : #undef ibv_reg_mr
86 : : #endif
87 : :
88 [ # # ]: 0 : DEFINE_RETURN_MOCK(ibv_reg_mr, struct ibv_mr *);
89 : : struct ibv_mr *
90 : : ibv_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
91 : : {
92 [ # # # # : 0 : HANDLE_RETURN_MOCK(ibv_reg_mr);
# # ]
93 [ # # ]: 0 : if (length > 0) {
94 : 0 : return &g_rdma_mr;
95 : : } else {
96 : 0 : return NULL;
97 : : }
98 : : }
99 : :
100 : : struct nvme_rdma_ut_bdev_io {
101 : : struct iovec iovs[NVME_RDMA_MAX_SGL_DESCRIPTORS];
102 : : int iovpos;
103 : : int iovcnt;
104 : : };
105 : :
106 [ # # ]: 0 : DEFINE_RETURN_MOCK(rdma_get_devices, struct ibv_context **);
107 : : struct ibv_context **
108 : : rdma_get_devices(int *num_devices)
109 : : {
110 : : static struct ibv_context *_contexts[] = {
111 : : (struct ibv_context *)0xDEADBEEF,
112 : : (struct ibv_context *)0xFEEDBEEF,
113 : : NULL
114 : : };
115 : :
116 [ - + - + : 3 : HANDLE_RETURN_MOCK(rdma_get_devices);
- + ]
117 : 3 : return _contexts;
118 : : }
119 : :
120 [ # # ]: 0 : DEFINE_RETURN_MOCK(rdma_create_event_channel, struct rdma_event_channel *);
121 : : struct rdma_event_channel *
122 : : rdma_create_event_channel(void)
123 : : {
124 [ - + + + : 3 : HANDLE_RETURN_MOCK(rdma_create_event_channel);
+ - ]
125 : 0 : return NULL;
126 : : }
127 : :
128 [ # # ]: 0 : DEFINE_RETURN_MOCK(ibv_query_device, int);
129 : : int
130 : : ibv_query_device(struct ibv_context *context,
131 : : struct ibv_device_attr *device_attr)
132 : : {
133 [ + - ]: 9 : if (device_attr) {
134 : 9 : device_attr->max_sge = NVME_RDMA_MAX_SGL_DESCRIPTORS;
135 : : }
136 [ - + - + : 9 : HANDLE_RETURN_MOCK(ibv_query_device);
- + ]
137 : :
138 : 9 : return 0;
139 : : }
140 : :
141 : : /* essentially a simplification of bdev_nvme_next_sge and bdev_nvme_reset_sgl */
142 : : static void
143 : 30 : nvme_rdma_ut_reset_sgl(void *cb_arg, uint32_t offset)
144 : : {
145 : 30 : struct nvme_rdma_ut_bdev_io *bio = cb_arg;
146 : : struct iovec *iov;
147 : :
148 [ + - ]: 30 : for (bio->iovpos = 0; bio->iovpos < NVME_RDMA_MAX_SGL_DESCRIPTORS; bio->iovpos++) {
149 : 30 : iov = &bio->iovs[bio->iovpos];
150 : : /* Only provide offsets at the beginning of an iov */
151 [ + - ]: 30 : if (offset == 0) {
152 : 30 : break;
153 : : }
154 : :
155 : 0 : offset -= iov->iov_len;
156 : : }
157 : :
158 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(bio->iovpos < NVME_RDMA_MAX_SGL_DESCRIPTORS);
159 : 30 : }
160 : :
161 : : static int
162 : 63 : nvme_rdma_ut_next_sge(void *cb_arg, void **address, uint32_t *length)
163 : : {
164 : 63 : struct nvme_rdma_ut_bdev_io *bio = cb_arg;
165 : : struct iovec *iov;
166 : :
167 [ - + ]: 63 : SPDK_CU_ASSERT_FATAL(bio->iovpos < NVME_RDMA_MAX_SGL_DESCRIPTORS);
168 : :
169 [ + + ]: 63 : if (bio->iovpos == bio->iovcnt) {
170 : 3 : return -1;
171 : : }
172 : :
173 : 60 : iov = &bio->iovs[bio->iovpos];
174 : :
175 : 60 : *address = iov->iov_base;
176 : 60 : *length = iov->iov_len;
177 : 60 : bio->iovpos++;
178 : :
179 : 60 : return 0;
180 : : }
181 : :
182 : : static void
183 : 3 : test_nvme_rdma_build_sgl_request(void)
184 : : {
185 : 3 : struct nvme_rdma_qpair rqpair;
186 : 3 : struct spdk_nvme_ctrlr ctrlr = {0};
187 : 3 : struct spdk_nvmf_cmd cmd = {{0}};
188 : 3 : struct spdk_nvme_rdma_req rdma_req = {0};
189 : 3 : struct nvme_request req = {{0}};
190 : 3 : struct nvme_rdma_ut_bdev_io bio = { .iovcnt = NVME_RDMA_MAX_SGL_DESCRIPTORS };
191 : : uint64_t i;
192 : : int rc;
193 : :
194 : 3 : ctrlr.max_sges = NVME_RDMA_MAX_SGL_DESCRIPTORS;
195 : 3 : ctrlr.cdata.nvmf_specific.msdbd = 16;
196 : 3 : ctrlr.ioccsz_bytes = 4096;
197 : :
198 : 3 : rqpair.mr_map = (struct spdk_rdma_utils_mem_map *)0xdeadbeef;
199 : 3 : rqpair.rdma_qp = (struct spdk_rdma_provider_qp *)0xdeadbeef;
200 : 3 : rqpair.qpair.ctrlr = &ctrlr;
201 : 3 : rqpair.cmds = &cmd;
202 : 3 : cmd.sgl[0].address = 0x1111;
203 : 3 : rdma_req.id = 0;
204 : 3 : rdma_req.req = &req;
205 : :
206 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_rdma_ut_reset_sgl, nvme_rdma_ut_next_sge, &bio, NULL);
207 : 3 : req.qpair = &rqpair.qpair;
208 : :
209 [ + + ]: 51 : for (i = 0; i < NVME_RDMA_MAX_SGL_DESCRIPTORS; i++) {
210 : 48 : bio.iovs[i].iov_base = (void *)0xF00000000 + i + 1;
211 : 48 : bio.iovs[i].iov_len = 0;
212 : : }
213 : :
214 : : /* Test case 1: single SGL. Expected: PASS */
215 : 3 : bio.iovpos = 0;
216 : 3 : req.payload_offset = 0;
217 : 3 : req.payload_size = 0x1000;
218 : 3 : bio.iovs[0].iov_len = 0x1000;
219 : 3 : rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req);
220 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
221 : 3 : CU_ASSERT(bio.iovpos == 1);
222 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.type == SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK);
223 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.subtype == SPDK_NVME_SGL_SUBTYPE_ADDRESS);
224 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.length == req.payload_size);
225 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.key == RDMA_UT_RKEY);
226 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == (uint64_t)bio.iovs[0].iov_base);
227 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
228 : :
229 : : /* Test case 2: multiple SGL. Expected: PASS */
230 : 3 : bio.iovpos = 0;
231 : 3 : req.payload_offset = 0;
232 : 3 : req.payload_size = 0x4000;
233 [ + + ]: 15 : for (i = 0; i < 4; i++) {
234 : 12 : bio.iovs[i].iov_len = 0x1000;
235 : : }
236 : 3 : rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req);
237 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
238 : 3 : CU_ASSERT(bio.iovpos == 4);
239 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_LAST_SEGMENT);
240 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
241 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == 4 * sizeof(struct spdk_nvme_sgl_descriptor));
242 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == (uint64_t)0);
243 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == 4 * sizeof(struct spdk_nvme_sgl_descriptor) + sizeof(
244 : : struct spdk_nvme_cmd))
245 [ + + ]: 15 : for (i = 0; i < 4; i++) {
246 : 12 : CU_ASSERT(cmd.sgl[i].keyed.type == SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK);
247 : 12 : CU_ASSERT(cmd.sgl[i].keyed.subtype == SPDK_NVME_SGL_SUBTYPE_ADDRESS);
248 : 12 : CU_ASSERT(cmd.sgl[i].keyed.length == bio.iovs[i].iov_len);
249 : 12 : CU_ASSERT(cmd.sgl[i].keyed.key == RDMA_UT_RKEY);
250 : 12 : CU_ASSERT(cmd.sgl[i].address == (uint64_t)bio.iovs[i].iov_base);
251 : : }
252 : :
253 : : /* Test case 3: Multiple SGL, SGL 2X mr size. Expected: FAIL */
254 : 3 : bio.iovpos = 0;
255 : 3 : req.payload_offset = 0;
256 : 3 : g_mr_size = 0x800;
257 : 3 : rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req);
258 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != 0);
259 : 3 : CU_ASSERT(bio.iovpos == 1);
260 : :
261 : : /* Test case 4: Multiple SGL, SGL size smaller than I/O size. Expected: FAIL */
262 : 3 : bio.iovpos = 0;
263 : 3 : bio.iovcnt = 4;
264 : 3 : req.payload_offset = 0;
265 : 3 : req.payload_size = 0x6000;
266 : 3 : g_mr_size = 0x0;
267 : 3 : rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req);
268 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != 0);
269 : 3 : CU_ASSERT(bio.iovpos == bio.iovcnt);
270 : 3 : bio.iovcnt = NVME_RDMA_MAX_SGL_DESCRIPTORS;
271 : :
272 : : /* Test case 5: SGL length exceeds 3 bytes. Expected: FAIL */
273 : 3 : req.payload_size = 0x1000 + (1 << 24);
274 : 3 : bio.iovs[0].iov_len = 0x1000;
275 : 3 : bio.iovs[1].iov_len = 1 << 24;
276 : 3 : rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req);
277 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != 0);
278 : :
279 : : /* Test case 6: 4 SGL descriptors, size of SGL descriptors exceeds ICD. Expected: FAIL */
280 : 3 : ctrlr.ioccsz_bytes = 60;
281 : 3 : bio.iovpos = 0;
282 : 3 : req.payload_offset = 0;
283 : 3 : req.payload_size = 0x4000;
284 [ + + ]: 15 : for (i = 0; i < 4; i++) {
285 : 12 : bio.iovs[i].iov_len = 0x1000;
286 : : }
287 : 3 : rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req);
288 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == -1);
289 : 3 : }
290 : :
291 : : static void
292 : 3 : test_nvme_rdma_build_sgl_inline_request(void)
293 : : {
294 : 3 : struct nvme_rdma_qpair rqpair;
295 : 3 : struct spdk_nvme_ctrlr ctrlr = {0};
296 : 3 : struct spdk_nvmf_cmd cmd = {{0}};
297 : 3 : struct spdk_nvme_rdma_req rdma_req = {0};
298 : 3 : struct nvme_request req = {{0}};
299 : 3 : struct nvme_rdma_ut_bdev_io bio = { .iovcnt = NVME_RDMA_MAX_SGL_DESCRIPTORS };
300 : : int rc;
301 : :
302 : 3 : ctrlr.max_sges = NVME_RDMA_MAX_SGL_DESCRIPTORS;
303 : 3 : ctrlr.cdata.nvmf_specific.msdbd = 16;
304 : :
305 : 3 : rqpair.mr_map = (struct spdk_rdma_utils_mem_map *)0xdeadbeef;
306 : 3 : rqpair.rdma_qp = (struct spdk_rdma_provider_qp *)0xdeadbeef;
307 : 3 : rqpair.qpair.ctrlr = &ctrlr;
308 : 3 : rqpair.cmds = &cmd;
309 : 3 : cmd.sgl[0].address = 0x1111;
310 : 3 : rdma_req.id = 0;
311 : 3 : rdma_req.req = &req;
312 : :
313 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_rdma_ut_reset_sgl, nvme_rdma_ut_next_sge, &bio, NULL);
314 : 3 : req.qpair = &rqpair.qpair;
315 : :
316 : : /* Test case 1: single inline SGL. Expected: PASS */
317 : 3 : bio.iovpos = 0;
318 : 3 : req.payload_offset = 0;
319 : 3 : req.payload_size = 0x1000;
320 : 3 : bio.iovs[0].iov_base = (void *)0xdeadbeef;
321 : 3 : bio.iovs[0].iov_len = 0x1000;
322 : 3 : rc = nvme_rdma_build_sgl_inline_request(&rqpair, &rdma_req);
323 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
324 : 3 : CU_ASSERT(bio.iovpos == 1);
325 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
326 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
327 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
328 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
329 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
330 : 3 : CU_ASSERT(rdma_req.send_sgl[1].length == req.payload_size);
331 : 3 : CU_ASSERT(rdma_req.send_sgl[1].addr == (uint64_t)bio.iovs[0].iov_base);
332 : 3 : CU_ASSERT(rdma_req.send_sgl[1].lkey == RDMA_UT_LKEY);
333 : :
334 : : /* Test case 2: SGL length exceeds 3 bytes. Expected: PASS */
335 : 3 : bio.iovpos = 0;
336 : 3 : req.payload_offset = 0;
337 : 3 : req.payload_size = 1 << 24;
338 : 3 : bio.iovs[0].iov_len = 1 << 24;
339 : 3 : rc = nvme_rdma_build_sgl_inline_request(&rqpair, &rdma_req);
340 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
341 : 3 : CU_ASSERT(bio.iovpos == 1);
342 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
343 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
344 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
345 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
346 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
347 : 3 : CU_ASSERT(rdma_req.send_sgl[1].length == req.payload_size);
348 : 3 : CU_ASSERT(rdma_req.send_sgl[1].addr == (uint64_t)bio.iovs[0].iov_base);
349 : 3 : CU_ASSERT(rdma_req.send_sgl[1].lkey == RDMA_UT_LKEY);
350 : 3 : }
351 : :
352 : : static void
353 : 3 : test_nvme_rdma_build_contig_request(void)
354 : : {
355 : 3 : struct nvme_rdma_qpair rqpair;
356 : 3 : struct spdk_nvme_ctrlr ctrlr = {0};
357 : 3 : struct spdk_nvmf_cmd cmd = {{0}};
358 : 3 : struct spdk_nvme_rdma_req rdma_req = {0};
359 : 3 : struct nvme_request req = {{0}};
360 : : int rc;
361 : :
362 : 3 : ctrlr.max_sges = NVME_RDMA_MAX_SGL_DESCRIPTORS;
363 : 3 : ctrlr.cdata.nvmf_specific.msdbd = 16;
364 : :
365 : 3 : rqpair.mr_map = (struct spdk_rdma_utils_mem_map *)0xdeadbeef;
366 : 3 : rqpair.rdma_qp = (struct spdk_rdma_provider_qp *)0xdeadbeef;
367 : 3 : rqpair.qpair.ctrlr = &ctrlr;
368 : 3 : rqpair.cmds = &cmd;
369 : 3 : cmd.sgl[0].address = 0x1111;
370 : 3 : rdma_req.id = 0;
371 : 3 : rdma_req.req = &req;
372 : :
373 : 3 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xdeadbeef, NULL);
374 : 3 : req.qpair = &rqpair.qpair;
375 : :
376 : : /* Test case 1: contig request. Expected: PASS */
377 : 3 : req.payload_offset = 0;
378 : 3 : req.payload_size = 0x1000;
379 : 3 : rc = nvme_rdma_build_contig_request(&rqpair, &rdma_req);
380 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
381 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.type == SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK);
382 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.subtype == SPDK_NVME_SGL_SUBTYPE_ADDRESS);
383 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.length == req.payload_size);
384 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.key == RDMA_UT_RKEY);
385 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == (uint64_t)req.payload.contig_or_cb_arg);
386 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
387 : :
388 : : /* Test case 2: SGL length exceeds 3 bytes. Expected: FAIL */
389 : 3 : req.payload_offset = 0;
390 : 3 : req.payload_size = 1 << 24;
391 : 3 : rc = nvme_rdma_build_contig_request(&rqpair, &rdma_req);
392 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != 0);
393 : 3 : }
394 : :
395 : : static void
396 : 3 : test_nvme_rdma_build_contig_inline_request(void)
397 : : {
398 : 3 : struct nvme_rdma_qpair rqpair;
399 : 3 : struct spdk_nvme_ctrlr ctrlr = {0};
400 : 3 : struct spdk_nvmf_cmd cmd = {{0}};
401 : 3 : struct spdk_nvme_rdma_req rdma_req = {0};
402 : 3 : struct nvme_request req = {{0}};
403 : : int rc;
404 : :
405 : 3 : ctrlr.max_sges = NVME_RDMA_MAX_SGL_DESCRIPTORS;
406 : 3 : ctrlr.cdata.nvmf_specific.msdbd = 16;
407 : :
408 : 3 : rqpair.mr_map = (struct spdk_rdma_utils_mem_map *)0xdeadbeef;
409 : 3 : rqpair.rdma_qp = (struct spdk_rdma_provider_qp *)0xdeadbeef;
410 : 3 : rqpair.qpair.ctrlr = &ctrlr;
411 : 3 : rqpair.cmds = &cmd;
412 : 3 : cmd.sgl[0].address = 0x1111;
413 : 3 : rdma_req.id = 0;
414 : 3 : rdma_req.req = &req;
415 : :
416 : 3 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xdeadbeef, NULL);
417 : 3 : req.qpair = &rqpair.qpair;
418 : :
419 : : /* Test case 1: single inline SGL. Expected: PASS */
420 : 3 : req.payload_offset = 0;
421 : 3 : req.payload_size = 0x1000;
422 : 3 : rc = nvme_rdma_build_contig_inline_request(&rqpair, &rdma_req);
423 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
424 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
425 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
426 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
427 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
428 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
429 : 3 : CU_ASSERT(rdma_req.send_sgl[1].length == req.payload_size);
430 : 3 : CU_ASSERT(rdma_req.send_sgl[1].addr == (uint64_t)req.payload.contig_or_cb_arg);
431 : 3 : CU_ASSERT(rdma_req.send_sgl[1].lkey == RDMA_UT_LKEY);
432 : :
433 : : /* Test case 2: SGL length exceeds 3 bytes. Expected: PASS */
434 : 3 : req.payload_offset = 0;
435 : 3 : req.payload_size = 1 << 24;
436 : 3 : rc = nvme_rdma_build_contig_inline_request(&rqpair, &rdma_req);
437 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
438 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
439 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
440 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
441 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
442 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
443 : 3 : CU_ASSERT(rdma_req.send_sgl[1].length == req.payload_size);
444 : 3 : CU_ASSERT(rdma_req.send_sgl[1].addr == (uint64_t)req.payload.contig_or_cb_arg);
445 : 3 : CU_ASSERT(rdma_req.send_sgl[1].lkey == RDMA_UT_LKEY);
446 : 3 : }
447 : :
448 : : static void
449 : 3 : test_nvme_rdma_create_reqs(void)
450 : : {
451 : 3 : struct nvme_rdma_qpair rqpair = {};
452 : : int rc;
453 : :
454 [ - + ]: 3 : memset(&g_nvme_hooks, 0, sizeof(g_nvme_hooks));
455 : :
456 : : /* Test case 1: zero entry. Expect: FAIL */
457 : 3 : rqpair.num_entries = 0;
458 : :
459 : 3 : rc = nvme_rdma_create_reqs(&rqpair);
460 : 3 : CU_ASSERT(rqpair.rdma_reqs == NULL);
461 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == -ENOMEM);
462 : :
463 : : /* Test case 2: single entry. Expect: PASS */
464 [ - + ]: 3 : memset(&rqpair, 0, sizeof(rqpair));
465 : 3 : rqpair.num_entries = 1;
466 : :
467 : 3 : rc = nvme_rdma_create_reqs(&rqpair);
468 : 3 : CU_ASSERT(rc == 0);
469 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_sgl[0].lkey == g_rdma_mr.lkey);
470 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_sgl[0].addr
471 : : == (uint64_t)&rqpair.cmds[0]);
472 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_wr.wr_id
473 : : == (uint64_t)&rqpair.rdma_reqs[0].rdma_wr);
474 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_wr.next == NULL);
475 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_wr.opcode == IBV_WR_SEND);
476 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_wr.send_flags == IBV_SEND_SIGNALED);
477 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_wr.sg_list
478 : : == rqpair.rdma_reqs[0].send_sgl);
479 : 3 : CU_ASSERT(rqpair.rdma_reqs[0].send_wr.imm_data == 0);
480 : 3 : spdk_free(rqpair.rdma_reqs);
481 : 3 : spdk_free(rqpair.cmds);
482 : :
483 : : /* Test case 3: multiple entries. Expect: PASS */
484 [ - + ]: 3 : memset(&rqpair, 0, sizeof(rqpair));
485 : 3 : rqpair.num_entries = 5;
486 : :
487 : 3 : rc = nvme_rdma_create_reqs(&rqpair);
488 : 3 : CU_ASSERT(rc == 0);
489 [ + + ]: 18 : for (int i = 0; i < 5; i++) {
490 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_sgl[0].lkey == g_rdma_mr.lkey);
491 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_sgl[0].addr
492 : : == (uint64_t)&rqpair.cmds[i]);
493 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_wr.wr_id
494 : : == (uint64_t)&rqpair.rdma_reqs[i].rdma_wr);
495 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_wr.next == NULL);
496 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_wr.opcode == IBV_WR_SEND);
497 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_wr.send_flags
498 : : == IBV_SEND_SIGNALED);
499 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_wr.sg_list
500 : : == rqpair.rdma_reqs[i].send_sgl);
501 : 15 : CU_ASSERT(rqpair.rdma_reqs[i].send_wr.imm_data == 0);
502 : : }
503 : 3 : spdk_free(rqpair.rdma_reqs);
504 : 3 : spdk_free(rqpair.cmds);
505 : 3 : }
506 : :
507 : : static void
508 : 3 : test_nvme_rdma_create_rsps(void)
509 : : {
510 : 3 : struct nvme_rdma_rsp_opts opts = {};
511 : : struct nvme_rdma_rsps *rsps;
512 : 3 : struct spdk_rdma_provider_qp *rdma_qp = (struct spdk_rdma_provider_qp *)0xfeedf00d;
513 : 3 : struct nvme_rdma_qpair rqpair = { .rdma_qp = rdma_qp, };
514 : :
515 [ - + ]: 3 : memset(&g_nvme_hooks, 0, sizeof(g_nvme_hooks));
516 : :
517 : 3 : opts.rqpair = &rqpair;
518 : :
519 : : /* Test case 1 calloc false */
520 : 3 : opts.num_entries = 0;
521 : 3 : rsps = nvme_rdma_create_rsps(&opts);
522 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rsps == NULL);
523 : :
524 : : /* Test case 2 calloc success */
525 : 3 : opts.num_entries = 1;
526 : :
527 : 3 : rsps = nvme_rdma_create_rsps(&opts);
528 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rsps != NULL);
529 : 3 : CU_ASSERT(rsps->rsp_sgls != NULL);
530 : 3 : CU_ASSERT(rsps->rsp_recv_wrs != NULL);
531 : 3 : CU_ASSERT(rsps->rsps != NULL);
532 : 3 : CU_ASSERT(rsps->rsp_sgls[0].lkey == g_rdma_mr.lkey);
533 : 3 : CU_ASSERT(rsps->rsp_sgls[0].addr == (uint64_t)&rsps->rsps[0]);
534 : 3 : CU_ASSERT(rsps->rsp_recv_wrs[0].wr_id == (uint64_t)&rsps->rsps[0].rdma_wr);
535 : :
536 : 3 : nvme_rdma_free_rsps(rsps);
537 : 3 : }
538 : :
539 : : static void
540 : 3 : test_nvme_rdma_ctrlr_create_qpair(void)
541 : : {
542 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
543 : : uint16_t qid, qsize;
544 : : struct spdk_nvme_qpair *qpair;
545 : : struct nvme_rdma_qpair *rqpair;
546 : :
547 : : /* Test case 1: max qsize. Expect: PASS */
548 : 3 : qsize = 0xffff;
549 : 3 : qid = 1;
550 : :
551 : 3 : qpair = nvme_rdma_ctrlr_create_qpair(&ctrlr, qid, qsize,
552 : : SPDK_NVME_QPRIO_URGENT, 1,
553 : : false, false);
554 : 3 : CU_ASSERT(qpair != NULL);
555 : 3 : rqpair = SPDK_CONTAINEROF(qpair, struct nvme_rdma_qpair, qpair);
556 : 3 : CU_ASSERT(qpair == &rqpair->qpair);
557 : 3 : CU_ASSERT(rqpair->num_entries == qsize - 1);
558 [ - + ]: 3 : CU_ASSERT(rqpair->delay_cmd_submit == false);
559 : :
560 : 3 : spdk_free(rqpair);
561 : 3 : rqpair = NULL;
562 : :
563 : : /* Test case 2: queue size 2. Expect: PASS */
564 : 3 : qsize = 2;
565 : 3 : qpair = nvme_rdma_ctrlr_create_qpair(&ctrlr, qid, qsize,
566 : : SPDK_NVME_QPRIO_URGENT, 1,
567 : : false, false);
568 : 3 : CU_ASSERT(qpair != NULL);
569 : 3 : rqpair = SPDK_CONTAINEROF(qpair, struct nvme_rdma_qpair, qpair);
570 : 3 : CU_ASSERT(rqpair->num_entries == qsize - 1);
571 : :
572 : 3 : spdk_free(rqpair);
573 : 3 : rqpair = NULL;
574 : :
575 : : /* Test case 3: queue size zero. Expect: FAIL */
576 : 3 : qsize = 0;
577 : :
578 : 3 : qpair = nvme_rdma_ctrlr_create_qpair(&ctrlr, qid, qsize,
579 : : SPDK_NVME_QPRIO_URGENT, 1,
580 : : false, false);
581 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(qpair == NULL);
582 : :
583 : : /* Test case 4: queue size 1. Expect: FAIL */
584 : 3 : qsize = 1;
585 : 3 : qpair = nvme_rdma_ctrlr_create_qpair(&ctrlr, qid, qsize,
586 : : SPDK_NVME_QPRIO_URGENT, 1,
587 : : false, false);
588 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(qpair == NULL);
589 : 3 : }
590 : :
591 [ - + - - ]: 30 : DEFINE_STUB(ibv_create_cq, struct ibv_cq *, (struct ibv_context *context, int cqe, void *cq_context,
592 : : struct ibv_comp_channel *channel, int comp_vector), (struct ibv_cq *)0xFEEDBEEF);
593 [ - + - - ]: 21 : DEFINE_STUB(ibv_destroy_cq, int, (struct ibv_cq *cq), 0);
594 : :
595 : : static void
596 : 3 : test_nvme_rdma_poller_create(void)
597 : : {
598 : 3 : struct nvme_rdma_poll_group group = {};
599 : 3 : struct ibv_context context = {
600 : : .device = (struct ibv_device *)0xDEADBEEF
601 : : };
602 : 3 : struct ibv_context context_2 = {
603 : : .device = (struct ibv_device *)0xBAADBEEF
604 : : };
605 : : struct nvme_rdma_poller *poller_1, *poller_2, *poller_3;
606 : :
607 : : /* Case: calloc and ibv not need to fail test */
608 : 3 : STAILQ_INIT(&group.pollers);
609 : :
610 : 3 : poller_1 = nvme_rdma_poll_group_get_poller(&group, &context);
611 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(poller_1 != NULL);
612 : 3 : CU_ASSERT(group.num_pollers == 1);
613 : 3 : CU_ASSERT(STAILQ_FIRST(&group.pollers) == poller_1);
614 : 3 : CU_ASSERT(poller_1->refcnt == 1);
615 : 3 : CU_ASSERT(poller_1->device == &context);
616 : 3 : CU_ASSERT(poller_1->cq == (struct ibv_cq *)0xFEEDBEEF);
617 : 3 : CU_ASSERT(poller_1->current_num_wc == DEFAULT_NVME_RDMA_CQ_SIZE);
618 : 3 : CU_ASSERT(poller_1->required_num_wc == 0);
619 : :
620 : 3 : poller_2 = nvme_rdma_poll_group_get_poller(&group, &context_2);
621 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(poller_2 != NULL);
622 : 3 : CU_ASSERT(group.num_pollers == 2);
623 : 3 : CU_ASSERT(STAILQ_FIRST(&group.pollers) == poller_2);
624 : 3 : CU_ASSERT(poller_2->refcnt == 1);
625 : 3 : CU_ASSERT(poller_2->device == &context_2);
626 : :
627 : 3 : poller_3 = nvme_rdma_poll_group_get_poller(&group, &context);
628 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(poller_3 != NULL);
629 : 3 : CU_ASSERT(poller_3 == poller_1);
630 : 3 : CU_ASSERT(group.num_pollers == 2);
631 : 3 : CU_ASSERT(poller_3->refcnt == 2);
632 : :
633 : 3 : nvme_rdma_poll_group_put_poller(&group, poller_2);
634 : 3 : CU_ASSERT(group.num_pollers == 1);
635 : :
636 : 3 : nvme_rdma_poll_group_put_poller(&group, poller_1);
637 : 3 : CU_ASSERT(group.num_pollers == 1);
638 : 3 : CU_ASSERT(poller_3->refcnt == 1);
639 : :
640 : 3 : nvme_rdma_poll_group_put_poller(&group, poller_3);
641 : 3 : CU_ASSERT(STAILQ_EMPTY(&group.pollers));
642 : 3 : CU_ASSERT(group.num_pollers == 0);
643 : :
644 : 3 : nvme_rdma_poll_group_free_pollers(&group);
645 : 3 : }
646 : :
647 : : static void
648 : 3 : test_nvme_rdma_qpair_process_cm_event(void)
649 : : {
650 : 3 : struct nvme_rdma_qpair rqpair = {};
651 : 3 : struct rdma_cm_event event = {};
652 : 3 : struct spdk_nvmf_rdma_accept_private_data accept_data = {};
653 : 3 : int rc = 0;
654 : :
655 : : /* case1: event == RDMA_CM_EVENT_ADDR_RESOLVED */
656 : 3 : rqpair.evt = &event;
657 : 3 : event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
658 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
659 : 3 : CU_ASSERT(rc == 0);
660 : :
661 : : /* case2: event == RDMA_CM_EVENT_CONNECT_REQUEST */
662 : 3 : rqpair.evt = &event;
663 : 3 : event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
664 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
665 : 3 : CU_ASSERT(rc == 0);
666 : :
667 : : /* case3: event == RDMA_CM_EVENT_CONNECT_ERROR */
668 : 3 : rqpair.evt = &event;
669 : 3 : event.event = RDMA_CM_EVENT_CONNECT_ERROR;
670 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
671 : 3 : CU_ASSERT(rc == 0);
672 : :
673 : : /* case4: event == RDMA_CM_EVENT_UNREACHABLE */
674 : 3 : rqpair.evt = &event;
675 : 3 : event.event = RDMA_CM_EVENT_UNREACHABLE;
676 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
677 : 3 : CU_ASSERT(rc == 0);
678 : :
679 : : /* case5: event == RDMA_CM_EVENT_CONNECT_RESPONSE */
680 : 3 : rqpair.evt = &event;
681 : 3 : event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
682 : 3 : event.param.conn.private_data = NULL;
683 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
684 : 3 : CU_ASSERT(rc == -1);
685 : :
686 : 3 : rqpair.evt = &event;
687 : 3 : event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
688 : 3 : event.param.conn.private_data = &accept_data;
689 : 3 : accept_data.crqsize = 512;
690 : 3 : rqpair.num_entries = 1024;
691 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
692 : 3 : CU_ASSERT(rc == 0);
693 : 3 : CU_ASSERT(rqpair.num_entries == 1024);
694 : :
695 : : /* case6: event == RDMA_CM_EVENT_DISCONNECTED */
696 : 3 : rqpair.evt = &event;
697 : 3 : event.event = RDMA_CM_EVENT_DISCONNECTED;
698 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
699 : 3 : CU_ASSERT(rc == 0);
700 : 3 : CU_ASSERT(rqpair.qpair.transport_failure_reason == SPDK_NVME_QPAIR_FAILURE_REMOTE);
701 : :
702 : : /* case7: event == RDMA_CM_EVENT_DEVICE_REMOVAL */
703 : 3 : rqpair.evt = &event;
704 : 3 : event.event = RDMA_CM_EVENT_DEVICE_REMOVAL;
705 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
706 : 3 : CU_ASSERT(rc == 0);
707 : 3 : CU_ASSERT(rqpair.qpair.transport_failure_reason == SPDK_NVME_QPAIR_FAILURE_LOCAL);
708 : :
709 : : /* case8: event == RDMA_CM_EVENT_MULTICAST_JOIN */
710 : 3 : rqpair.evt = &event;
711 : 3 : event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
712 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
713 : 3 : CU_ASSERT(rc == 0);
714 : :
715 : : /* case9: event == RDMA_CM_EVENT_ADDR_CHANGE */
716 : 3 : rqpair.evt = &event;
717 : 3 : event.event = RDMA_CM_EVENT_ADDR_CHANGE;
718 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
719 : 3 : CU_ASSERT(rc == 0);
720 : 3 : CU_ASSERT(rqpair.qpair.transport_failure_reason == SPDK_NVME_QPAIR_FAILURE_LOCAL);
721 : :
722 : : /* case10: event == RDMA_CM_EVENT_TIMEWAIT_EXIT */
723 : 3 : rqpair.evt = &event;
724 : 3 : event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT;
725 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
726 : 3 : CU_ASSERT(rc == 0);
727 : :
728 : : /* case11: default event == 0xFF */
729 : 3 : rqpair.evt = &event;
730 : 3 : event.event = 0xFF;
731 : 3 : rc = nvme_rdma_qpair_process_cm_event(&rqpair);
732 : 3 : CU_ASSERT(rc == 0);
733 : 3 : }
734 : :
735 : : static void
736 : 3 : test_nvme_rdma_ctrlr_construct(void)
737 : : {
738 : : struct spdk_nvme_ctrlr *ctrlr;
739 : 3 : struct spdk_nvme_transport_id trid = {};
740 : 3 : struct spdk_nvme_ctrlr_opts opts = {};
741 : 3 : struct nvme_rdma_qpair *rqpair = NULL;
742 : 3 : struct nvme_rdma_ctrlr *rctrlr = NULL;
743 : 3 : struct rdma_event_channel cm_channel = {};
744 : 3 : void *devhandle = NULL;
745 : : int rc;
746 : :
747 : 3 : opts.transport_retry_count = NVME_RDMA_CTRLR_MAX_TRANSPORT_RETRY_COUNT + 1;
748 : 3 : opts.transport_ack_timeout = NVME_RDMA_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT + 1;
749 : 3 : opts.admin_queue_size = 0xFFFF;
750 : 3 : trid.trtype = SPDK_NVME_TRANSPORT_RDMA;
751 : 3 : trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;
752 : 3 : MOCK_SET(rdma_create_event_channel, &cm_channel);
753 : :
754 : 3 : ctrlr = nvme_rdma_ctrlr_construct(&trid, &opts, devhandle);
755 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(ctrlr != NULL);
756 : 3 : CU_ASSERT(ctrlr->opts.transport_retry_count ==
757 : : NVME_RDMA_CTRLR_MAX_TRANSPORT_RETRY_COUNT);
758 : 3 : CU_ASSERT(ctrlr->opts.transport_ack_timeout ==
759 : : NVME_RDMA_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT);
760 : 3 : CU_ASSERT(ctrlr->opts.admin_queue_size == opts.admin_queue_size);
761 : 3 : rctrlr = SPDK_CONTAINEROF(ctrlr, struct nvme_rdma_ctrlr, ctrlr);
762 : 3 : CU_ASSERT(rctrlr->max_sge == NVME_RDMA_MAX_SGL_DESCRIPTORS);
763 : 3 : CU_ASSERT(rctrlr->cm_channel == &cm_channel);
764 [ - + ]: 3 : CU_ASSERT(!strncmp((char *)&rctrlr->ctrlr.trid,
765 : : (char *)&trid, sizeof(trid)));
766 : :
767 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(ctrlr->adminq != NULL);
768 : 3 : rqpair = SPDK_CONTAINEROF(ctrlr->adminq, struct nvme_rdma_qpair, qpair);
769 : 3 : CU_ASSERT(rqpair->num_entries == opts.admin_queue_size - 1);
770 [ - + ]: 3 : CU_ASSERT(rqpair->delay_cmd_submit == false);
771 [ - - - + ]: 3 : MOCK_CLEAR(rdma_create_event_channel);
772 : :
773 : : /* Hardcode the trtype, because nvme_qpair_init() is stub function. */
774 : 3 : rqpair->qpair.trtype = SPDK_NVME_TRANSPORT_RDMA;
775 : 3 : rc = nvme_rdma_ctrlr_destruct(ctrlr);
776 : 3 : CU_ASSERT(rc == 0);
777 : 3 : }
778 : :
779 : : static void
780 : 3 : test_nvme_rdma_req_put_and_get(void)
781 : : {
782 : 3 : struct nvme_rdma_qpair rqpair = {};
783 : 3 : struct spdk_nvme_rdma_req rdma_req = {};
784 : : struct spdk_nvme_rdma_req *rdma_req_get;
785 : :
786 : : /* case 1: nvme_rdma_req_put */
787 : 3 : TAILQ_INIT(&rqpair.free_reqs);
788 : 3 : rdma_req.completion_flags = 1;
789 : 3 : rdma_req.req = (struct nvme_request *)0xDEADBEFF;
790 : 3 : rdma_req.id = 10086;
791 : 3 : nvme_rdma_req_put(&rqpair, &rdma_req);
792 : :
793 : 3 : CU_ASSERT(rqpair.free_reqs.tqh_first == &rdma_req);
794 : 3 : CU_ASSERT(rqpair.free_reqs.tqh_first->completion_flags == 0);
795 : 3 : CU_ASSERT(rqpair.free_reqs.tqh_first->req == NULL);
796 : 3 : CU_ASSERT(rqpair.free_reqs.tqh_first->id == 10086);
797 : 3 : CU_ASSERT(rdma_req.completion_flags == 0);
798 : 3 : CU_ASSERT(rdma_req.req == NULL);
799 : :
800 : : /* case 2: nvme_rdma_req_get */
801 : 3 : rdma_req_get = nvme_rdma_req_get(&rqpair);
802 : 3 : CU_ASSERT(rdma_req_get == &rdma_req);
803 : 3 : CU_ASSERT(rdma_req_get->id == 10086);
804 : 3 : CU_ASSERT(rqpair.free_reqs.tqh_first == NULL);
805 : 3 : }
806 : :
807 : : static void
808 : 3 : test_nvme_rdma_req_init(void)
809 : : {
810 : 3 : struct nvme_rdma_qpair rqpair = {};
811 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
812 : 3 : struct spdk_nvmf_cmd cmd = {};
813 : 3 : struct spdk_nvme_rdma_req rdma_req = {};
814 : 3 : struct nvme_request req = {};
815 : 3 : struct nvme_rdma_ut_bdev_io bio = { .iovcnt = NVME_RDMA_MAX_SGL_DESCRIPTORS };
816 : 3 : int rc = 1;
817 : :
818 : 3 : ctrlr.max_sges = NVME_RDMA_MAX_SGL_DESCRIPTORS;
819 : 3 : ctrlr.cdata.nvmf_specific.msdbd = 16;
820 : :
821 : 3 : rqpair.mr_map = (struct spdk_rdma_utils_mem_map *)0xdeadbeef;
822 : 3 : rqpair.rdma_qp = (struct spdk_rdma_provider_qp *)0xdeadbeef;
823 : 3 : rqpair.qpair.ctrlr = &ctrlr;
824 : 3 : rqpair.cmds = &cmd;
825 : 3 : cmd.sgl[0].address = 0x1111;
826 : 3 : rdma_req.id = 0;
827 : 3 : req.cmd.opc = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
828 : :
829 : 3 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xdeadbeef, NULL);
830 : : /* case 1: req->payload_size == 0, expect: pass. */
831 : 3 : req.payload_size = 0;
832 : 3 : rqpair.qpair.ctrlr->ioccsz_bytes = 1024;
833 : 3 : rqpair.qpair.ctrlr->icdoff = 0;
834 : 3 : rc = nvme_rdma_req_init(&rqpair, &req, &rdma_req);
835 : 3 : CU_ASSERT(rc == 0);
836 : 3 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
837 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
838 : 3 : CU_ASSERT(rdma_req.send_wr.num_sge == 1);
839 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.type == SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK);
840 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.subtype == SPDK_NVME_SGL_SUBTYPE_ADDRESS);
841 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.length == 0);
842 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.key == 0);
843 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
844 : :
845 : : /* case 2: payload_type == NVME_PAYLOAD_TYPE_CONTIG, expect: pass. */
846 : : /* icd_supported is true */
847 : 3 : rdma_req.req = NULL;
848 : 3 : rqpair.qpair.ctrlr->icdoff = 0;
849 : 3 : req.payload_offset = 0;
850 : 3 : req.payload_size = 1024;
851 : 3 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xdeadbeef, NULL);
852 : 3 : rc = nvme_rdma_req_init(&rqpair, &req, &rdma_req);
853 : 3 : CU_ASSERT(rc == 0);
854 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
855 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
856 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
857 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
858 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
859 : 3 : CU_ASSERT(rdma_req.send_sgl[1].length == req.payload_size);
860 : 3 : CU_ASSERT(rdma_req.send_sgl[1].addr == (uint64_t)req.payload.contig_or_cb_arg);
861 : 3 : CU_ASSERT(rdma_req.send_sgl[1].lkey == RDMA_UT_LKEY);
862 : :
863 : : /* icd_supported is false */
864 : 3 : rdma_req.req = NULL;
865 : 3 : rqpair.qpair.ctrlr->icdoff = 1;
866 : 3 : req.payload_offset = 0;
867 : 3 : req.payload_size = 1024;
868 : 3 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xdeadbeef, NULL);
869 : 3 : rc = nvme_rdma_req_init(&rqpair, &req, &rdma_req);
870 : 3 : CU_ASSERT(rc == 0);
871 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.type == SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK);
872 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.subtype == SPDK_NVME_SGL_SUBTYPE_ADDRESS);
873 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.length == req.payload_size);
874 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.key == RDMA_UT_RKEY);
875 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == (uint64_t)req.payload.contig_or_cb_arg);
876 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
877 : :
878 : : /* case 3: payload_type == NVME_PAYLOAD_TYPE_SGL, expect: pass. */
879 : : /* icd_supported is true */
880 : 3 : rdma_req.req = NULL;
881 : 3 : rqpair.qpair.ctrlr->icdoff = 0;
882 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_rdma_ut_reset_sgl, nvme_rdma_ut_next_sge, &bio, NULL);
883 : 3 : req.qpair = &rqpair.qpair;
884 : 3 : bio.iovpos = 0;
885 : 3 : req.payload_offset = 0;
886 : 3 : req.payload_size = 1024;
887 : 3 : bio.iovs[0].iov_base = (void *)0xdeadbeef;
888 : 3 : bio.iovs[0].iov_len = 1024;
889 : 3 : rc = nvme_rdma_req_init(&rqpair, &req, &rdma_req);
890 : 3 : CU_ASSERT(rc == 0);
891 : 3 : CU_ASSERT(bio.iovpos == 1);
892 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
893 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
894 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
895 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
896 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
897 : 3 : CU_ASSERT(rdma_req.send_sgl[1].length == req.payload_size);
898 : 3 : CU_ASSERT(rdma_req.send_sgl[1].addr == (uint64_t)bio.iovs[0].iov_base);
899 : 3 : CU_ASSERT(rdma_req.send_sgl[1].lkey == RDMA_UT_LKEY);
900 : :
901 : : /* icd_supported is false */
902 : 3 : rdma_req.req = NULL;
903 : 3 : rqpair.qpair.ctrlr->icdoff = 1;
904 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_rdma_ut_reset_sgl, nvme_rdma_ut_next_sge, &bio, NULL);
905 : 3 : req.qpair = &rqpair.qpair;
906 : 3 : bio.iovpos = 0;
907 : 3 : req.payload_offset = 0;
908 : 3 : req.payload_size = 1024;
909 : 3 : bio.iovs[0].iov_base = (void *)0xdeadbeef;
910 : 3 : bio.iovs[0].iov_len = 1024;
911 : 3 : rc = nvme_rdma_req_init(&rqpair, &req, &rdma_req);
912 : 3 : CU_ASSERT(rc == 0);
913 : 3 : CU_ASSERT(bio.iovpos == 1);
914 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.type == SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK);
915 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.subtype == SPDK_NVME_SGL_SUBTYPE_ADDRESS);
916 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.length == req.payload_size);
917 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.keyed.key == RDMA_UT_RKEY);
918 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == (uint64_t)bio.iovs[0].iov_base);
919 : 3 : CU_ASSERT(rdma_req.send_sgl[0].length == sizeof(struct spdk_nvme_cmd));
920 : 3 : }
921 : :
922 : : static void
923 : 3 : test_nvme_rdma_validate_cm_event(void)
924 : : {
925 : : enum rdma_cm_event_type expected_evt_type;
926 : 3 : struct rdma_cm_event reaped_evt = {};
927 : : int rc;
928 : :
929 : : /* case 1: expected_evt_type == reaped_evt->event, expect: pass */
930 : 3 : expected_evt_type = RDMA_CM_EVENT_ADDR_RESOLVED;
931 : 3 : reaped_evt.event = RDMA_CM_EVENT_ADDR_RESOLVED;
932 : :
933 : 3 : rc = nvme_rdma_validate_cm_event(expected_evt_type, &reaped_evt);
934 : 3 : CU_ASSERT(rc == 0);
935 : :
936 : : /* case 2: expected_evt_type != RDMA_CM_EVENT_ESTABLISHED and is not equal to reaped_evt->event, expect: fail */
937 : 3 : reaped_evt.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
938 : :
939 : 3 : rc = nvme_rdma_validate_cm_event(expected_evt_type, &reaped_evt);
940 : 3 : CU_ASSERT(rc == -EBADMSG);
941 : :
942 : : /* case 3: expected_evt_type == RDMA_CM_EVENT_ESTABLISHED */
943 : 3 : expected_evt_type = RDMA_CM_EVENT_ESTABLISHED;
944 : : /* reaped_evt->event == RDMA_CM_EVENT_REJECTED and reaped_evt->status == 10, expect: fail */
945 : 3 : reaped_evt.event = RDMA_CM_EVENT_REJECTED;
946 : 3 : reaped_evt.status = 10;
947 : :
948 : 3 : rc = nvme_rdma_validate_cm_event(expected_evt_type, &reaped_evt);
949 : 3 : CU_ASSERT(rc == -ESTALE);
950 : :
951 : : /* reaped_evt->event == RDMA_CM_EVENT_CONNECT_RESPONSE, expect: pass */
952 : 3 : reaped_evt.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
953 : :
954 : 3 : rc = nvme_rdma_validate_cm_event(expected_evt_type, &reaped_evt);
955 : 3 : CU_ASSERT(rc == 0);
956 : 3 : }
957 : :
958 : : static void
959 : 3 : test_nvme_rdma_qpair_init(void)
960 : : {
961 : 3 : struct nvme_rdma_qpair rqpair = {};
962 : 3 : struct rdma_cm_id cm_id = {};
963 : 3 : struct ibv_pd *pd = (struct ibv_pd *)0xfeedbeef;
964 : 3 : struct spdk_memory_domain *domain = (struct spdk_memory_domain *)0xf00dfeed;
965 : 3 : struct ibv_qp qp = { .pd = pd };
966 : 3 : struct nvme_rdma_ctrlr rctrlr = {};
967 : 3 : int rc = 0;
968 : :
969 : 3 : rctrlr.ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_RDMA;
970 : 3 : rqpair.cm_id = &cm_id;
971 : 3 : g_nvme_hooks.get_ibv_pd = NULL;
972 : 3 : rqpair.qpair.poll_group = NULL;
973 : 3 : rqpair.qpair.ctrlr = &rctrlr.ctrlr;
974 : 3 : g_spdk_rdma_qp.qp = &qp;
975 : 3 : MOCK_SET(spdk_rdma_utils_get_pd, pd);
976 : 3 : MOCK_SET(spdk_rdma_utils_get_memory_domain, domain);
977 : :
978 : 3 : rc = nvme_rdma_qpair_init(&rqpair);
979 : 3 : CU_ASSERT(rc == 0);
980 : :
981 : 3 : CU_ASSERT(rqpair.cm_id->context == &rqpair.qpair);
982 : 3 : CU_ASSERT(rqpair.max_send_sge == NVME_RDMA_DEFAULT_TX_SGE);
983 : 3 : CU_ASSERT(rqpair.max_recv_sge == NVME_RDMA_DEFAULT_RX_SGE);
984 : 3 : CU_ASSERT(rqpair.current_num_sends == 0);
985 : 3 : CU_ASSERT(rqpair.cq == (struct ibv_cq *)0xFEEDBEEF);
986 : 3 : CU_ASSERT(rqpair.memory_domain == domain);
987 : :
988 [ - - - + ]: 3 : MOCK_CLEAR(spdk_rdma_utils_get_pd);
989 [ - - - + ]: 3 : MOCK_CLEAR(spdk_rdma_utils_get_memory_domain);
990 : 3 : }
991 : :
992 : : static void
993 : 3 : test_nvme_rdma_qpair_submit_request(void)
994 : : {
995 : : int rc;
996 : 3 : struct nvme_rdma_qpair rqpair = {};
997 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
998 : 3 : struct nvme_request req = {};
999 : 3 : struct nvme_rdma_poller poller = {};
1000 : 3 : struct spdk_nvme_rdma_req *rdma_req = NULL;
1001 : :
1002 : 3 : req.cmd.opc = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
1003 : 3 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xdeadbeef, NULL);
1004 : 3 : req.payload_size = 0;
1005 : 3 : rqpair.mr_map = (struct spdk_rdma_utils_mem_map *)0xdeadbeef;
1006 : 3 : rqpair.rdma_qp = (struct spdk_rdma_provider_qp *)0xdeadbeef;
1007 : 3 : rqpair.qpair.ctrlr = &ctrlr;
1008 : 3 : rqpair.num_entries = 1;
1009 : 3 : rqpair.qpair.trtype = SPDK_NVME_TRANSPORT_RDMA;
1010 : 3 : rqpair.poller = &poller;
1011 : :
1012 : 3 : rc = nvme_rdma_create_reqs(&rqpair);
1013 : 3 : CU_ASSERT(rc == 0);
1014 : : /* Give send_wr.next a non null value */
1015 : 3 : rdma_req = TAILQ_FIRST(&rqpair.free_reqs);
1016 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rdma_req != NULL);
1017 : 3 : rdma_req->send_wr.next = (void *)0xdeadbeef;
1018 : :
1019 : 3 : rc = nvme_rdma_qpair_submit_request(&rqpair.qpair, &req);
1020 : 3 : CU_ASSERT(rc == 0);
1021 : 3 : CU_ASSERT(rqpair.current_num_sends == 1);
1022 : 3 : CU_ASSERT(rdma_req->send_wr.next == NULL);
1023 [ - + ]: 3 : TAILQ_REMOVE(&rqpair.outstanding_reqs, rdma_req, link);
1024 : 3 : CU_ASSERT(TAILQ_EMPTY(&rqpair.outstanding_reqs));
1025 : :
1026 : : /* No request available */
1027 : 3 : rc = nvme_rdma_qpair_submit_request(&rqpair.qpair, &req);
1028 : 3 : CU_ASSERT(rc == -EAGAIN);
1029 : 3 : CU_ASSERT(rqpair.poller->stats.queued_requests == 1);
1030 : :
1031 : 3 : nvme_rdma_free_reqs(&rqpair);
1032 : 3 : }
1033 : :
1034 : : static void
1035 : 3 : test_rdma_ctrlr_get_memory_domains(void)
1036 : : {
1037 : 3 : struct nvme_rdma_ctrlr rctrlr = {};
1038 : 3 : struct nvme_rdma_qpair rqpair = {};
1039 : 3 : struct spdk_memory_domain *domain = (struct spdk_memory_domain *)0xbaadbeef;
1040 : 3 : struct spdk_memory_domain *domains[1] = {NULL};
1041 : :
1042 : 3 : rqpair.memory_domain = domain;
1043 : 3 : rqpair.qpair.trtype = SPDK_NVME_TRANSPORT_RDMA;
1044 : 3 : rctrlr.ctrlr.adminq = &rqpair.qpair;
1045 : :
1046 : : /* Test 1, input domains pointer is NULL */
1047 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_memory_domains(&rctrlr.ctrlr, NULL, 1) == 1);
1048 : :
1049 : : /* Test 2, input array_size is 0 */
1050 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_memory_domains(&rctrlr.ctrlr, domains, 0) == 1);
1051 : 3 : CU_ASSERT(domains[0] == NULL);
1052 : :
1053 : : /* Test 3, both input domains pointer and array_size are NULL/0 */
1054 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_memory_domains(&rctrlr.ctrlr, NULL, 0) == 1);
1055 : :
1056 : : /* Test 2, input parameters are valid */
1057 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_memory_domains(&rctrlr.ctrlr, domains, 1) == 1);
1058 : 3 : CU_ASSERT(domains[0] == domain);
1059 : 3 : }
1060 : :
1061 : : static void
1062 : 3 : test_rdma_get_memory_translation(void)
1063 : : {
1064 : 3 : struct ibv_qp qp = {.pd = (struct ibv_pd *) 0xfeedbeef};
1065 : 3 : struct spdk_rdma_provider_qp rdma_qp = {.qp = &qp};
1066 : 3 : struct nvme_rdma_qpair rqpair = {.rdma_qp = &rdma_qp};
1067 : 3 : struct spdk_nvme_ns_cmd_ext_io_opts io_opts = {
1068 : : .memory_domain = (struct spdk_memory_domain *) 0xdeaddead
1069 : : };
1070 : 3 : struct nvme_request req = {.payload = {.opts = &io_opts}};
1071 : 3 : struct nvme_rdma_memory_translation_ctx ctx = {
1072 : : .addr = (void *) 0xBAADF00D,
1073 : : .length = 0x100
1074 : : };
1075 : : int rc;
1076 : :
1077 : 3 : rqpair.memory_domain = (struct spdk_memory_domain *) 0xfeedbeef;
1078 : :
1079 : : /* case 1, using extended IO opts with DMA device.
1080 : : * Test 1 - spdk_dma_translate_data error, expect fail */
1081 : 3 : MOCK_SET(spdk_memory_domain_translate_data, -1);
1082 : 3 : rc = nvme_rdma_get_memory_translation(&req, &rqpair, &ctx);
1083 : 3 : CU_ASSERT(rc != 0);
1084 [ - - - + ]: 3 : MOCK_CLEAR(spdk_memory_domain_translate_data);
1085 : :
1086 : : /* Test 2 - expect pass */
1087 : 3 : g_memory_translation_translation.iov_count = 1;
1088 : 3 : g_memory_translation_translation.iov.iov_base = ctx.addr + 1;
1089 : 3 : g_memory_translation_translation.iov.iov_len = ctx.length;
1090 : 3 : g_memory_translation_translation.rdma.lkey = 123;
1091 : 3 : g_memory_translation_translation.rdma.rkey = 321;
1092 : :
1093 : 3 : rc = nvme_rdma_get_memory_translation(&req, &rqpair, &ctx);
1094 : 3 : CU_ASSERT(rc == 0);
1095 : 3 : CU_ASSERT(ctx.lkey == g_memory_translation_translation.rdma.lkey);
1096 : 3 : CU_ASSERT(ctx.rkey == g_memory_translation_translation.rdma.rkey);
1097 : 3 : CU_ASSERT(ctx.addr == g_memory_translation_translation.iov.iov_base);
1098 : 3 : CU_ASSERT(ctx.length == g_memory_translation_translation.iov.iov_len);
1099 : :
1100 : : /* case 2, using rdma translation
1101 : : * Test 1 - spdk_rdma_get_translation error, expect fail */
1102 : 3 : req.payload.opts = NULL;
1103 : 3 : MOCK_SET(spdk_rdma_utils_get_translation, -1);
1104 : 3 : rc = nvme_rdma_get_memory_translation(&req, &rqpair, &ctx);
1105 : 3 : CU_ASSERT(rc != 0);
1106 [ - - - + ]: 3 : MOCK_CLEAR(spdk_rdma_utils_get_translation);
1107 : :
1108 : : /* Test 2 - expect pass */
1109 : 3 : rc = nvme_rdma_get_memory_translation(&req, &rqpair, &ctx);
1110 : 3 : CU_ASSERT(rc == 0);
1111 : 3 : CU_ASSERT(ctx.lkey == RDMA_UT_LKEY);
1112 : 3 : CU_ASSERT(ctx.rkey == RDMA_UT_RKEY);
1113 : 3 : }
1114 : :
1115 : : static void
1116 : 3 : test_get_rdma_qpair_from_wc(void)
1117 : : {
1118 : 3 : const uint32_t test_qp_num = 123;
1119 : 3 : struct nvme_rdma_poll_group group = {};
1120 : 3 : struct nvme_rdma_qpair rqpair = {};
1121 : 3 : struct spdk_rdma_provider_qp rdma_qp = {};
1122 : 3 : struct ibv_qp qp = { .qp_num = test_qp_num };
1123 : 3 : struct ibv_wc wc = { .qp_num = test_qp_num };
1124 : :
1125 : 3 : STAILQ_INIT(&group.group.disconnected_qpairs);
1126 : 3 : STAILQ_INIT(&group.group.connected_qpairs);
1127 : 3 : rqpair.qpair.trtype = SPDK_NVME_TRANSPORT_RDMA;
1128 : :
1129 : : /* Test 1 - Simulate case when nvme_rdma_qpair is disconnected but still in one of lists.
1130 : : * get_rdma_qpair_from_wc must return NULL */
1131 [ + - ]: 3 : STAILQ_INSERT_HEAD(&group.group.disconnected_qpairs, &rqpair.qpair, poll_group_stailq);
1132 : 3 : CU_ASSERT(get_rdma_qpair_from_wc(&group, &wc) == NULL);
1133 [ + - ]: 3 : STAILQ_REMOVE_HEAD(&group.group.disconnected_qpairs, poll_group_stailq);
1134 : :
1135 [ + - ]: 3 : STAILQ_INSERT_HEAD(&group.group.connected_qpairs, &rqpair.qpair, poll_group_stailq);
1136 : 3 : CU_ASSERT(get_rdma_qpair_from_wc(&group, &wc) == NULL);
1137 [ + - ]: 3 : STAILQ_REMOVE_HEAD(&group.group.connected_qpairs, poll_group_stailq);
1138 : :
1139 : : /* Test 2 - nvme_rdma_qpair with valid rdma_qp/ibv_qp and qp_num */
1140 : 3 : rdma_qp.qp = &qp;
1141 : 3 : rqpair.rdma_qp = &rdma_qp;
1142 : :
1143 [ + - ]: 3 : STAILQ_INSERT_HEAD(&group.group.disconnected_qpairs, &rqpair.qpair, poll_group_stailq);
1144 : 3 : CU_ASSERT(get_rdma_qpair_from_wc(&group, &wc) == &rqpair);
1145 [ + - ]: 3 : STAILQ_REMOVE_HEAD(&group.group.disconnected_qpairs, poll_group_stailq);
1146 : :
1147 [ + - ]: 3 : STAILQ_INSERT_HEAD(&group.group.connected_qpairs, &rqpair.qpair, poll_group_stailq);
1148 : 3 : CU_ASSERT(get_rdma_qpair_from_wc(&group, &wc) == &rqpair);
1149 [ + - ]: 3 : STAILQ_REMOVE_HEAD(&group.group.connected_qpairs, poll_group_stailq);
1150 : 3 : }
1151 : :
1152 : : static void
1153 : 3 : test_nvme_rdma_ctrlr_get_max_sges(void)
1154 : : {
1155 : 3 : struct nvme_rdma_ctrlr rctrlr = {};
1156 : :
1157 : 3 : rctrlr.ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_RDMA;
1158 : 3 : rctrlr.max_sge = NVME_RDMA_MAX_SGL_DESCRIPTORS;
1159 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.msdbd = 16;
1160 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.ioccsz = 4096;
1161 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_max_sges(&rctrlr.ctrlr) == 16);
1162 : :
1163 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.msdbd = 32;
1164 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.ioccsz = 4096;
1165 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_max_sges(&rctrlr.ctrlr) == 16);
1166 : :
1167 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.msdbd = 8;
1168 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.ioccsz = 4096;
1169 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_max_sges(&rctrlr.ctrlr) == 8);
1170 : :
1171 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.msdbd = 16;
1172 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.ioccsz = 4;
1173 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_max_sges(&rctrlr.ctrlr) == 1);
1174 : :
1175 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.msdbd = 16;
1176 : 3 : rctrlr.ctrlr.cdata.nvmf_specific.ioccsz = 6;
1177 : 3 : CU_ASSERT(nvme_rdma_ctrlr_get_max_sges(&rctrlr.ctrlr) == 2);
1178 : 3 : }
1179 : :
1180 : : static void
1181 : 3 : test_nvme_rdma_poll_group_get_stats(void)
1182 : : {
1183 : 3 : int rc = -1;
1184 : 3 : struct spdk_nvme_transport_poll_group_stat *tpointer = NULL;
1185 : 3 : struct nvme_rdma_poll_group tgroup = {};
1186 : 3 : struct ibv_device dev1, dev2 = {};
1187 : 3 : struct ibv_context contexts1, contexts2 = {};
1188 : 3 : struct nvme_rdma_poller *tpoller1 = NULL;
1189 : 3 : struct nvme_rdma_poller *tpoller2 = NULL;
1190 : :
1191 : 3 : memcpy(dev1.name, "/dev/test1", sizeof("/dev/test1"));
1192 : 3 : memcpy(dev2.name, "/dev/test2", sizeof("/dev/test2"));
1193 : 3 : contexts1.device = &dev1;
1194 : 3 : contexts2.device = &dev2;
1195 : :
1196 : : /* Initialization */
1197 : 3 : STAILQ_INIT(&tgroup.pollers);
1198 : 3 : tpoller2 = nvme_rdma_poller_create(&tgroup, &contexts1);
1199 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(tpoller2 != NULL);
1200 : 3 : CU_ASSERT(tgroup.num_pollers == 1);
1201 : :
1202 : 3 : tpoller1 = nvme_rdma_poller_create(&tgroup, &contexts2);
1203 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(tpoller1 != NULL);
1204 : 3 : CU_ASSERT(tgroup.num_pollers == 2);
1205 : 3 : CU_ASSERT(&tgroup.pollers != NULL);
1206 : :
1207 : 3 : CU_ASSERT(tpoller1->device == &contexts2);
1208 : 3 : CU_ASSERT(tpoller2->device == &contexts1);
1209 [ - + ]: 3 : CU_ASSERT(strcmp(tpoller1->device->device->name, "/dev/test2") == 0);
1210 [ - + ]: 3 : CU_ASSERT(strcmp(tpoller2->device->device->name, "/dev/test1") == 0);
1211 : 3 : CU_ASSERT(tpoller1->current_num_wc == DEFAULT_NVME_RDMA_CQ_SIZE);
1212 : 3 : CU_ASSERT(tpoller2->current_num_wc == DEFAULT_NVME_RDMA_CQ_SIZE);
1213 : 3 : CU_ASSERT(tpoller1->required_num_wc == 0);
1214 : 3 : CU_ASSERT(tpoller2->required_num_wc == 0);
1215 : :
1216 : : /* Test1: Invalid stats */
1217 : 3 : rc = nvme_rdma_poll_group_get_stats(NULL, &tpointer);
1218 : 3 : CU_ASSERT(rc == -EINVAL);
1219 : :
1220 : : /* Test2: Invalid group pointer */
1221 : 3 : rc = nvme_rdma_poll_group_get_stats(&tgroup.group, NULL);
1222 : 3 : CU_ASSERT(rc == -EINVAL);
1223 : :
1224 : : /* Test3: Success member variables should be correct */
1225 : 3 : tpoller1->stats.polls = 111;
1226 : 3 : tpoller1->stats.idle_polls = 112;
1227 : 3 : tpoller1->stats.completions = 113;
1228 : 3 : tpoller1->stats.queued_requests = 114;
1229 : 3 : tpoller1->stats.rdma_stats.send.num_submitted_wrs = 121;
1230 : 3 : tpoller1->stats.rdma_stats.send.doorbell_updates = 122;
1231 : 3 : tpoller1->stats.rdma_stats.recv.num_submitted_wrs = 131;
1232 : 3 : tpoller1->stats.rdma_stats.recv.doorbell_updates = 132;
1233 : 3 : tpoller2->stats.polls = 211;
1234 : 3 : tpoller2->stats.idle_polls = 212;
1235 : 3 : tpoller2->stats.completions = 213;
1236 : 3 : tpoller2->stats.queued_requests = 214;
1237 : 3 : tpoller2->stats.rdma_stats.send.num_submitted_wrs = 221;
1238 : 3 : tpoller2->stats.rdma_stats.send.doorbell_updates = 222;
1239 : 3 : tpoller2->stats.rdma_stats.recv.num_submitted_wrs = 231;
1240 : 3 : tpoller2->stats.rdma_stats.recv.doorbell_updates = 232;
1241 : :
1242 : 3 : rc = nvme_rdma_poll_group_get_stats(&tgroup.group, &tpointer);
1243 : 3 : CU_ASSERT(rc == 0);
1244 : 3 : CU_ASSERT(tpointer != NULL);
1245 : 3 : CU_ASSERT(tpointer->trtype == SPDK_NVME_TRANSPORT_RDMA);
1246 : 3 : CU_ASSERT(tpointer->rdma.num_devices == tgroup.num_pollers);
1247 : 3 : CU_ASSERT(tpointer->rdma.device_stats != NULL);
1248 : :
1249 [ - + ]: 3 : CU_ASSERT(strcmp(tpointer->rdma.device_stats[0].name, "/dev/test2") == 0);
1250 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].polls == 111);
1251 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].idle_polls == 112);
1252 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].completions == 113);
1253 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].queued_requests == 114);
1254 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].total_send_wrs == 121);
1255 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].send_doorbell_updates == 122);
1256 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].total_recv_wrs == 131);
1257 : 3 : CU_ASSERT(tpointer->rdma.device_stats[0].recv_doorbell_updates == 132);
1258 : :
1259 [ - + ]: 3 : CU_ASSERT(strcmp(tpointer->rdma.device_stats[1].name, "/dev/test1") == 0);
1260 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].polls == 211);
1261 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].idle_polls == 212);
1262 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].completions == 213);
1263 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].queued_requests == 214);
1264 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].total_send_wrs == 221);
1265 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].send_doorbell_updates == 222);
1266 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].total_recv_wrs == 231);
1267 : 3 : CU_ASSERT(tpointer->rdma.device_stats[1].recv_doorbell_updates == 232);
1268 : :
1269 : 3 : nvme_rdma_poll_group_free_stats(&tgroup.group, tpointer);
1270 : 3 : nvme_rdma_poll_group_free_pollers(&tgroup);
1271 : 3 : }
1272 : :
1273 : : static void
1274 : 3 : test_nvme_rdma_qpair_set_poller(void)
1275 : : {
1276 : 3 : int rc = -1;
1277 : : struct nvme_rdma_poll_group *group;
1278 : : struct spdk_nvme_transport_poll_group *tgroup;
1279 : : struct nvme_rdma_poller *poller;
1280 : 3 : struct nvme_rdma_qpair rqpair = {};
1281 : 3 : struct rdma_cm_id cm_id = {};
1282 : :
1283 : : /* Case1: Test function nvme_rdma_poll_group_create */
1284 : : /* Test1: Function nvme_rdma_poll_group_create success */
1285 : 3 : tgroup = nvme_rdma_poll_group_create();
1286 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(tgroup != NULL);
1287 : :
1288 : 3 : group = nvme_rdma_poll_group(tgroup);
1289 : 3 : CU_ASSERT(group != NULL);
1290 : 3 : CU_ASSERT(STAILQ_EMPTY(&group->pollers));
1291 : :
1292 : : /* Case2: Test function nvme_rdma_qpair_set_poller */
1293 : 3 : rqpair.qpair.poll_group = tgroup;
1294 : 3 : rqpair.qpair.trtype = SPDK_NVME_TRANSPORT_RDMA;
1295 : 3 : rqpair.cm_id = &cm_id;
1296 : :
1297 : : /* Test1: Function ibv_create_cq failed */
1298 : 3 : cm_id.verbs = (void *)0xFEEDBEEF;
1299 : 3 : MOCK_SET(ibv_create_cq, NULL);
1300 : :
1301 : 3 : rc = nvme_rdma_qpair_set_poller(&rqpair.qpair);
1302 : 3 : CU_ASSERT(rc == -EINVAL);
1303 : 3 : CU_ASSERT(rqpair.cq == NULL);
1304 : 3 : CU_ASSERT(STAILQ_EMPTY(&group->pollers));
1305 : :
1306 [ - - - + ]: 3 : MOCK_CLEAR(ibv_create_cq);
1307 : :
1308 : : /* Test2: Unable to find a cq for qpair on poll group */
1309 : 3 : cm_id.verbs = NULL;
1310 : :
1311 : 3 : rc = nvme_rdma_qpair_set_poller(&rqpair.qpair);
1312 : 3 : CU_ASSERT(rc == -EINVAL);
1313 : 3 : CU_ASSERT(rqpair.cq == NULL);
1314 : 3 : CU_ASSERT(STAILQ_EMPTY(&group->pollers));
1315 : :
1316 : : /* Test3: Match cq success, current_num_wc is enough */
1317 : 3 : MOCK_SET(ibv_create_cq, (struct ibv_cq *)0xFEEDBEEF);
1318 : :
1319 : 3 : cm_id.verbs = (void *)0xFEEDBEEF;
1320 : 3 : rqpair.num_entries = 0;
1321 : :
1322 : 3 : rc = nvme_rdma_qpair_set_poller(&rqpair.qpair);
1323 : 3 : CU_ASSERT(rc == 0);
1324 : 3 : CU_ASSERT(rqpair.cq == (void *)0xFEEDBEEF);
1325 : :
1326 : 3 : poller = STAILQ_FIRST(&group->pollers);
1327 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(poller != NULL);
1328 : 3 : CU_ASSERT(STAILQ_NEXT(poller, link) == NULL);
1329 : 3 : CU_ASSERT(poller->device == (struct ibv_context *)0xFEEDBEEF);
1330 : 3 : CU_ASSERT(poller->current_num_wc == DEFAULT_NVME_RDMA_CQ_SIZE);
1331 : 3 : CU_ASSERT(poller->required_num_wc == 0);
1332 : 3 : CU_ASSERT(rqpair.poller == poller);
1333 : :
1334 : 3 : rqpair.qpair.poll_group_tailq_head = &tgroup->disconnected_qpairs;
1335 : :
1336 : 3 : nvme_rdma_poll_group_put_poller(group, rqpair.poller);
1337 : 3 : CU_ASSERT(STAILQ_EMPTY(&group->pollers));
1338 : :
1339 : 3 : rqpair.qpair.poll_group_tailq_head = &tgroup->connected_qpairs;
1340 : :
1341 : : /* Test4: Match cq success, function ibv_resize_cq failed */
1342 : 3 : rqpair.cq = NULL;
1343 : 3 : rqpair.num_entries = DEFAULT_NVME_RDMA_CQ_SIZE - 1;
1344 : 3 : MOCK_SET(ibv_resize_cq, -1);
1345 : :
1346 : 3 : rc = nvme_rdma_qpair_set_poller(&rqpair.qpair);
1347 : 3 : CU_ASSERT(rc == -EPROTO);
1348 : 3 : CU_ASSERT(STAILQ_EMPTY(&group->pollers));
1349 : :
1350 : : /* Test5: Current_num_wc is not enough, resize success */
1351 : 3 : MOCK_SET(ibv_resize_cq, 0);
1352 : :
1353 : 3 : rc = nvme_rdma_qpair_set_poller(&rqpair.qpair);
1354 : 3 : CU_ASSERT(rc == 0);
1355 : :
1356 : 3 : poller = STAILQ_FIRST(&group->pollers);
1357 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(poller != NULL);
1358 : 3 : CU_ASSERT(poller->current_num_wc == DEFAULT_NVME_RDMA_CQ_SIZE * 2);
1359 : 3 : CU_ASSERT(poller->required_num_wc == (DEFAULT_NVME_RDMA_CQ_SIZE - 1) * 2);
1360 : 3 : CU_ASSERT(rqpair.cq == poller->cq);
1361 : 3 : CU_ASSERT(rqpair.poller == poller);
1362 : :
1363 : 3 : rqpair.qpair.poll_group_tailq_head = &tgroup->disconnected_qpairs;
1364 : :
1365 : 3 : nvme_rdma_poll_group_put_poller(group, rqpair.poller);
1366 : 3 : CU_ASSERT(STAILQ_EMPTY(&group->pollers));
1367 : :
1368 : 3 : rc = nvme_rdma_poll_group_destroy(tgroup);
1369 : 3 : CU_ASSERT(rc == 0);
1370 : 3 : }
1371 : :
1372 : : int
1373 : 3 : main(int argc, char **argv)
1374 : : {
1375 : 3 : CU_pSuite suite = NULL;
1376 : : unsigned int num_failures;
1377 : :
1378 : 3 : CU_initialize_registry();
1379 : :
1380 : 3 : suite = CU_add_suite("nvme_rdma", NULL, NULL);
1381 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_build_sgl_request);
1382 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_build_sgl_inline_request);
1383 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_build_contig_request);
1384 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_build_contig_inline_request);
1385 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_create_reqs);
1386 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_create_rsps);
1387 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_ctrlr_create_qpair);
1388 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_poller_create);
1389 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_qpair_process_cm_event);
1390 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_ctrlr_construct);
1391 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_req_put_and_get);
1392 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_req_init);
1393 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_validate_cm_event);
1394 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_qpair_init);
1395 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_qpair_submit_request);
1396 : 3 : CU_ADD_TEST(suite, test_rdma_ctrlr_get_memory_domains);
1397 : 3 : CU_ADD_TEST(suite, test_rdma_get_memory_translation);
1398 : 3 : CU_ADD_TEST(suite, test_get_rdma_qpair_from_wc);
1399 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_ctrlr_get_max_sges);
1400 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_poll_group_get_stats);
1401 : 3 : CU_ADD_TEST(suite, test_nvme_rdma_qpair_set_poller);
1402 : :
1403 : 3 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
1404 : 3 : CU_cleanup_registry();
1405 : 3 : return num_failures;
1406 : : }
|