LCOV - code coverage report
Current view: top level - include/spdk_internal - sock.h (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 93 117 79.5 %
Date: 2024-07-11 18:14:01 Functions: 8 8 100.0 %

          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           8 : spdk_sock_request_queue(struct spdk_sock *sock, struct spdk_sock_request *req)
     141             : {
     142           8 :         assert(req->internal.curr_list == NULL);
     143           8 :         if (spdk_trace_tpoint_enabled(TRACE_SOCK_REQ_QUEUE)) {
     144           0 :                 uint64_t len = 0;
     145             :                 int i;
     146             : 
     147           0 :                 for (i = 0; i < req->iovcnt; i++) {
     148           0 :                         len += SPDK_SOCK_REQUEST_IOV(req, i)->iov_len;
     149             :                 }
     150           0 :                 spdk_trace_record(TRACE_SOCK_REQ_QUEUE, 0, len, (uintptr_t)req, (uintptr_t)req->cb_arg);
     151             :         }
     152           8 :         TAILQ_INSERT_TAIL(&sock->queued_reqs, req, internal.link);
     153             : #ifdef DEBUG
     154           8 :         req->internal.curr_list = &sock->queued_reqs;
     155             : #endif
     156           8 :         sock->queued_iovcnt += req->iovcnt;
     157           8 : }
     158             : 
     159             : static inline void
     160           6 : spdk_sock_request_pend(struct spdk_sock *sock, struct spdk_sock_request *req)
     161             : {
     162           6 :         assert(req->internal.curr_list == &sock->queued_reqs);
     163           6 :         spdk_trace_record(TRACE_SOCK_REQ_PEND, 0, 0, (uintptr_t)req, (uintptr_t)req->cb_arg);
     164           6 :         TAILQ_REMOVE(&sock->queued_reqs, req, internal.link);
     165           6 :         assert(sock->queued_iovcnt >= req->iovcnt);
     166           6 :         sock->queued_iovcnt -= req->iovcnt;
     167           6 :         TAILQ_INSERT_TAIL(&sock->pending_reqs, req, internal.link);
     168             : #ifdef DEBUG
     169           6 :         req->internal.curr_list = &sock->pending_reqs;
     170             : #endif
     171           6 : }
     172             : 
     173             : static inline int
     174           6 : spdk_sock_request_complete(struct spdk_sock *sock, struct spdk_sock_request *req, int err)
     175             : {
     176             :         bool closed;
     177           6 :         int rc = 0;
     178             : 
     179           6 :         spdk_trace_record(TRACE_SOCK_REQ_COMPLETE, 0, 0, (uintptr_t)req, (uintptr_t)req->cb_arg);
     180           6 :         req->internal.offset = 0;
     181           6 :         req->internal.is_zcopy = 0;
     182             : 
     183           6 :         closed = sock->flags.closed;
     184           6 :         sock->cb_cnt++;
     185           6 :         req->cb_fn(req->cb_arg, err);
     186           6 :         assert(sock->cb_cnt > 0);
     187           6 :         sock->cb_cnt--;
     188             : 
     189           6 :         if (sock->cb_cnt == 0 && !closed && sock->flags.closed) {
     190             :                 /* The user closed the socket in response to a callback above. */
     191           1 :                 rc = -1;
     192           1 :                 spdk_sock_close(&sock);
     193             :         }
     194             : 
     195           6 :         return rc;
     196             : }
     197             : 
     198             : static inline int
     199           6 : spdk_sock_request_put(struct spdk_sock *sock, struct spdk_sock_request *req, int err)
     200             : {
     201           6 :         assert(req->internal.curr_list == &sock->pending_reqs);
     202           6 :         TAILQ_REMOVE(&sock->pending_reqs, req, internal.link);
     203             : #ifdef DEBUG
     204           6 :         req->internal.curr_list = NULL;
     205             : #endif
     206           6 :         return spdk_sock_request_complete(sock, req, err);
     207             : }
     208             : 
     209             : static inline int
     210          32 : spdk_sock_abort_requests(struct spdk_sock *sock)
     211             : {
     212             :         struct spdk_sock_request *req;
     213             :         bool closed;
     214          32 :         int rc = 0;
     215             : 
     216          32 :         closed = sock->flags.closed;
     217          32 :         sock->cb_cnt++;
     218             : 
     219          32 :         req = TAILQ_FIRST(&sock->pending_reqs);
     220          32 :         while (req) {
     221           0 :                 assert(req->internal.curr_list == &sock->pending_reqs);
     222           0 :                 TAILQ_REMOVE(&sock->pending_reqs, req, internal.link);
     223             : #ifdef DEBUG
     224           0 :                 req->internal.curr_list = NULL;
     225             : #endif
     226             : 
     227           0 :                 req->cb_fn(req->cb_arg, -ECANCELED);
     228             : 
     229           0 :                 req = TAILQ_FIRST(&sock->pending_reqs);
     230             :         }
     231             : 
     232          32 :         req = TAILQ_FIRST(&sock->queued_reqs);
     233          33 :         while (req) {
     234           1 :                 assert(req->internal.curr_list == &sock->queued_reqs);
     235           1 :                 TAILQ_REMOVE(&sock->queued_reqs, req, internal.link);
     236             : #ifdef DEBUG
     237           1 :                 req->internal.curr_list = NULL;
     238             : #endif
     239             : 
     240           1 :                 assert(sock->queued_iovcnt >= req->iovcnt);
     241           1 :                 sock->queued_iovcnt -= req->iovcnt;
     242             : 
     243           1 :                 req->cb_fn(req->cb_arg, -ECANCELED);
     244             : 
     245           1 :                 req = TAILQ_FIRST(&sock->queued_reqs);
     246             :         }
     247             : 
     248          32 :         req = sock->read_req;
     249          32 :         if (req != NULL) {
     250           0 :                 sock->read_req = NULL;
     251           0 :                 req->cb_fn(req->cb_arg, -ECANCELED);
     252             :         }
     253          32 :         assert(sock->cb_cnt > 0);
     254          32 :         sock->cb_cnt--;
     255             : 
     256          32 :         assert(TAILQ_EMPTY(&sock->queued_reqs));
     257          32 :         assert(TAILQ_EMPTY(&sock->pending_reqs));
     258             : 
     259          32 :         if (sock->cb_cnt == 0 && !closed && sock->flags.closed) {
     260             :                 /* The user closed the socket in response to a callback above. */
     261           0 :                 rc = -1;
     262           0 :                 spdk_sock_close(&sock);
     263             :         }
     264             : 
     265          32 :         return rc;
     266             : }
     267             : 
     268             : static inline int
     269          10 : 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          10 :         assert(index < IOV_BATCH_SIZE);
     276          10 :         offset = req->internal.offset;
     277          10 :         iovcnt = index;
     278             : 
     279          28 :         for (i = 0; i < req->iovcnt; i++) {
     280             :                 /* Consume any offset first */
     281          18 :                 if (offset >= SPDK_SOCK_REQUEST_IOV(req, i)->iov_len) {
     282           1 :                         offset -= SPDK_SOCK_REQUEST_IOV(req, i)->iov_len;
     283           1 :                         continue;
     284             :                 }
     285             : 
     286          17 :                 iovs[iovcnt].iov_base = (uint8_t *)SPDK_SOCK_REQUEST_IOV(req, i)->iov_base + offset;
     287          17 :                 iovs[iovcnt].iov_len = SPDK_SOCK_REQUEST_IOV(req, i)->iov_len - offset;
     288          17 :                 if (num_bytes != NULL) {
     289          17 :                         *num_bytes += iovs[iovcnt].iov_len;
     290             :                 }
     291             : 
     292          17 :                 iovcnt++;
     293          17 :                 offset = 0;
     294             : 
     295          17 :                 if (iovcnt >= IOV_BATCH_SIZE) {
     296           0 :                         break;
     297             :                 }
     298             :         }
     299             : 
     300          10 :         return iovcnt;
     301             : }
     302             : 
     303             : static inline int
     304          29 : 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          29 :         uint64_t total = 0;
     310             : 
     311             :         /* Gather an iov */
     312          29 :         iovcnt = index;
     313          29 :         if (spdk_unlikely(iovcnt >= IOV_BATCH_SIZE)) {
     314           0 :                 goto end;
     315             :         }
     316             : 
     317          29 :         if (last_req != NULL && *last_req != NULL) {
     318           0 :                 req = TAILQ_NEXT(*last_req, internal.link);
     319             :         } else {
     320          29 :                 req = TAILQ_FIRST(&_sock->queued_reqs);
     321             :         }
     322             : 
     323          39 :         while (req) {
     324          10 :                 iovcnt = spdk_sock_prep_req(req, iovs, iovcnt, &total);
     325          10 :                 if (iovcnt >= IOV_BATCH_SIZE) {
     326           0 :                         break;
     327             :                 }
     328             : 
     329          10 :                 if (last_req != NULL) {
     330           0 :                         *last_req = req;
     331             :                 }
     332          10 :                 req = TAILQ_NEXT(req, internal.link);
     333             :         }
     334             : 
     335          29 : end:
     336             : 
     337             : #if defined(MSG_ZEROCOPY)
     338             :         /* if data size < zerocopy_threshold, remove MSG_ZEROCOPY flag */
     339             :         if (total < _sock->impl_opts.zerocopy_threshold && flags != NULL) {
     340             :                 *flags = *flags & (~MSG_ZEROCOPY);
     341             :         }
     342             : #endif
     343             : 
     344          29 :         return iovcnt;
     345             : }
     346             : 
     347             : static inline void
     348          21 : spdk_sock_get_placement_id(int fd, enum spdk_placement_mode mode, int *placement_id)
     349             : {
     350          21 :         *placement_id = -1;
     351             : 
     352          21 :         switch (mode) {
     353          21 :         case PLACEMENT_NONE:
     354          21 :                 break;
     355           0 :         case PLACEMENT_MARK:
     356             :         case PLACEMENT_NAPI: {
     357             : #if defined(SO_INCOMING_NAPI_ID)
     358             :                 socklen_t len = sizeof(int);
     359             : 
     360             :                 int rc = getsockopt(fd, SOL_SOCKET, SO_INCOMING_NAPI_ID, placement_id, &len);
     361             :                 if (rc == -1) {
     362             :                         SPDK_ERRLOG("getsockopt() failed: %s\n", strerror(errno));
     363             :                         assert(false);
     364             :                 }
     365             : #endif
     366           0 :                 break;
     367             :         }
     368           0 :         case PLACEMENT_CPU: {
     369             : #if defined(SO_INCOMING_CPU)
     370             :                 socklen_t len = sizeof(int);
     371             : 
     372             :                 int rc = getsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, placement_id, &len);
     373             :                 if (rc == -1) {
     374             :                         SPDK_ERRLOG("getsockopt() failed: %s\n", strerror(errno));
     375             :                         assert(false);
     376             :                 }
     377             : #endif
     378           0 :                 break;
     379             :         }
     380           0 :         default:
     381           0 :                 break;
     382             :         }
     383          21 : }
     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 */

Generated by: LCOV version 1.15