xref: /spdk/test/unit/lib/vhost/vhost.c/vhost_ut.c (revision 179ed697b3c461d100e675915d074be717b7b9cc)
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_internal/mock.h"
39 
40 #include "vhost.c"
41 
42 DEFINE_STUB(rte_vhost_driver_unregister, int, (const char *path), 0);
43 DEFINE_STUB(spdk_event_allocate, struct spdk_event *,
44 	    (uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2), NULL);
45 DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0);
46 DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0);
47 DEFINE_STUB(spdk_vtophys, uint64_t, (void *vaddr), 1);
48 DEFINE_STUB(spdk_iommu_mem_register, int, (uint64_t addr, uint64_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_iommu_mem_unregister, int, (uint64_t addr, uint64_t len), 0);
53 DEFINE_STUB(rte_vhost_get_mem_table, int, (int vid, struct rte_vhost_memory **mem), 0);
54 DEFINE_STUB(rte_vhost_get_negotiated_features, int, (int vid, uint64_t *features), 0);
55 DEFINE_STUB(rte_vhost_get_vhost_vring, int,
56 	    (int vid, uint16_t vring_idx, struct rte_vhost_vring *vring), 0);
57 DEFINE_STUB(rte_vhost_enable_guest_notification, int,
58 	    (int vid, uint16_t queue_id, int enable), 0);
59 DEFINE_STUB(rte_vhost_get_ifname, int, (int vid, char *buf, size_t len), 0);
60 DEFINE_STUB(rte_vhost_get_vring_num, uint16_t, (int vid), 0);
61 DEFINE_STUB(rte_vhost_driver_start, int, (const char *name), 0);
62 DEFINE_STUB(rte_vhost_driver_callback_register, int,
63 	    (const char *path, struct vhost_device_ops const *const ops), 0);
64 DEFINE_STUB(rte_vhost_driver_disable_features, int, (const char *path, uint64_t features), 0);
65 DEFINE_STUB(rte_vhost_driver_set_features, int, (const char *path, uint64_t features), 0);
66 DEFINE_STUB(rte_vhost_driver_register, int, (const char *path, uint64_t flags), 0);
67 DEFINE_STUB(spdk_vhost_scsi_controller_construct, int, (void), 0);
68 DEFINE_STUB(spdk_vhost_blk_controller_construct, int, (void), 0);
69 DEFINE_STUB(rte_vhost_set_vhost_vring_last_idx, int,
70 	    (int vid, uint16_t vring_idx, uint16_t last_avail_idx, uint16_t last_used_idx), 0);
71 
72 static int
73 test_setup(void)
74 {
75 	return 0;
76 }
77 
78 static struct spdk_vhost_dev *
79 alloc_vdev(void)
80 {
81 	struct spdk_vhost_dev *vdev = NULL;
82 	int rc;
83 
84 	/* spdk_vhost_dev must be allocated on a cache line boundary. */
85 	rc = posix_memalign((void **)&vdev, 64, sizeof(*vdev));
86 	CU_ASSERT(rc == 0);
87 	SPDK_CU_ASSERT_FATAL(vdev != NULL);
88 
89 	vdev->mem = calloc(1, sizeof(*vdev->mem) + 2 * sizeof(struct rte_vhost_mem_region));
90 	SPDK_CU_ASSERT_FATAL(vdev->mem != NULL);
91 	vdev->mem->nregions = 2;
92 	vdev->mem->regions[0].guest_phys_addr = 0;
93 	vdev->mem->regions[0].size = 0x400000; /* 4 MB */
94 	vdev->mem->regions[0].host_user_addr = 0x1000000;
95 	vdev->mem->regions[1].guest_phys_addr = 0x400000;
96 	vdev->mem->regions[1].size = 0x400000; /* 4 MB */
97 	vdev->mem->regions[1].host_user_addr = 0x2000000;
98 
99 	return vdev;
100 }
101 
102 static void
103 free_vdev(struct spdk_vhost_dev *vdev)
104 {
105 	free(vdev->mem);
106 	free(vdev);
107 }
108 
109 static void
110 desc_to_iov_test(void)
111 {
112 	struct spdk_vhost_dev *vdev;
113 	struct iovec iov[SPDK_VHOST_IOVS_MAX];
114 	uint16_t iov_index;
115 	struct vring_desc desc;
116 	int rc;
117 
118 	vdev = alloc_vdev();
119 
120 	/* Test simple case where iov falls fully within a 2MB page. */
121 	desc.addr = 0x110000;
122 	desc.len = 0x1000;
123 	iov_index = 0;
124 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
125 	CU_ASSERT(rc == 0);
126 	CU_ASSERT(iov_index == 1);
127 	CU_ASSERT(iov[0].iov_base == (void *)0x1110000);
128 	CU_ASSERT(iov[0].iov_len == 0x1000);
129 	/*
130 	 * Always memset the iov to ensure each test validates data written by its call
131 	 * to the function under test.
132 	 */
133 	memset(iov, 0, sizeof(iov));
134 
135 	/* Same test, but ensure it respects the non-zero starting iov_index. */
136 	iov_index = SPDK_VHOST_IOVS_MAX - 1;
137 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
138 	CU_ASSERT(rc == 0);
139 	CU_ASSERT(iov_index == SPDK_VHOST_IOVS_MAX);
140 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_base == (void *)0x1110000);
141 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_len == 0x1000);
142 	memset(iov, 0, sizeof(iov));
143 
144 	/* Test for failure if iov_index already equals SPDK_VHOST_IOVS_MAX. */
145 	iov_index = SPDK_VHOST_IOVS_MAX;
146 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
147 	CU_ASSERT(rc != 0);
148 	memset(iov, 0, sizeof(iov));
149 
150 	/* Test case where iov spans a 2MB boundary, but does not span a vhost memory region. */
151 	desc.addr = 0x1F0000;
152 	desc.len = 0x20000;
153 	iov_index = 0;
154 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
155 	CU_ASSERT(rc == 0);
156 	CU_ASSERT(iov_index == 2);
157 	CU_ASSERT(iov[0].iov_base == (void *)0x11F0000);
158 	CU_ASSERT(iov[0].iov_len == 0x10000);
159 	CU_ASSERT(iov[1].iov_base == (void *)0x1200000);
160 	CU_ASSERT(iov[1].iov_len == 0x10000);
161 	memset(iov, 0, sizeof(iov));
162 
163 	/* Same test, but ensure it respects the non-zero starting iov_index. */
164 	iov_index = SPDK_VHOST_IOVS_MAX - 2;
165 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
166 	CU_ASSERT(rc == 0);
167 	CU_ASSERT(iov_index == SPDK_VHOST_IOVS_MAX);
168 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 2].iov_base == (void *)0x11F0000);
169 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 2].iov_len == 0x10000);
170 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_base == (void *)0x1200000);
171 	CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_len == 0x10000);
172 	memset(iov, 0, sizeof(iov));
173 
174 	/*
175 	 * This test should fail.  The first part of the descriptor will fit in the last
176 	 * iov, but the part after the 2MB boundary would overflow.
177 	 */
178 	iov_index = SPDK_VHOST_IOVS_MAX - 1;
179 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
180 	CU_ASSERT(rc != 0);
181 	memset(iov, 0, sizeof(iov));
182 
183 	/* Test case where iov spans a vhost memory region. */
184 	desc.addr = 0x3F0000;
185 	desc.len = 0x20000;
186 	iov_index = 0;
187 	rc = spdk_vhost_vring_desc_to_iov(vdev, iov, &iov_index, &desc);
188 	CU_ASSERT(rc == 0);
189 	CU_ASSERT(iov_index == 2);
190 	CU_ASSERT(iov[0].iov_base == (void *)0x13F0000);
191 	CU_ASSERT(iov[0].iov_len == 0x10000);
192 	CU_ASSERT(iov[1].iov_base == (void *)0x2000000);
193 	CU_ASSERT(iov[1].iov_len == 0x10000);
194 	memset(iov, 0, sizeof(iov));
195 
196 	free_vdev(vdev);
197 
198 	CU_ASSERT(true);
199 }
200 
201 int
202 main(int argc, char **argv)
203 {
204 	CU_pSuite	suite = NULL;
205 	unsigned int	num_failures;
206 
207 	if (CU_initialize_registry() != CUE_SUCCESS) {
208 		return CU_get_error();
209 	}
210 
211 	suite = CU_add_suite("vhost_suite", test_setup, NULL);
212 	if (suite == NULL) {
213 		CU_cleanup_registry();
214 		return CU_get_error();
215 	}
216 
217 	if (
218 		CU_add_test(suite, "desc_to_iov", desc_to_iov_test) == NULL
219 	) {
220 		CU_cleanup_registry();
221 		return CU_get_error();
222 	}
223 
224 	CU_basic_set_mode(CU_BRM_VERBOSE);
225 	CU_basic_run_tests();
226 	num_failures = CU_get_number_of_failures();
227 	CU_cleanup_registry();
228 
229 	return num_failures;
230 }
231