xref: /spdk/test/unit/lib/nvmf/vfio_user.c/vfio_user_ut.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2021 Intel Corporation. All rights reserved.
3  */
4 
5 #include "spdk/stdinc.h"
6 #include "spdk_internal/cunit.h"
7 #include "common/lib/test_env.c"
8 #include "nvmf/vfio_user.c"
9 #include "nvmf/transport.c"
10 
11 DEFINE_STUB(spdk_nvmf_ctrlr_get_regs, const struct spdk_nvmf_registers *,
12 	    (struct spdk_nvmf_ctrlr *ctrlr), NULL);
13 DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0);
14 DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0);
15 DEFINE_STUB_V(spdk_nvmf_request_exec, (struct spdk_nvmf_request *req));
16 DEFINE_STUB_V(spdk_nvmf_request_exec_fabrics, (struct spdk_nvmf_request *req));
17 DEFINE_STUB(spdk_nvmf_request_complete, int, (struct spdk_nvmf_request *req), 0);
18 DEFINE_STUB_V(spdk_nvmf_tgt_new_qpair, (struct spdk_nvmf_tgt *tgt, struct spdk_nvmf_qpair *qpair));
19 DEFINE_STUB(nvmf_ctrlr_abort_request, int, (struct spdk_nvmf_request *req), 0);
20 DEFINE_STUB(spdk_nvmf_qpair_disconnect, int, (struct spdk_nvmf_qpair *qpair,
21 		nvmf_qpair_disconnect_cb cb_fn, void *ctx), 0);
22 DEFINE_STUB(spdk_nvmf_subsystem_get_nqn, const char *,
23 	    (const struct spdk_nvmf_subsystem *subsystem), NULL);
24 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), 512);
25 DEFINE_STUB(spdk_nvmf_subsystem_pause, int, (struct spdk_nvmf_subsystem *subsystem,
26 		uint32_t nsid, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg), 0);
27 DEFINE_STUB(spdk_nvmf_subsystem_resume, int, (struct spdk_nvmf_subsystem *subsystem,
28 		spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg), 0);
29 DEFINE_STUB_V(spdk_nvmf_ctrlr_abort_aer, (struct spdk_nvmf_ctrlr *ctrlr));
30 DEFINE_STUB(spdk_nvmf_ctrlr_async_event_error_event, int, (struct spdk_nvmf_ctrlr *ctrlr,
31 		enum spdk_nvme_async_event_info_error info), 0);
32 DEFINE_STUB(spdk_nvme_transport_id_adrfam_str, const char *, (enum spdk_nvmf_adrfam adrfam), NULL);
33 DEFINE_STUB(spdk_nvmf_qpair_get_listen_trid, int, (struct spdk_nvmf_qpair *qpair,
34 		struct spdk_nvme_transport_id *trid), 0);
35 DEFINE_STUB(spdk_nvme_transport_id_compare, int, (const struct spdk_nvme_transport_id *trid1,
36 		const struct spdk_nvme_transport_id *trid2), 0);
37 DEFINE_STUB(nvmf_subsystem_get_ctrlr, struct spdk_nvmf_ctrlr *,
38 	    (struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid), NULL);
39 DEFINE_STUB_V(nvmf_ctrlr_set_fatal_status, (struct spdk_nvmf_ctrlr *ctrlr));
40 DEFINE_STUB(spdk_nvmf_ctrlr_save_migr_data, int, (struct spdk_nvmf_ctrlr *ctrlr,
41 		struct spdk_nvmf_ctrlr_migr_data *data), 0);
42 DEFINE_STUB(spdk_nvmf_ctrlr_restore_migr_data, int, (struct spdk_nvmf_ctrlr *ctrlr,
43 		const struct spdk_nvmf_ctrlr_migr_data *data), 0);
44 DEFINE_STUB(spdk_mempool_lookup, struct spdk_mempool *, (const char *name), NULL);
45 
46 static void *
47 gpa_to_vva(void *prv, uint64_t addr, uint64_t len, int prot)
48 {
49 	return (void *)(uintptr_t)addr;
50 }
51 
52 static void
53 test_nvme_cmd_map_prps(void)
54 {
55 	struct spdk_nvme_cmd cmd = {};
56 	struct iovec iovs[33];
57 	uint64_t phy_addr, *prp;
58 	uint32_t len;
59 	void *buf, *prps;
60 	int i, ret;
61 	size_t mps = 4096;
62 
63 	buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0);
64 	CU_ASSERT(buf != NULL);
65 	prps = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0);
66 	CU_ASSERT(prps != NULL);
67 
68 	/* test case 1: 4KiB with PRP1 only */
69 	cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf;
70 	len = 4096;
71 	ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
72 	CU_ASSERT(ret == 1);
73 	CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1);
74 	CU_ASSERT(iovs[0].iov_len == len);
75 
76 	/* test case 2: 4KiB with PRP1 and PRP2, 1KiB in first iov, and 3KiB in second iov */
77 	cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3;
78 	cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)buf + 4096;
79 	len = 4096;
80 	ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 1, len, mps, gpa_to_vva);
81 	CU_ASSERT(ret == -ERANGE);
82 	ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
83 	CU_ASSERT(ret == 2);
84 	CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1);
85 	CU_ASSERT(iovs[0].iov_len == 1024);
86 	CU_ASSERT(iovs[1].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp2);
87 	CU_ASSERT(iovs[1].iov_len == 1024 * 3);
88 
89 	/* test case 3: 128KiB with PRP list, 1KiB in first iov, 3KiB in last iov */
90 	cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3;
91 	cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps;
92 	len = 128 * 1024;
93 	prp = prps;
94 	for (i = 1; i < 33; i++) {
95 		*prp = (uint64_t)(uintptr_t)buf + i * 4096;
96 		prp++;
97 	}
98 	ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
99 	CU_ASSERT(ret == 33);
100 	CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1);
101 	CU_ASSERT(iovs[0].iov_len == 1024);
102 	for (i = 1; i < 32; i++) {
103 		CU_ASSERT(iovs[i].iov_base == (void *)((uintptr_t)buf + i * 4096));
104 		CU_ASSERT(iovs[i].iov_len == 4096);
105 	}
106 	CU_ASSERT(iovs[32].iov_base == (void *)((uintptr_t)buf + 32 * 4096));
107 	CU_ASSERT(iovs[32].iov_len == 1024 * 3);
108 
109 	/* test case 4: 256KiB with PRP list, not enough iovs */
110 	cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3;
111 	cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps;
112 	len = 256 * 1024;
113 	ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
114 	CU_ASSERT(ret == -ERANGE);
115 
116 	spdk_free(buf);
117 	spdk_free(prps);
118 }
119 
120 static void
121 test_nvme_cmd_map_sgls(void)
122 {
123 	struct spdk_nvme_cmd cmd = {};
124 	struct iovec iovs[33];
125 	uint64_t phy_addr;
126 	uint32_t len;
127 	void *buf, *sgls;
128 	struct spdk_nvme_sgl_descriptor *sgl;
129 	int i, ret;
130 	size_t mps = 4096;
131 
132 	buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0);
133 	CU_ASSERT(buf != NULL);
134 	sgls = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0);
135 	CU_ASSERT(sgls != NULL);
136 
137 	/* test case 1: 8KiB with 1 data block */
138 	len = 8192;
139 	cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
140 	cmd.dptr.sgl1.unkeyed.length = len;
141 	cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)buf;
142 
143 	ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
144 	CU_ASSERT(ret == 1);
145 	CU_ASSERT(iovs[0].iov_base == buf);
146 	CU_ASSERT(iovs[0].iov_len == 8192);
147 
148 	/* test case 2: 8KiB with 2 data blocks and 1 last segment */
149 	sgl = (struct spdk_nvme_sgl_descriptor *)sgls;
150 	sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
151 	sgl[0].unkeyed.length = 2048;
152 	sgl[0].address = (uint64_t)(uintptr_t)buf;
153 	sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
154 	sgl[1].unkeyed.length = len - 2048;
155 	sgl[1].address = (uint64_t)(uintptr_t)buf + 16 * 1024;
156 
157 	cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
158 	cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl);
159 	cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls;
160 
161 	ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
162 	CU_ASSERT(ret == 2);
163 	CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf);
164 	CU_ASSERT(iovs[0].iov_len == 2048);
165 	CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 16 * 1024));
166 	CU_ASSERT(iovs[1].iov_len == len - 2048);
167 
168 	/* test case 3: 8KiB with 1 segment, 1 last segment and 3 data blocks */
169 	sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
170 	sgl[0].unkeyed.length = 2048;
171 	sgl[0].address = (uint64_t)(uintptr_t)buf;
172 	sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
173 	sgl[1].unkeyed.length = 2 * sizeof(*sgl);
174 	sgl[1].address = (uint64_t)(uintptr_t)&sgl[9];
175 
176 	sgl[9].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
177 	sgl[9].unkeyed.length = 4096;
178 	sgl[9].address = (uint64_t)(uintptr_t)buf + 4 * 1024;
179 	sgl[10].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
180 	sgl[10].unkeyed.length = 2048;
181 	sgl[10].address = (uint64_t)(uintptr_t)buf + 16 * 1024;
182 
183 	cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_SEGMENT;
184 	cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl);
185 	cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)&sgl[0];
186 
187 	ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
188 	CU_ASSERT(ret == 3);
189 	CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf);
190 	CU_ASSERT(iovs[0].iov_len == 2048);
191 	CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 4 * 1024));
192 	CU_ASSERT(iovs[1].iov_len == 4096);
193 	CU_ASSERT(iovs[2].iov_base == (void *)((uintptr_t)buf + 16 * 1024));
194 	CU_ASSERT(iovs[2].iov_len == 2048);
195 
196 	/* test case 4: not enough iovs */
197 	len = 12 * 1024;
198 	for (i = 0; i < 6; i++) {
199 		sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
200 		sgl[0].unkeyed.length = 2048;
201 		sgl[0].address = (uint64_t)(uintptr_t)buf + i * 4096;
202 	}
203 
204 	cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
205 	cmd.dptr.sgl1.unkeyed.length = 6 * sizeof(*sgl);
206 	cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls;
207 
208 	ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 4, len, mps, gpa_to_vva);
209 	CU_ASSERT(ret == -ERANGE);
210 
211 	spdk_free(buf);
212 	spdk_free(sgls);
213 }
214 
215 static void
216 ut_transport_destroy_done_cb(void *cb_arg)
217 {
218 	int *done = cb_arg;
219 	*done = 1;
220 }
221 
222 static void
223 test_nvmf_vfio_user_create_destroy(void)
224 {
225 	struct spdk_nvmf_transport *transport = NULL;
226 	struct nvmf_vfio_user_transport *vu_transport = NULL;
227 	struct nvmf_vfio_user_endpoint *endpoint = NULL;
228 	struct spdk_nvmf_transport_opts opts = {};
229 	int rc;
230 	int done;
231 
232 	/* Initialize transport_specific NULL to avoid decoding json */
233 	opts.transport_specific = NULL;
234 
235 	transport = nvmf_vfio_user_create(&opts);
236 	CU_ASSERT(transport != NULL);
237 
238 	vu_transport = SPDK_CONTAINEROF(transport, struct nvmf_vfio_user_transport,
239 					transport);
240 	/* Allocate a endpoint for destroy */
241 	endpoint = calloc(1, sizeof(*endpoint));
242 	pthread_mutex_init(&endpoint->lock, NULL);
243 	TAILQ_INSERT_TAIL(&vu_transport->endpoints, endpoint, link);
244 	done = 0;
245 
246 	rc = nvmf_vfio_user_destroy(transport, ut_transport_destroy_done_cb, &done);
247 	CU_ASSERT(rc == 0);
248 	CU_ASSERT(done == 1);
249 }
250 
251 int
252 main(int argc, char **argv)
253 {
254 	CU_pSuite	suite = NULL;
255 	unsigned int	num_failures;
256 
257 	CU_initialize_registry();
258 
259 	suite = CU_add_suite("vfio_user", NULL, NULL);
260 
261 	CU_ADD_TEST(suite, test_nvme_cmd_map_prps);
262 	CU_ADD_TEST(suite, test_nvme_cmd_map_sgls);
263 	CU_ADD_TEST(suite, test_nvmf_vfio_user_create_destroy);
264 
265 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
266 	CU_cleanup_registry();
267 	return num_failures;
268 }
269