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