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
_req_cb(void * cb_arg,int len)36 _req_cb(void *cb_arg, int len)
37 {
38 *(bool *)cb_arg = true;
39 CU_ASSERT(len == 0);
40 }
41
42 static void
flush_client(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
flush_server(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
main(int argc,char ** argv)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