xref: /spdk/test/unit/lib/vhost/vhost.c/vhost_ut.c (revision f86f10757912918b8ba7b4b3bfdab1cd4c2d180c)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "CUnit/Basic.h"
37 #include "spdk_cunit.h"
38 #include "spdk/io_channel.h"
39 #include "spdk_internal/mock.h"
40 #include "lib/test_env.c"
41 
42 #include "vhost.c"
43 
44 DEFINE_STUB(rte_vhost_driver_unregister, int, (const char *path), 0);
45 DEFINE_STUB(spdk_event_allocate, struct spdk_event *,
46 	    (uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2), NULL);
47 DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0);
48 DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0);
49 DEFINE_STUB(spdk_app_get_core_mask, uint64_t, (void), 0);
50 DEFINE_STUB_V(spdk_app_stop, (int rc));
51 DEFINE_STUB_V(spdk_event_call, (struct spdk_event *event));
52 DEFINE_STUB(spdk_poller_register, struct spdk_poller *, (spdk_poller_fn fn, void *arg,
53 		uint64_t period_microseconds), NULL);
54 DEFINE_STUB_V(spdk_poller_unregister, (struct spdk_poller **ppoller));
55 DEFINE_STUB(spdk_iommu_mem_unregister, int, (uint64_t addr, uint64_t len), 0);
56 DEFINE_STUB(rte_vhost_get_mem_table, int, (int vid, struct rte_vhost_memory **mem), 0);
57 DEFINE_STUB(rte_vhost_get_negotiated_features, int, (int vid, uint64_t *features), 0);
58 DEFINE_STUB(rte_vhost_get_vhost_vring, int,
59 	    (int vid, uint16_t vring_idx, struct rte_vhost_vring *vring), 0);
60 DEFINE_STUB(rte_vhost_enable_guest_notification, int,
61 	    (int vid, uint16_t queue_id, int enable), 0);
62 DEFINE_STUB(rte_vhost_get_ifname, int, (int vid, char *buf, size_t len), 0);
63 DEFINE_STUB(rte_vhost_get_vring_num, uint16_t, (int vid), 0);
64 DEFINE_STUB(rte_vhost_driver_start, int, (const char *name), 0);
65 DEFINE_STUB(rte_vhost_driver_callback_register, int,
66 	    (const char *path, struct vhost_device_ops const *const ops), 0);
67 DEFINE_STUB(rte_vhost_driver_disable_features, int, (const char *path, uint64_t features), 0);
68 DEFINE_STUB(rte_vhost_driver_set_features, int, (const char *path, uint64_t features), 0);
69 DEFINE_STUB(rte_vhost_driver_register, int, (const char *path, uint64_t flags), 0);
70 DEFINE_STUB(spdk_vhost_scsi_controller_construct, int, (void), 0);
71 DEFINE_STUB(spdk_vhost_blk_controller_construct, int, (void), 0);
72 DEFINE_STUB(rte_vhost_set_vhost_vring_last_idx, int,
73 	    (int vid, uint16_t vring_idx, uint16_t last_avail_idx, uint16_t last_used_idx), 0);
74 DEFINE_STUB(spdk_env_get_current_core, uint32_t, (void), 0);
75 
76 static int
77 test_setup(void)
78 {
79 	return 0;
80 }
81 
82 static struct spdk_vhost_dev *
83 alloc_vdev(void)
84 {
85 	struct spdk_vhost_dev *vdev = NULL;
86 	int rc;
87 
88 	/* spdk_vhost_dev must be allocated on a cache line boundary. */
89 	rc = posix_memalign((void **)&vdev, 64, sizeof(*vdev));
90 	CU_ASSERT(rc == 0);
91 	SPDK_CU_ASSERT_FATAL(vdev != NULL);
92 	memset(vdev, 0, sizeof(*vdev));
93 
94 	vdev->mem = calloc(1, sizeof(*vdev->mem) + 2 * sizeof(struct rte_vhost_mem_region));
95 	SPDK_CU_ASSERT_FATAL(vdev->mem != NULL);
96 	vdev->mem->nregions = 2;
97 	vdev->mem->regions[0].guest_phys_addr = 0;
98 	vdev->mem->regions[0].size = 0x400000; /* 4 MB */
99 	vdev->mem->regions[0].host_user_addr = 0x1000000;
100 	vdev->mem->regions[1].guest_phys_addr = 0x400000;
101 	vdev->mem->regions[1].size = 0x400000; /* 4 MB */
102 	vdev->mem->regions[1].host_user_addr = 0x2000000;
103 	vdev->vid = 0x10;
104 
105 	return vdev;
106 }
107 
108 static void
109 free_vdev(struct spdk_vhost_dev *vdev)
110 {
111 	free(vdev->name);
112 	free(vdev->mem);
113 	free(vdev);
114 }
115 
116 static void
117 desc_to_iov_test(void)
118 {
119 	struct spdk_vhost_dev *vdev;
120 	struct iovec iov[SPDK_VHOST_IOVS_MAX];
121 	uint16_t iov_index;
122 	struct vring_desc desc;
123 	int rc;
124 
125 	vdev = alloc_vdev();
126 
127 	/* Test simple case where iov falls fully within a 2MB page. */
128 	desc.addr = 0x110000;
129 	desc.len = 0x1000;
130 	iov_index = 0;
131 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
132 	CU_ASSERT(rc == 0);
133 	CU_ASSERT(iov_index == 1);
134 	CU_ASSERT(iov[0].iov_base == (void *)0x1110000);
135 	CU_ASSERT(iov[0].iov_len == 0x1000);
136 	/*
137 	 * Always memset the iov to ensure each test validates data written by its call
138 	 * to the function under test.
139 	 */
140 	memset(iov, 0, sizeof(iov));
141 
142 	/* Same test, but ensure it respects the non-zero starting iov_index. */
143 	iov_index = SPDK_VHOST_IOVS_MAX - 1;
144 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
145 	CU_ASSERT(rc == 0);
146 	CU_ASSERT(iov_index == SPDK_VHOST_IOVS_MAX);
147 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_base == (void *)0x1110000);
148 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_len == 0x1000);
149 	memset(iov, 0, sizeof(iov));
150 
151 	/* Test for failure if iov_index already equals SPDK_VHOST_IOVS_MAX. */
152 	iov_index = SPDK_VHOST_IOVS_MAX;
153 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
154 	CU_ASSERT(rc != 0);
155 	memset(iov, 0, sizeof(iov));
156 
157 	/* Test case where iov spans a 2MB boundary, but does not span a vhost memory region. */
158 	desc.addr = 0x1F0000;
159 	desc.len = 0x20000;
160 	iov_index = 0;
161 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
162 	CU_ASSERT(rc == 0);
163 	CU_ASSERT(iov_index == 2);
164 	CU_ASSERT(iov[0].iov_base == (void *)0x11F0000);
165 	CU_ASSERT(iov[0].iov_len == 0x10000);
166 	CU_ASSERT(iov[1].iov_base == (void *)0x1200000);
167 	CU_ASSERT(iov[1].iov_len == 0x10000);
168 	memset(iov, 0, sizeof(iov));
169 
170 	/* Same test, but ensure it respects the non-zero starting iov_index. */
171 	iov_index = SPDK_VHOST_IOVS_MAX - 2;
172 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
173 	CU_ASSERT(rc == 0);
174 	CU_ASSERT(iov_index == SPDK_VHOST_IOVS_MAX);
175 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 2].iov_base == (void *)0x11F0000);
176 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 2].iov_len == 0x10000);
177 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_base == (void *)0x1200000);
178 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_len == 0x10000);
179 	memset(iov, 0, sizeof(iov));
180 
181 	/*
182 	 * This test should fail.  The first part of the descriptor will fit in the last
183 	 * iov, but the part after the 2MB boundary would overflow.
184 	 */
185 	iov_index = SPDK_VHOST_IOVS_MAX - 1;
186 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
187 	CU_ASSERT(rc != 0);
188 	memset(iov, 0, sizeof(iov));
189 
190 	/* Test case where iov spans a vhost memory region. */
191 	desc.addr = 0x3F0000;
192 	desc.len = 0x20000;
193 	iov_index = 0;
194 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
195 	CU_ASSERT(rc == 0);
196 	CU_ASSERT(iov_index == 2);
197 	CU_ASSERT(iov[0].iov_base == (void *)0x13F0000);
198 	CU_ASSERT(iov[0].iov_len == 0x10000);
199 	CU_ASSERT(iov[1].iov_base == (void *)0x2000000);
200 	CU_ASSERT(iov[1].iov_len == 0x10000);
201 	memset(iov, 0, sizeof(iov));
202 
203 	free_vdev(vdev);
204 
205 	CU_ASSERT(true);
206 }
207 
208 static void
209 create_controller_test(void)
210 {
211 	struct spdk_vhost_dev *vdev;
212 	int ret;
213 	unsigned ctrlr_num;
214 	char long_name[PATH_MAX];
215 	struct spdk_vhost_dev_backend backend;
216 
217 	MOCK_SET(spdk_app_get_core_mask, uint64_t, 1);
218 
219 	/* Create device with no name */
220 	vdev = alloc_vdev();
221 	ret = spdk_vhost_dev_construct(vdev, NULL, "0x1", SPDK_VHOST_DEV_T_BLK, &backend);
222 	CU_ASSERT(ret != 0);
223 
224 	/* Create device with incorrect cpumask */
225 	ret = spdk_vhost_dev_construct(vdev, "vdev_name_0", "0x2", SPDK_VHOST_DEV_T_BLK, &backend);
226 	CU_ASSERT(ret != 0);
227 
228 	/* Create device with too long name and path */
229 	memset(long_name, 'x', sizeof(long_name));
230 	long_name[PATH_MAX - 1] = 0;
231 	snprintf(dev_dirname, sizeof(dev_dirname), "some_path/");
232 	ret = spdk_vhost_dev_construct(vdev, long_name, "0x1", SPDK_VHOST_DEV_T_BLK, &backend);
233 	CU_ASSERT(ret != 0);
234 	dev_dirname[0] = 0;
235 
236 	/* Create device when device name is already taken */
237 	vdev->name = strdup("vdev_name_0");
238 	g_spdk_vhost_devices[0] = vdev;
239 	ret = spdk_vhost_dev_construct(vdev, "vdev_name_0", "0x1", SPDK_VHOST_DEV_T_BLK, &backend);
240 	CU_ASSERT(ret != 0);
241 
242 	/* Create device when max number of devices is reached */
243 	for (ctrlr_num = 0; ctrlr_num < MAX_VHOST_DEVICES; ctrlr_num ++) {
244 		g_spdk_vhost_devices[ctrlr_num] = vdev;
245 	}
246 
247 	ret = spdk_vhost_dev_construct(vdev, "vdev_name_1", "0x1", SPDK_VHOST_DEV_T_BLK, &backend);
248 	CU_ASSERT(ret != 0);
249 
250 	free_vdev(vdev);
251 	for (ctrlr_num = 0; ctrlr_num < MAX_VHOST_DEVICES; ctrlr_num++) {
252 		g_spdk_vhost_devices[ctrlr_num] = NULL;
253 	}
254 }
255 
256 static void
257 dev_find_by_vid_test(void)
258 {
259 	struct spdk_vhost_dev *vdev;
260 
261 	g_spdk_vhost_devices[0] = alloc_vdev();
262 	vdev = spdk_vhost_dev_find_by_vid(0x10);
263 	CU_ASSERT(vdev != NULL);
264 
265 	/* Search for a device with incorrect vid */
266 	vdev = spdk_vhost_dev_find_by_vid(0xFF);
267 	CU_ASSERT(vdev == NULL);
268 
269 	free_vdev(g_spdk_vhost_devices[0]);
270 	g_spdk_vhost_devices[0] = NULL;
271 }
272 
273 static void
274 remove_controller_test(void)
275 {
276 	struct spdk_vhost_dev *vdev;
277 	char long_name[PATH_MAX];
278 	int ret;
279 
280 	vdev = alloc_vdev();
281 	vdev->lcore = 0;
282 	vdev->name = strdup("vdev_name_0");
283 
284 	/* Remove device when controller is in use */
285 	ret = spdk_vhost_dev_remove(vdev);
286 	CU_ASSERT(ret != 0);
287 	if (ret == 0) {
288 		vdev->name = strdup("vdev_name_0");
289 	}
290 
291 	/* Remove nonexistent device */
292 	vdev->lcore = -1;
293 	ret = spdk_vhost_dev_remove(vdev);
294 	CU_ASSERT(ret != 0);
295 	if (ret != 0) {
296 		free(vdev->name);
297 	}
298 
299 	/* Remove device with too long name and path */
300 	memset(long_name, 'x', sizeof(long_name));
301 	long_name[PATH_MAX - 1] = 0;
302 	snprintf(dev_dirname, sizeof(dev_dirname), "some_path/");
303 	vdev->name = strdup(long_name);
304 	g_spdk_vhost_devices[0] = vdev;
305 	ret = spdk_vhost_dev_remove(vdev);
306 	CU_ASSERT(ret != 0);
307 	if (ret == 0) {
308 		vdev->name = NULL;
309 	}
310 
311 	free_vdev(vdev);
312 	g_spdk_vhost_devices[0] = NULL;
313 	dev_dirname[0] = 0;
314 }
315 
316 int
317 main(int argc, char **argv)
318 {
319 	CU_pSuite	suite = NULL;
320 	unsigned int	num_failures;
321 
322 	if (CU_initialize_registry() != CUE_SUCCESS) {
323 		return CU_get_error();
324 	}
325 
326 	suite = CU_add_suite("vhost_suite", test_setup, NULL);
327 	if (suite == NULL) {
328 		CU_cleanup_registry();
329 		return CU_get_error();
330 	}
331 
332 	if (
333 		CU_add_test(suite, "desc_to_iov", desc_to_iov_test) == NULL ||
334 		CU_add_test(suite, "create_controller", create_controller_test) == NULL ||
335 		CU_add_test(suite, "dev_find_by_vid", dev_find_by_vid_test) == NULL ||
336 		CU_add_test(suite, "remove_controller", remove_controller_test) == NULL
337 	) {
338 		CU_cleanup_registry();
339 		return CU_get_error();
340 	}
341 
342 	CU_basic_set_mode(CU_BRM_VERBOSE);
343 	CU_basic_run_tests();
344 	num_failures = CU_get_number_of_failures();
345 	CU_cleanup_registry();
346 
347 	return num_failures;
348 }
349