xref: /spdk/test/unit/lib/sock/uring.c/uring_ut.c (revision 3c6897d0c303da6539e2cfe17620553aa22167cf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2019 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/util.h"
8 
9 #include "spdk_internal/mock.h"
10 
11 #include "spdk_internal/cunit.h"
12 
13 #include "common/lib/test_env.c"
14 #include "sock/uring/uring.c"
15 
16 DEFINE_STUB(spdk_sock_map_insert, int, (struct spdk_sock_map *map, int placement_id,
17 					struct spdk_sock_group_impl *group), 0);
18 DEFINE_STUB_V(spdk_sock_map_release, (struct spdk_sock_map *map, int placement_id));
19 DEFINE_STUB(spdk_sock_map_lookup, int, (struct spdk_sock_map *map, int placement_id,
20 					struct spdk_sock_group_impl **group, struct spdk_sock_group_impl *hint), 0);
21 DEFINE_STUB(spdk_sock_map_find_free, int, (struct spdk_sock_map *map), -1);
22 DEFINE_STUB_V(spdk_sock_map_cleanup, (struct spdk_sock_map *map));
23 
24 DEFINE_STUB_V(spdk_net_impl_register, (struct spdk_net_impl *impl, int priority));
25 DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **s), 0);
26 DEFINE_STUB(__io_uring_get_cqe, int, (struct io_uring *ring, struct io_uring_cqe **cqe_ptr,
27 				      unsigned submit,
28 				      unsigned wait_nr, sigset_t *sigmask), 0);
29 DEFINE_STUB(io_uring_submit, int, (struct io_uring *ring), 0);
30 DEFINE_STUB(io_uring_queue_init, int, (unsigned entries, struct io_uring *ring, unsigned flags), 0);
31 DEFINE_STUB_V(io_uring_queue_exit, (struct io_uring *ring));
32 DEFINE_STUB(spdk_sock_group_provide_buf, int, (struct spdk_sock_group *group, void *buf,
33 		size_t len, void *ctx), 0);
34 DEFINE_STUB(spdk_sock_group_get_buf, size_t, (struct spdk_sock_group *group, void **buf,
35 		void **ctx), 0);
36 
37 static void
38 _req_cb(void *cb_arg, int len)
39 {
40 	*(bool *)cb_arg = true;
41 	CU_ASSERT(len == 0);
42 }
43 
44 static void
45 flush_client(void)
46 {
47 	struct spdk_uring_sock_group_impl group = {};
48 	struct spdk_uring_sock usock = {};
49 	struct spdk_sock *sock = &usock.base;
50 	struct spdk_sock_request *req1, *req2;
51 	bool cb_arg1, cb_arg2;
52 	int rc;
53 
54 	/* Set up data structures */
55 	TAILQ_INIT(&sock->queued_reqs);
56 	TAILQ_INIT(&sock->pending_reqs);
57 	sock->group_impl = &group.base;
58 
59 	req1 = calloc(1, sizeof(struct spdk_sock_request) + 3 * sizeof(struct iovec));
60 	SPDK_CU_ASSERT_FATAL(req1 != NULL);
61 	SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100;
62 	SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64;
63 	SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200;
64 	SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64;
65 	SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_base = (void *)300;
66 	SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_len = 64;
67 	req1->iovcnt = 3;
68 	req1->cb_fn = _req_cb;
69 	req1->cb_arg = &cb_arg1;
70 
71 	req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec));
72 	SPDK_CU_ASSERT_FATAL(req2 != NULL);
73 	SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100;
74 	SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32;
75 	SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200;
76 	SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32;
77 	req2->iovcnt = 2;
78 	req2->cb_fn = _req_cb;
79 	req2->cb_arg = &cb_arg2;
80 
81 	/* Simple test - a request with a 3 element iovec
82 	 * that gets submitted in a single sendmsg. */
83 	spdk_sock_request_queue(sock, req1);
84 	MOCK_SET(sendmsg, 192);
85 	cb_arg1 = false;
86 	rc = uring_sock_flush(sock);
87 	CU_ASSERT(rc == 192);
88 	CU_ASSERT(cb_arg1 == true);
89 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
90 
91 	/* Two requests, where both can fully send. */
92 	spdk_sock_request_queue(sock, req1);
93 	spdk_sock_request_queue(sock, req2);
94 	MOCK_SET(sendmsg, 256);
95 	cb_arg1 = false;
96 	cb_arg2 = false;
97 	rc = uring_sock_flush(sock);
98 	CU_ASSERT(rc == 256);
99 	CU_ASSERT(cb_arg1 == true);
100 	CU_ASSERT(cb_arg2 == true);
101 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
102 
103 	/* Two requests. Only first one can send */
104 	spdk_sock_request_queue(sock, req1);
105 	spdk_sock_request_queue(sock, req2);
106 	MOCK_SET(sendmsg, 192);
107 	cb_arg1 = false;
108 	cb_arg2 = false;
109 	rc = uring_sock_flush(sock);
110 	CU_ASSERT(rc == 192);
111 	CU_ASSERT(cb_arg1 == true);
112 	CU_ASSERT(cb_arg2 == false);
113 	CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req2);
114 	TAILQ_REMOVE(&sock->queued_reqs, req2, internal.link);
115 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
116 
117 	/* One request. Partial send. */
118 	spdk_sock_request_queue(sock, req1);
119 	MOCK_SET(sendmsg, 10);
120 	cb_arg1 = false;
121 	rc = uring_sock_flush(sock);
122 	CU_ASSERT(rc == 10);
123 	CU_ASSERT(cb_arg1 == false);
124 	CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
125 
126 	/* Do a second flush that partial sends again. */
127 	MOCK_SET(sendmsg, 52);
128 	cb_arg1 = false;
129 	rc = uring_sock_flush(sock);
130 	CU_ASSERT(rc == 52);
131 	CU_ASSERT(cb_arg1 == false);
132 	CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
133 
134 	/* Flush the rest of the data */
135 	MOCK_SET(sendmsg, 130);
136 	cb_arg1 = false;
137 	rc = uring_sock_flush(sock);
138 	CU_ASSERT(rc == 130);
139 	CU_ASSERT(cb_arg1 == true);
140 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
141 
142 	free(req1);
143 	free(req2);
144 }
145 
146 static void
147 flush_server(void)
148 {
149 	struct spdk_uring_sock_group_impl group = {};
150 	struct spdk_uring_sock usock = {};
151 	struct spdk_sock *sock = &usock.base;
152 	struct spdk_sock_request *req1, *req2;
153 	bool cb_arg1, cb_arg2;
154 	int rc;
155 
156 	/* Set up data structures */
157 	TAILQ_INIT(&sock->queued_reqs);
158 	TAILQ_INIT(&sock->pending_reqs);
159 	sock->group_impl = &group.base;
160 	usock.write_task.sock = &usock;
161 	usock.group = &group;
162 
163 	req1 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec));
164 	SPDK_CU_ASSERT_FATAL(req1 != NULL);
165 	SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100;
166 	SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64;
167 	SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200;
168 	SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64;
169 	req1->iovcnt = 2;
170 	req1->cb_fn = _req_cb;
171 	req1->cb_arg = &cb_arg1;
172 
173 	req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec));
174 	SPDK_CU_ASSERT_FATAL(req2 != NULL);
175 	SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100;
176 	SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32;
177 	SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200;
178 	SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32;
179 	req2->iovcnt = 2;
180 	req2->cb_fn = _req_cb;
181 	req2->cb_arg = &cb_arg2;
182 
183 	/* we should not call _sock_flush directly, since it will finally
184 	 * call liburing related functions  */
185 
186 	/* Simple test - a request with a 2 element iovec
187 	 * that is fully completed. */
188 	spdk_sock_request_queue(sock, req1);
189 	cb_arg1 = false;
190 	rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL, NULL);
191 	CU_ASSERT(rc == 2);
192 	sock_complete_write_reqs(sock, 128, 0);
193 	CU_ASSERT(cb_arg1 == true);
194 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
195 
196 	/* Two requests, where both can be fully completed. */
197 	spdk_sock_request_queue(sock, req1);
198 	spdk_sock_request_queue(sock, req2);
199 	cb_arg1 = false;
200 	cb_arg2 = false;
201 	rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL, NULL);
202 	CU_ASSERT(rc == 4);
203 	sock_complete_write_reqs(sock, 192, 0);
204 	CU_ASSERT(cb_arg1 == true);
205 	CU_ASSERT(cb_arg2 == true);
206 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
207 
208 
209 	/* One request that is partially sent. */
210 	spdk_sock_request_queue(sock, req1);
211 	cb_arg1 = false;
212 	rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL, NULL);
213 	CU_ASSERT(rc == 2);
214 	sock_complete_write_reqs(sock, 92, 0);
215 	CU_ASSERT(rc == 2);
216 	CU_ASSERT(cb_arg1 == false);
217 	CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
218 
219 	/* Get the second time partial sent result. */
220 	sock_complete_write_reqs(sock, 10, 0);
221 	CU_ASSERT(cb_arg1 == false);
222 	CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
223 
224 	/* Data is finally sent. */
225 	sock_complete_write_reqs(sock, 26, 0);
226 	CU_ASSERT(cb_arg1 == true);
227 	CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
228 
229 	free(req1);
230 	free(req2);
231 }
232 
233 int
234 main(int argc, char **argv)
235 {
236 	CU_pSuite	suite = NULL;
237 	unsigned int	num_failures;
238 
239 	CU_set_error_action(CUEA_ABORT);
240 	CU_initialize_registry();
241 
242 	suite = CU_add_suite("uring", NULL, NULL);
243 
244 
245 	CU_ADD_TEST(suite, flush_client);
246 	CU_ADD_TEST(suite, flush_server);
247 
248 	CU_basic_set_mode(CU_BRM_VERBOSE);
249 
250 	CU_basic_run_tests();
251 
252 	num_failures = CU_get_number_of_failures();
253 	CU_cleanup_registry();
254 
255 	return num_failures;
256 }
257