Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
4 : : */
5 : :
6 : : /** \file
7 : : * TCP network implementation abstraction layer
8 : : */
9 : :
10 : : #ifndef SPDK_INTERNAL_SOCK_H
11 : : #define SPDK_INTERNAL_SOCK_H
12 : :
13 : : #include "spdk/stdinc.h"
14 : : #include "spdk/sock.h"
15 : : #include "spdk/queue.h"
16 : : #include "spdk/likely.h"
17 : : #include "spdk/log.h"
18 : : #include "spdk/trace.h"
19 : : #include "spdk_internal/trace_defs.h"
20 : :
21 : : #ifdef __cplusplus
22 : : extern "C" {
23 : : #endif
24 : :
25 : : #define MAX_EVENTS_PER_POLL 32
26 : : #define DEFAULT_SOCK_PRIORITY 0
27 : : #define MIN_SOCK_PIPE_SIZE 1024
28 : : #define DEFAULT_SO_RCVBUF_SIZE (2 * 1024 * 1024)
29 : : #define DEFAULT_SO_SNDBUF_SIZE (2 * 1024 * 1024)
30 : : #define MIN_SO_RCVBUF_SIZE (4 * 1024)
31 : : #define MIN_SO_SNDBUF_SIZE (4 * 1024)
32 : : #define IOV_BATCH_SIZE 64
33 : :
34 : : struct spdk_sock {
35 : : struct spdk_net_impl *net_impl;
36 : : struct spdk_sock_opts opts;
37 : : struct spdk_sock_group_impl *group_impl;
38 : : TAILQ_ENTRY(spdk_sock) link;
39 : :
40 : : TAILQ_HEAD(, spdk_sock_request) queued_reqs;
41 : : TAILQ_HEAD(, spdk_sock_request) pending_reqs;
42 : : struct spdk_sock_request *read_req;
43 : : int queued_iovcnt;
44 : : int cb_cnt;
45 : : spdk_sock_cb cb_fn;
46 : : void *cb_arg;
47 : : struct {
48 : : uint8_t closed : 1;
49 : : uint8_t reserved : 7;
50 : : } flags;
51 : : struct spdk_sock_impl_opts impl_opts;
52 : : };
53 : :
54 : : struct spdk_sock_group_provided_buf {
55 : : size_t len;
56 : : void *ctx;
57 : : STAILQ_ENTRY(spdk_sock_group_provided_buf) link;
58 : : };
59 : :
60 : : struct spdk_sock_group {
61 : : STAILQ_HEAD(, spdk_sock_group_impl) group_impls;
62 : : STAILQ_HEAD(, spdk_sock_group_provided_buf) pool;
63 : : void *ctx;
64 : : };
65 : :
66 : : struct spdk_sock_group_impl {
67 : : struct spdk_net_impl *net_impl;
68 : : struct spdk_sock_group *group;
69 : : TAILQ_HEAD(, spdk_sock) socks;
70 : : STAILQ_ENTRY(spdk_sock_group_impl) link;
71 : : };
72 : :
73 : : struct spdk_sock_map {
74 : : STAILQ_HEAD(, spdk_sock_placement_id_entry) entries;
75 : : pthread_mutex_t mtx;
76 : : };
77 : :
78 : : struct spdk_net_impl {
79 : : const char *name;
80 : :
81 : : int (*getaddr)(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, char *caddr,
82 : : int clen, uint16_t *cport);
83 : : struct spdk_sock *(*connect)(const char *ip, int port, struct spdk_sock_opts *opts);
84 : : struct spdk_sock *(*listen)(const char *ip, int port, struct spdk_sock_opts *opts);
85 : : struct spdk_sock *(*accept)(struct spdk_sock *sock);
86 : : int (*close)(struct spdk_sock *sock);
87 : : ssize_t (*recv)(struct spdk_sock *sock, void *buf, size_t len);
88 : : ssize_t (*readv)(struct spdk_sock *sock, struct iovec *iov, int iovcnt);
89 : : ssize_t (*writev)(struct spdk_sock *sock, struct iovec *iov, int iovcnt);
90 : :
91 : : int (*recv_next)(struct spdk_sock *sock, void **buf, void **ctx);
92 : : void (*writev_async)(struct spdk_sock *sock, struct spdk_sock_request *req);
93 : : void (*readv_async)(struct spdk_sock *sock, struct spdk_sock_request *req);
94 : : int (*flush)(struct spdk_sock *sock);
95 : :
96 : : int (*set_recvlowat)(struct spdk_sock *sock, int nbytes);
97 : : int (*set_recvbuf)(struct spdk_sock *sock, int sz);
98 : : int (*set_sendbuf)(struct spdk_sock *sock, int sz);
99 : :
100 : : bool (*is_ipv6)(struct spdk_sock *sock);
101 : : bool (*is_ipv4)(struct spdk_sock *sock);
102 : : bool (*is_connected)(struct spdk_sock *sock);
103 : :
104 : : struct spdk_sock_group_impl *(*group_impl_get_optimal)(struct spdk_sock *sock,
105 : : struct spdk_sock_group_impl *hint);
106 : : struct spdk_sock_group_impl *(*group_impl_create)(void);
107 : : int (*group_impl_add_sock)(struct spdk_sock_group_impl *group, struct spdk_sock *sock);
108 : : int (*group_impl_remove_sock)(struct spdk_sock_group_impl *group, struct spdk_sock *sock);
109 : : int (*group_impl_poll)(struct spdk_sock_group_impl *group, int max_events,
110 : : struct spdk_sock **socks);
111 : : int (*group_impl_register_interrupt)(struct spdk_sock_group_impl *group, uint32_t events,
112 : : spdk_interrupt_fn fn, void *arg, const char *name);
113 : : void (*group_impl_unregister_interrupt)(struct spdk_sock_group_impl *group);
114 : : int (*group_impl_close)(struct spdk_sock_group_impl *group);
115 : :
116 : : int (*get_opts)(struct spdk_sock_impl_opts *opts, size_t *len);
117 : : int (*set_opts)(const struct spdk_sock_impl_opts *opts, size_t len);
118 : :
119 : : STAILQ_ENTRY(spdk_net_impl) link;
120 : : };
121 : :
122 : : void spdk_net_impl_register(struct spdk_net_impl *impl);
123 : :
124 : : #define SPDK_NET_IMPL_REGISTER(name, impl) \
125 : : static void __attribute__((constructor)) net_impl_register_##name(void) \
126 : : { \
127 : : spdk_net_impl_register(impl); \
128 : : }
129 : :
130 : : #define SPDK_NET_IMPL_REGISTER_DEFAULT(name, impl) \
131 : : static void __attribute__((constructor)) net_impl_register_default_##name(void) \
132 : : { \
133 : : spdk_net_impl_register(impl); \
134 : : spdk_sock_set_default_impl(SPDK_STRINGIFY(name)); \
135 : : }
136 : :
137 : : size_t spdk_sock_group_get_buf(struct spdk_sock_group *group, void **buf, void **ctx);
138 : :
139 : : static inline void
140 : 66807719 : spdk_sock_request_queue(struct spdk_sock *sock, struct spdk_sock_request *req)
141 : : {
142 [ - + ]: 66807719 : assert(req->internal.curr_list == NULL);
143 [ + + + + ]: 66807719 : if (spdk_trace_tpoint_enabled(TRACE_SOCK_REQ_QUEUE)) {
144 : 22935911 : uint64_t len = 0;
145 : : int i;
146 : :
147 [ + + ]: 72704886 : for (i = 0; i < req->iovcnt; i++) {
148 : 49768975 : len += SPDK_SOCK_REQUEST_IOV(req, i)->iov_len;
149 : : }
150 [ + - + - ]: 22935911 : spdk_trace_record(TRACE_SOCK_REQ_QUEUE, 0, len, (uintptr_t)req, (uintptr_t)req->cb_arg);
151 : : }
152 : 66807719 : TAILQ_INSERT_TAIL(&sock->queued_reqs, req, internal.link);
153 : : #ifdef DEBUG
154 : 66807719 : req->internal.curr_list = &sock->queued_reqs;
155 : : #endif
156 : 66807719 : sock->queued_iovcnt += req->iovcnt;
157 : 66807719 : }
158 : :
159 : : static inline void
160 : 66806494 : spdk_sock_request_pend(struct spdk_sock *sock, struct spdk_sock_request *req)
161 : : {
162 [ - + ]: 66806494 : assert(req->internal.curr_list == &sock->queued_reqs);
163 [ + + + + ]: 66806494 : spdk_trace_record(TRACE_SOCK_REQ_PEND, 0, 0, (uintptr_t)req, (uintptr_t)req->cb_arg);
164 [ + + ]: 66806494 : TAILQ_REMOVE(&sock->queued_reqs, req, internal.link);
165 [ - + ]: 66806494 : assert(sock->queued_iovcnt >= req->iovcnt);
166 : 66806494 : sock->queued_iovcnt -= req->iovcnt;
167 : 66806494 : TAILQ_INSERT_TAIL(&sock->pending_reqs, req, internal.link);
168 : : #ifdef DEBUG
169 : 66806494 : req->internal.curr_list = &sock->pending_reqs;
170 : : #endif
171 : 66806494 : }
172 : :
173 : : static inline int
174 : 66805656 : spdk_sock_request_complete(struct spdk_sock *sock, struct spdk_sock_request *req, int err)
175 : : {
176 : : bool closed;
177 : 66805656 : int rc = 0;
178 : :
179 [ + + + + ]: 66805656 : spdk_trace_record(TRACE_SOCK_REQ_COMPLETE, 0, 0, (uintptr_t)req, (uintptr_t)req->cb_arg);
180 : 66805656 : req->internal.offset = 0;
181 : 66805656 : req->internal.is_zcopy = 0;
182 : :
183 : 66805656 : closed = sock->flags.closed;
184 : 66805656 : sock->cb_cnt++;
185 : 66805656 : req->cb_fn(req->cb_arg, err);
186 [ - + ]: 66805656 : assert(sock->cb_cnt > 0);
187 : 66805656 : sock->cb_cnt--;
188 : :
189 [ + - + - : 66805656 : if (sock->cb_cnt == 0 && !closed && sock->flags.closed) {
+ + ]
190 : : /* The user closed the socket in response to a callback above. */
191 : 6 : rc = -1;
192 : 6 : spdk_sock_close(&sock);
193 : : }
194 : :
195 : 66805656 : return rc;
196 : : }
197 : :
198 : : static inline int
199 : 66805656 : spdk_sock_request_put(struct spdk_sock *sock, struct spdk_sock_request *req, int err)
200 : : {
201 [ - + ]: 66805656 : assert(req->internal.curr_list == &sock->pending_reqs);
202 [ + + ]: 66805656 : TAILQ_REMOVE(&sock->pending_reqs, req, internal.link);
203 : : #ifdef DEBUG
204 : 66805656 : req->internal.curr_list = NULL;
205 : : #endif
206 : 66805656 : return spdk_sock_request_complete(sock, req, err);
207 : : }
208 : :
209 : : static inline int
210 : 21698 : spdk_sock_abort_requests(struct spdk_sock *sock)
211 : : {
212 : : struct spdk_sock_request *req;
213 : : bool closed;
214 : 21698 : int rc = 0;
215 : :
216 : 21698 : closed = sock->flags.closed;
217 : 21698 : sock->cb_cnt++;
218 : :
219 : 21698 : req = TAILQ_FIRST(&sock->pending_reqs);
220 [ + + ]: 22536 : while (req) {
221 [ - + ]: 838 : assert(req->internal.curr_list == &sock->pending_reqs);
222 [ + + ]: 838 : TAILQ_REMOVE(&sock->pending_reqs, req, internal.link);
223 : : #ifdef DEBUG
224 : 838 : req->internal.curr_list = NULL;
225 : : #endif
226 : :
227 : 838 : req->cb_fn(req->cb_arg, -ECANCELED);
228 : :
229 : 838 : req = TAILQ_FIRST(&sock->pending_reqs);
230 : : }
231 : :
232 : 21698 : req = TAILQ_FIRST(&sock->queued_reqs);
233 [ + + ]: 22915 : while (req) {
234 [ - + ]: 1217 : assert(req->internal.curr_list == &sock->queued_reqs);
235 [ + + ]: 1217 : TAILQ_REMOVE(&sock->queued_reqs, req, internal.link);
236 : : #ifdef DEBUG
237 : 1217 : req->internal.curr_list = NULL;
238 : : #endif
239 : :
240 [ - + ]: 1217 : assert(sock->queued_iovcnt >= req->iovcnt);
241 : 1217 : sock->queued_iovcnt -= req->iovcnt;
242 : :
243 : 1217 : req->cb_fn(req->cb_arg, -ECANCELED);
244 : :
245 : 1217 : req = TAILQ_FIRST(&sock->queued_reqs);
246 : : }
247 : :
248 : 21698 : req = sock->read_req;
249 [ - + ]: 21698 : if (req != NULL) {
250 : 0 : sock->read_req = NULL;
251 : 0 : req->cb_fn(req->cb_arg, -ECANCELED);
252 : : }
253 [ - + ]: 21698 : assert(sock->cb_cnt > 0);
254 : 21698 : sock->cb_cnt--;
255 : :
256 [ - + ]: 21698 : assert(TAILQ_EMPTY(&sock->queued_reqs));
257 [ - + ]: 21698 : assert(TAILQ_EMPTY(&sock->pending_reqs));
258 : :
259 [ + + + + : 21698 : if (sock->cb_cnt == 0 && !closed && sock->flags.closed) {
+ + ]
260 : : /* The user closed the socket in response to a callback above. */
261 : 19 : rc = -1;
262 : 19 : spdk_sock_close(&sock);
263 : : }
264 : :
265 : 21698 : return rc;
266 : : }
267 : :
268 : : static inline int
269 : 365115949 : spdk_sock_prep_req(struct spdk_sock_request *req, struct iovec *iovs, int index,
270 : : uint64_t *num_bytes)
271 : : {
272 : : unsigned int offset;
273 : : int iovcnt, i;
274 : :
275 [ - + ]: 365115949 : assert(index < IOV_BATCH_SIZE);
276 : 365115949 : offset = req->internal.offset;
277 : 365115949 : iovcnt = index;
278 : :
279 [ + + ]: 1009764529 : for (i = 0; i < req->iovcnt; i++) {
280 : : /* Consume any offset first */
281 [ + + ]: 651507684 : if (offset >= SPDK_SOCK_REQUEST_IOV(req, i)->iov_len) {
282 : 18524746 : offset -= SPDK_SOCK_REQUEST_IOV(req, i)->iov_len;
283 : 18524746 : continue;
284 : : }
285 : :
286 : 632982938 : iovs[iovcnt].iov_base = (uint8_t *)SPDK_SOCK_REQUEST_IOV(req, i)->iov_base + offset;
287 : 632982938 : iovs[iovcnt].iov_len = SPDK_SOCK_REQUEST_IOV(req, i)->iov_len - offset;
288 [ + - ]: 632982938 : if (num_bytes != NULL) {
289 : 632982938 : *num_bytes += iovs[iovcnt].iov_len;
290 : : }
291 : :
292 : 632982938 : iovcnt++;
293 : 632982938 : offset = 0;
294 : :
295 [ + + ]: 632982938 : if (iovcnt >= IOV_BATCH_SIZE) {
296 : 6859104 : break;
297 : : }
298 : : }
299 : :
300 : 365115949 : return iovcnt;
301 : : }
302 : :
303 : : static inline int
304 : 2361342838 : spdk_sock_prep_reqs(struct spdk_sock *_sock, struct iovec *iovs, int index,
305 : : struct spdk_sock_request **last_req, int *flags)
306 : : {
307 : : int iovcnt;
308 : : struct spdk_sock_request *req;
309 : 2361342838 : uint64_t total = 0;
310 : :
311 : : /* Gather an iov */
312 : 2361342838 : iovcnt = index;
313 [ + + ]: 2361342838 : if (spdk_unlikely(iovcnt >= IOV_BATCH_SIZE)) {
314 : 636350 : goto end;
315 : : }
316 : :
317 [ + + + + ]: 2360706488 : if (last_req != NULL && *last_req != NULL) {
318 : 138381 : req = TAILQ_NEXT(*last_req, internal.link);
319 : : } else {
320 : 2360568107 : req = TAILQ_FIRST(&_sock->queued_reqs);
321 : : }
322 : :
323 [ + + ]: 2718963333 : while (req) {
324 : 365115949 : iovcnt = spdk_sock_prep_req(req, iovs, iovcnt, &total);
325 [ + + ]: 365115949 : if (iovcnt >= IOV_BATCH_SIZE) {
326 : 6859104 : break;
327 : : }
328 : :
329 [ + + ]: 358256845 : if (last_req != NULL) {
330 : 23331469 : *last_req = req;
331 : : }
332 : 358256845 : req = TAILQ_NEXT(req, internal.link);
333 : : }
334 : :
335 : 2354216530 : end:
336 : :
337 : : #if defined(MSG_ZEROCOPY)
338 : : /* if data size < zerocopy_threshold, remove MSG_ZEROCOPY flag */
339 [ - + - - ]: 2361342809 : if (total < _sock->impl_opts.zerocopy_threshold && flags != NULL) {
340 : 0 : *flags = *flags & (~MSG_ZEROCOPY);
341 : : }
342 : : #endif
343 : :
344 : 2361342838 : return iovcnt;
345 : : }
346 : :
347 : : static inline void
348 : 13201 : spdk_sock_get_placement_id(int fd, enum spdk_placement_mode mode, int *placement_id)
349 : : {
350 : 13201 : *placement_id = -1;
351 : :
352 [ + + - - ]: 13201 : switch (mode) {
353 : 13195 : case PLACEMENT_NONE:
354 : 13195 : break;
355 : 6 : case PLACEMENT_MARK:
356 : : case PLACEMENT_NAPI: {
357 : : #if defined(SO_INCOMING_NAPI_ID)
358 : 6 : socklen_t len = sizeof(int);
359 : :
360 : 6 : int rc = getsockopt(fd, SOL_SOCKET, SO_INCOMING_NAPI_ID, placement_id, &len);
361 [ - + ]: 6 : if (rc == -1) {
362 : 0 : SPDK_ERRLOG("getsockopt() failed: %s\n", strerror(errno));
363 : 0 : assert(false);
364 : : }
365 : : #endif
366 : 6 : break;
367 : : }
368 : 0 : case PLACEMENT_CPU: {
369 : : #if defined(SO_INCOMING_CPU)
370 : 0 : socklen_t len = sizeof(int);
371 : :
372 : 0 : int rc = getsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, placement_id, &len);
373 [ # # ]: 0 : if (rc == -1) {
374 : 0 : SPDK_ERRLOG("getsockopt() failed: %s\n", strerror(errno));
375 : 0 : assert(false);
376 : : }
377 : : #endif
378 : 0 : break;
379 : : }
380 : 0 : default:
381 : 0 : break;
382 : : }
383 : 13201 : }
384 : :
385 : : /**
386 : : * Insert a group into the placement map.
387 : : * If the group is already in the map, take a reference.
388 : : */
389 : : int spdk_sock_map_insert(struct spdk_sock_map *map, int placement_id,
390 : : struct spdk_sock_group_impl *group_impl);
391 : :
392 : : /**
393 : : * Release a reference for the given placement_id. If the reference count goes to 0, the
394 : : * entry will no longer be associated with a group.
395 : : */
396 : : void spdk_sock_map_release(struct spdk_sock_map *map, int placement_id);
397 : :
398 : : /**
399 : : * Look up the group for the given placement_id.
400 : : */
401 : : int spdk_sock_map_lookup(struct spdk_sock_map *map, int placement_id,
402 : : struct spdk_sock_group_impl **group_impl, struct spdk_sock_group_impl *hint);
403 : :
404 : : /**
405 : : * Find a placement id with no associated group
406 : : */
407 : : int spdk_sock_map_find_free(struct spdk_sock_map *map);
408 : :
409 : : /**
410 : : * Clean up all memory associated with the given map
411 : : */
412 : : void spdk_sock_map_cleanup(struct spdk_sock_map *map);
413 : :
414 : : #ifdef __cplusplus
415 : : }
416 : : #endif
417 : :
418 : : #endif /* SPDK_INTERNAL_SOCK_H */
|