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_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