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