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