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