Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
4 : * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : */
6 :
7 : #include "spdk/stdinc.h"
8 :
9 : #include "spdk/sock.h"
10 : #include "spdk_internal/sock.h"
11 : #include "spdk/log.h"
12 : #include "spdk/env.h"
13 : #include "spdk/util.h"
14 : #include "spdk/trace.h"
15 : #include "spdk/thread.h"
16 : #include "spdk_internal/trace_defs.h"
17 :
18 : #define SPDK_SOCK_DEFAULT_PRIORITY 0
19 : #define SPDK_SOCK_DEFAULT_ZCOPY true
20 : #define SPDK_SOCK_DEFAULT_ACK_TIMEOUT 0
21 :
22 : #define SPDK_SOCK_OPTS_FIELD_OK(opts, field) (offsetof(struct spdk_sock_opts, field) + sizeof(opts->field) <= (opts->opts_size))
23 :
24 : static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls);
25 : static struct spdk_net_impl *g_default_impl;
26 :
27 : struct spdk_sock_placement_id_entry {
28 : int placement_id;
29 : uint32_t ref;
30 : struct spdk_sock_group_impl *group;
31 : STAILQ_ENTRY(spdk_sock_placement_id_entry) link;
32 : };
33 :
34 : static inline struct spdk_sock_group_impl *
35 14 : sock_get_group_impl_from_group(struct spdk_sock *sock, struct spdk_sock_group *group)
36 : {
37 14 : struct spdk_sock_group_impl *group_impl = NULL;
38 :
39 36 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
40 36 : if (sock->net_impl == group_impl->net_impl) {
41 14 : return group_impl;
42 : }
43 : }
44 0 : return NULL;
45 : }
46 :
47 : /* Called under map->mtx lock */
48 : static struct spdk_sock_placement_id_entry *
49 7 : _sock_map_entry_alloc(struct spdk_sock_map *map, int placement_id)
50 : {
51 : struct spdk_sock_placement_id_entry *entry;
52 :
53 7 : entry = calloc(1, sizeof(*entry));
54 7 : if (!entry) {
55 0 : SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id);
56 0 : return NULL;
57 : }
58 :
59 7 : entry->placement_id = placement_id;
60 :
61 7 : STAILQ_INSERT_TAIL(&map->entries, entry, link);
62 :
63 7 : return entry;
64 : }
65 :
66 : int
67 11 : spdk_sock_map_insert(struct spdk_sock_map *map, int placement_id,
68 : struct spdk_sock_group_impl *group)
69 : {
70 : struct spdk_sock_placement_id_entry *entry;
71 11 : int rc = 0;
72 :
73 11 : pthread_mutex_lock(&map->mtx);
74 12 : STAILQ_FOREACH(entry, &map->entries, link) {
75 6 : if (placement_id == entry->placement_id) {
76 : /* Can't set group to NULL if it is already not-NULL */
77 5 : if (group == NULL) {
78 0 : rc = (entry->group == NULL) ? 0 : -EINVAL;
79 0 : goto end;
80 : }
81 :
82 5 : if (entry->group == NULL) {
83 1 : entry->group = group;
84 4 : } else if (entry->group != group) {
85 2 : rc = -EINVAL;
86 2 : goto end;
87 : }
88 :
89 3 : entry->ref++;
90 3 : goto end;
91 : }
92 : }
93 :
94 6 : entry = _sock_map_entry_alloc(map, placement_id);
95 6 : if (entry == NULL) {
96 0 : rc = -ENOMEM;
97 0 : goto end;
98 : }
99 6 : if (group) {
100 5 : entry->group = group;
101 5 : entry->ref++;
102 : }
103 1 : end:
104 11 : pthread_mutex_unlock(&map->mtx);
105 :
106 11 : return rc;
107 : }
108 :
109 : void
110 3 : spdk_sock_map_release(struct spdk_sock_map *map, int placement_id)
111 : {
112 : struct spdk_sock_placement_id_entry *entry;
113 :
114 3 : pthread_mutex_lock(&map->mtx);
115 3 : STAILQ_FOREACH(entry, &map->entries, link) {
116 3 : if (placement_id == entry->placement_id) {
117 3 : assert(entry->ref > 0);
118 3 : entry->ref--;
119 :
120 3 : if (entry->ref == 0) {
121 2 : entry->group = NULL;
122 : }
123 3 : break;
124 : }
125 : }
126 :
127 3 : pthread_mutex_unlock(&map->mtx);
128 3 : }
129 :
130 : int
131 12 : spdk_sock_map_lookup(struct spdk_sock_map *map, int placement_id,
132 : struct spdk_sock_group_impl **group, struct spdk_sock_group_impl *hint)
133 : {
134 : struct spdk_sock_placement_id_entry *entry;
135 :
136 12 : *group = NULL;
137 12 : pthread_mutex_lock(&map->mtx);
138 13 : STAILQ_FOREACH(entry, &map->entries, link) {
139 11 : if (placement_id == entry->placement_id) {
140 10 : *group = entry->group;
141 10 : if (*group != NULL) {
142 : /* Return previously assigned sock_group */
143 8 : pthread_mutex_unlock(&map->mtx);
144 8 : return 0;
145 : }
146 2 : break;
147 : }
148 : }
149 :
150 : /* No entry with assigned sock_group, nor hint to use */
151 4 : if (hint == NULL) {
152 3 : pthread_mutex_unlock(&map->mtx);
153 3 : return -EINVAL;
154 : }
155 :
156 : /* Create new entry if there is none with matching placement_id */
157 1 : if (entry == NULL) {
158 1 : entry = _sock_map_entry_alloc(map, placement_id);
159 1 : if (entry == NULL) {
160 0 : pthread_mutex_unlock(&map->mtx);
161 0 : return -ENOMEM;
162 : }
163 : }
164 :
165 1 : entry->group = hint;
166 1 : pthread_mutex_unlock(&map->mtx);
167 :
168 1 : return 0;
169 : }
170 :
171 : void
172 7 : spdk_sock_map_cleanup(struct spdk_sock_map *map)
173 : {
174 : struct spdk_sock_placement_id_entry *entry, *tmp;
175 :
176 7 : pthread_mutex_lock(&map->mtx);
177 14 : STAILQ_FOREACH_SAFE(entry, &map->entries, link, tmp) {
178 7 : STAILQ_REMOVE(&map->entries, entry, spdk_sock_placement_id_entry, link);
179 7 : free(entry);
180 : }
181 7 : pthread_mutex_unlock(&map->mtx);
182 7 : }
183 :
184 : int
185 5 : spdk_sock_map_find_free(struct spdk_sock_map *map)
186 : {
187 : struct spdk_sock_placement_id_entry *entry;
188 5 : int placement_id = -1;
189 :
190 5 : pthread_mutex_lock(&map->mtx);
191 7 : STAILQ_FOREACH(entry, &map->entries, link) {
192 4 : if (entry->group == NULL) {
193 2 : placement_id = entry->placement_id;
194 2 : break;
195 : }
196 : }
197 :
198 5 : pthread_mutex_unlock(&map->mtx);
199 :
200 5 : return placement_id;
201 : }
202 :
203 : int
204 2 : spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group,
205 : struct spdk_sock_group *hint)
206 : {
207 : struct spdk_sock_group_impl *group_impl;
208 2 : struct spdk_sock_group_impl *hint_group_impl = NULL;
209 :
210 2 : assert(group != NULL);
211 :
212 2 : if (hint != NULL) {
213 2 : hint_group_impl = sock_get_group_impl_from_group(sock, hint);
214 2 : if (hint_group_impl == NULL) {
215 0 : return -EINVAL;
216 : }
217 : }
218 :
219 2 : group_impl = sock->net_impl->group_impl_get_optimal(sock, hint_group_impl);
220 :
221 2 : if (group_impl) {
222 0 : *group = group_impl->group;
223 : }
224 :
225 2 : return 0;
226 : }
227 :
228 : int
229 0 : spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport,
230 : char *caddr, int clen, uint16_t *cport)
231 : {
232 0 : return sock->net_impl->getaddr(sock, saddr, slen, sport, caddr, clen, cport);
233 : }
234 :
235 : const char *
236 6 : spdk_sock_get_interface_name(struct spdk_sock *sock)
237 : {
238 6 : if (sock->net_impl->get_interface_name) {
239 6 : return sock->net_impl->get_interface_name(sock);
240 : } else {
241 0 : return NULL;
242 : }
243 : }
244 :
245 : uint32_t
246 0 : spdk_sock_get_numa_socket_id(struct spdk_sock *sock)
247 : {
248 0 : if (sock->net_impl->get_numa_socket_id) {
249 0 : return sock->net_impl->get_numa_socket_id(sock);
250 : } else {
251 0 : return SPDK_ENV_SOCKET_ID_ANY;
252 : }
253 : }
254 :
255 : const char *
256 0 : spdk_sock_get_impl_name(struct spdk_sock *sock)
257 : {
258 0 : return sock->net_impl->name;
259 : }
260 :
261 : void
262 44 : spdk_sock_get_default_opts(struct spdk_sock_opts *opts)
263 : {
264 44 : assert(opts);
265 :
266 44 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) {
267 42 : opts->priority = SPDK_SOCK_DEFAULT_PRIORITY;
268 : }
269 :
270 44 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) {
271 42 : opts->zcopy = SPDK_SOCK_DEFAULT_ZCOPY;
272 : }
273 :
274 44 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, ack_timeout)) {
275 42 : opts->ack_timeout = SPDK_SOCK_DEFAULT_ACK_TIMEOUT;
276 : }
277 :
278 44 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
279 42 : opts->impl_opts = NULL;
280 : }
281 :
282 44 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts_size)) {
283 42 : opts->impl_opts_size = 0;
284 : }
285 44 : }
286 :
287 : /*
288 : * opts The opts allocated in the current library.
289 : * opts_user The opts passed by the caller.
290 : * */
291 : static void
292 20 : sock_init_opts(struct spdk_sock_opts *opts, struct spdk_sock_opts *opts_user)
293 : {
294 20 : assert(opts);
295 20 : assert(opts_user);
296 :
297 20 : opts->opts_size = sizeof(*opts);
298 20 : spdk_sock_get_default_opts(opts);
299 :
300 : /* reset the size according to the user */
301 20 : opts->opts_size = opts_user->opts_size;
302 20 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) {
303 20 : opts->priority = opts_user->priority;
304 : }
305 :
306 20 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) {
307 20 : opts->zcopy = opts_user->zcopy;
308 : }
309 :
310 20 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, ack_timeout)) {
311 20 : opts->ack_timeout = opts_user->ack_timeout;
312 : }
313 :
314 20 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
315 20 : opts->impl_opts = opts_user->impl_opts;
316 : }
317 :
318 20 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
319 20 : opts->impl_opts_size = opts_user->impl_opts_size;
320 : }
321 20 : }
322 :
323 : struct spdk_sock *
324 8 : spdk_sock_connect(const char *ip, int port, const char *impl_name)
325 : {
326 8 : struct spdk_sock_opts opts;
327 :
328 8 : opts.opts_size = sizeof(opts);
329 8 : spdk_sock_get_default_opts(&opts);
330 8 : return spdk_sock_connect_ext(ip, port, impl_name, &opts);
331 : }
332 :
333 : struct spdk_sock *
334 11 : spdk_sock_connect_ext(const char *ip, int port, const char *_impl_name, struct spdk_sock_opts *opts)
335 : {
336 11 : struct spdk_net_impl *impl = NULL;
337 : struct spdk_sock *sock;
338 11 : struct spdk_sock_opts opts_local;
339 11 : const char *impl_name = NULL;
340 :
341 11 : if (opts == NULL) {
342 0 : SPDK_ERRLOG("the opts should not be NULL pointer\n");
343 0 : return NULL;
344 : }
345 :
346 11 : if (_impl_name) {
347 11 : impl_name = _impl_name;
348 0 : } else if (g_default_impl) {
349 0 : impl_name = g_default_impl->name;
350 : }
351 :
352 29 : STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
353 29 : if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
354 18 : continue;
355 : }
356 :
357 11 : SPDK_DEBUGLOG(sock, "Creating a client socket using impl %s\n", impl->name);
358 11 : sock_init_opts(&opts_local, opts);
359 11 : sock = impl->connect(ip, port, &opts_local);
360 11 : if (sock != NULL) {
361 : /* Copy the contents, both the two structures are the same ABI version */
362 11 : memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
363 : /* Clear out impl_opts to make sure we don't keep reference to a dangling
364 : * pointer */
365 11 : sock->opts.impl_opts = NULL;
366 11 : sock->net_impl = impl;
367 11 : TAILQ_INIT(&sock->queued_reqs);
368 11 : TAILQ_INIT(&sock->pending_reqs);
369 :
370 11 : return sock;
371 : }
372 : }
373 :
374 0 : return NULL;
375 : }
376 :
377 : struct spdk_sock *
378 6 : spdk_sock_listen(const char *ip, int port, const char *impl_name)
379 : {
380 6 : struct spdk_sock_opts opts;
381 :
382 6 : opts.opts_size = sizeof(opts);
383 6 : spdk_sock_get_default_opts(&opts);
384 6 : return spdk_sock_listen_ext(ip, port, impl_name, &opts);
385 : }
386 :
387 : struct spdk_sock *
388 9 : spdk_sock_listen_ext(const char *ip, int port, const char *_impl_name, struct spdk_sock_opts *opts)
389 : {
390 9 : struct spdk_net_impl *impl = NULL;
391 : struct spdk_sock *sock;
392 9 : struct spdk_sock_opts opts_local;
393 9 : const char *impl_name = NULL;
394 :
395 9 : if (opts == NULL) {
396 0 : SPDK_ERRLOG("the opts should not be NULL pointer\n");
397 0 : return NULL;
398 : }
399 :
400 9 : if (_impl_name) {
401 9 : impl_name = _impl_name;
402 0 : } else if (g_default_impl) {
403 0 : impl_name = g_default_impl->name;
404 : }
405 :
406 23 : STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
407 23 : if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
408 14 : continue;
409 : }
410 :
411 9 : SPDK_DEBUGLOG(sock, "Creating a listening socket using impl %s\n", impl->name);
412 9 : sock_init_opts(&opts_local, opts);
413 9 : sock = impl->listen(ip, port, &opts_local);
414 9 : if (sock != NULL) {
415 : /* Copy the contents, both the two structures are the same ABI version */
416 9 : memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
417 : /* Clear out impl_opts to make sure we don't keep reference to a dangling
418 : * pointer */
419 9 : sock->opts.impl_opts = NULL;
420 9 : sock->net_impl = impl;
421 : /* Don't need to initialize the request queues for listen
422 : * sockets. */
423 9 : return sock;
424 : }
425 : }
426 :
427 0 : return NULL;
428 : }
429 :
430 : struct spdk_sock *
431 14 : spdk_sock_accept(struct spdk_sock *sock)
432 : {
433 : struct spdk_sock *new_sock;
434 :
435 14 : new_sock = sock->net_impl->accept(sock);
436 14 : if (new_sock != NULL) {
437 : /* Inherit the opts from the "accept sock" */
438 10 : new_sock->opts = sock->opts;
439 10 : memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts));
440 10 : new_sock->net_impl = sock->net_impl;
441 10 : TAILQ_INIT(&new_sock->queued_reqs);
442 10 : TAILQ_INIT(&new_sock->pending_reqs);
443 : }
444 :
445 14 : return new_sock;
446 : }
447 :
448 : int
449 33 : spdk_sock_close(struct spdk_sock **_sock)
450 : {
451 33 : struct spdk_sock *sock = *_sock;
452 :
453 33 : if (sock == NULL) {
454 0 : errno = EBADF;
455 0 : return -1;
456 : }
457 :
458 33 : if (sock->cb_fn != NULL) {
459 : /* This sock is still part of a sock_group. */
460 2 : errno = EBUSY;
461 2 : return -1;
462 : }
463 :
464 : /* Beyond this point the socket is considered closed. */
465 31 : *_sock = NULL;
466 :
467 31 : sock->flags.closed = true;
468 :
469 31 : if (sock->cb_cnt > 0) {
470 : /* Let the callback unwind before destroying the socket */
471 1 : return 0;
472 : }
473 :
474 30 : spdk_sock_abort_requests(sock);
475 :
476 30 : return sock->net_impl->close(sock);
477 : }
478 :
479 : ssize_t
480 10 : spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len)
481 : {
482 10 : if (sock == NULL || sock->flags.closed) {
483 0 : errno = EBADF;
484 0 : return -1;
485 : }
486 :
487 10 : return sock->net_impl->recv(sock, buf, len);
488 : }
489 :
490 : ssize_t
491 4 : spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
492 : {
493 4 : if (sock == NULL || sock->flags.closed) {
494 0 : errno = EBADF;
495 0 : return -1;
496 : }
497 :
498 4 : return sock->net_impl->readv(sock, iov, iovcnt);
499 : }
500 :
501 : ssize_t
502 10 : spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
503 : {
504 10 : if (sock == NULL || sock->flags.closed) {
505 0 : errno = EBADF;
506 0 : return -1;
507 : }
508 :
509 10 : return sock->net_impl->writev(sock, iov, iovcnt);
510 : }
511 :
512 : void
513 2 : spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req)
514 : {
515 2 : assert(req->cb_fn != NULL);
516 :
517 2 : if (sock == NULL || sock->flags.closed) {
518 0 : req->cb_fn(req->cb_arg, -EBADF);
519 0 : return;
520 : }
521 :
522 2 : sock->net_impl->writev_async(sock, req);
523 : }
524 :
525 : int
526 0 : spdk_sock_recv_next(struct spdk_sock *sock, void **buf, void **ctx)
527 : {
528 0 : if (sock == NULL || sock->flags.closed) {
529 0 : errno = EBADF;
530 0 : return -1;
531 : }
532 :
533 0 : if (sock->group_impl == NULL) {
534 0 : errno = ENOTSUP;
535 0 : return -1;
536 : }
537 :
538 0 : return sock->net_impl->recv_next(sock, buf, ctx);
539 : }
540 :
541 : int
542 2 : spdk_sock_flush(struct spdk_sock *sock)
543 : {
544 2 : if (sock == NULL || sock->flags.closed) {
545 1 : errno = EBADF;
546 1 : return -1;
547 : }
548 :
549 1 : return sock->net_impl->flush(sock);
550 : }
551 :
552 : int
553 2 : spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
554 : {
555 2 : return sock->net_impl->set_recvlowat(sock, nbytes);
556 : }
557 :
558 : int
559 2 : spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
560 : {
561 2 : return sock->net_impl->set_recvbuf(sock, sz);
562 : }
563 :
564 : int
565 2 : spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
566 : {
567 2 : return sock->net_impl->set_sendbuf(sock, sz);
568 : }
569 :
570 : bool
571 2 : spdk_sock_is_ipv6(struct spdk_sock *sock)
572 : {
573 2 : return sock->net_impl->is_ipv6(sock);
574 : }
575 :
576 : bool
577 2 : spdk_sock_is_ipv4(struct spdk_sock *sock)
578 : {
579 2 : return sock->net_impl->is_ipv4(sock);
580 : }
581 :
582 : bool
583 6 : spdk_sock_is_connected(struct spdk_sock *sock)
584 : {
585 6 : return sock->net_impl->is_connected(sock);
586 : }
587 :
588 : struct spdk_sock_group *
589 6 : spdk_sock_group_create(void *ctx)
590 : {
591 6 : struct spdk_net_impl *impl = NULL;
592 : struct spdk_sock_group *group;
593 : struct spdk_sock_group_impl *group_impl;
594 :
595 6 : group = calloc(1, sizeof(*group));
596 6 : if (group == NULL) {
597 0 : return NULL;
598 : }
599 :
600 6 : STAILQ_INIT(&group->group_impls);
601 6 : STAILQ_INIT(&group->pool);
602 :
603 24 : STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
604 18 : group_impl = impl->group_impl_create();
605 18 : if (group_impl != NULL) {
606 18 : STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
607 18 : TAILQ_INIT(&group_impl->socks);
608 18 : group_impl->net_impl = impl;
609 18 : group_impl->group = group;
610 : }
611 : }
612 :
613 6 : group->ctx = ctx;
614 :
615 6 : return group;
616 : }
617 :
618 : void *
619 2 : spdk_sock_group_get_ctx(struct spdk_sock_group *group)
620 : {
621 2 : if (group == NULL) {
622 1 : return NULL;
623 : }
624 :
625 1 : return group->ctx;
626 : }
627 :
628 : int
629 10 : spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
630 : spdk_sock_cb cb_fn, void *cb_arg)
631 : {
632 10 : struct spdk_sock_group_impl *group_impl = NULL;
633 : int rc;
634 :
635 10 : if (cb_fn == NULL) {
636 2 : errno = EINVAL;
637 2 : return -1;
638 : }
639 :
640 8 : if (sock->group_impl != NULL) {
641 : /*
642 : * This sock is already part of a sock_group.
643 : */
644 2 : errno = EINVAL;
645 2 : return -1;
646 : }
647 :
648 6 : group_impl = sock_get_group_impl_from_group(sock, group);
649 6 : if (group_impl == NULL) {
650 0 : errno = EINVAL;
651 0 : return -1;
652 : }
653 :
654 6 : rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
655 6 : if (rc != 0) {
656 0 : return rc;
657 : }
658 :
659 6 : TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
660 6 : sock->group_impl = group_impl;
661 6 : sock->cb_fn = cb_fn;
662 6 : sock->cb_arg = cb_arg;
663 :
664 6 : return 0;
665 : }
666 :
667 : int
668 6 : spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
669 : {
670 6 : struct spdk_sock_group_impl *group_impl = NULL;
671 : int rc;
672 :
673 6 : group_impl = sock_get_group_impl_from_group(sock, group);
674 6 : if (group_impl == NULL) {
675 0 : errno = EINVAL;
676 0 : return -1;
677 : }
678 :
679 6 : assert(group_impl == sock->group_impl);
680 :
681 6 : rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
682 6 : if (rc == 0) {
683 6 : TAILQ_REMOVE(&group_impl->socks, sock, link);
684 6 : sock->group_impl = NULL;
685 6 : sock->cb_fn = NULL;
686 6 : sock->cb_arg = NULL;
687 : }
688 :
689 6 : return rc;
690 : }
691 :
692 : int
693 0 : spdk_sock_group_provide_buf(struct spdk_sock_group *group, void *buf, size_t len, void *ctx)
694 : {
695 : struct spdk_sock_group_provided_buf *provided;
696 :
697 0 : provided = (struct spdk_sock_group_provided_buf *)buf;
698 :
699 0 : provided->len = len;
700 0 : provided->ctx = ctx;
701 0 : STAILQ_INSERT_HEAD(&group->pool, provided, link);
702 :
703 0 : return 0;
704 : }
705 :
706 : size_t
707 0 : spdk_sock_group_get_buf(struct spdk_sock_group *group, void **buf, void **ctx)
708 : {
709 : struct spdk_sock_group_provided_buf *provided;
710 :
711 0 : provided = STAILQ_FIRST(&group->pool);
712 0 : if (provided == NULL) {
713 0 : *buf = NULL;
714 0 : return 0;
715 : }
716 0 : STAILQ_REMOVE_HEAD(&group->pool, link);
717 :
718 0 : *buf = provided;
719 0 : *ctx = provided->ctx;
720 0 : return provided->len;
721 : }
722 :
723 : int
724 5 : spdk_sock_group_poll(struct spdk_sock_group *group)
725 : {
726 5 : return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
727 : }
728 :
729 : static int
730 27 : sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
731 : struct spdk_sock_group *group,
732 : int max_events)
733 : {
734 27 : struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
735 : int num_events, i;
736 :
737 27 : if (TAILQ_EMPTY(&group_impl->socks)) {
738 18 : return 0;
739 : }
740 :
741 9 : num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
742 9 : if (num_events == -1) {
743 0 : return -1;
744 : }
745 :
746 15 : for (i = 0; i < num_events; i++) {
747 6 : struct spdk_sock *sock = socks[i];
748 6 : assert(sock->cb_fn != NULL);
749 6 : sock->cb_fn(sock->cb_arg, group, sock);
750 : }
751 :
752 9 : return num_events;
753 : }
754 :
755 : int
756 9 : spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
757 : {
758 9 : struct spdk_sock_group_impl *group_impl = NULL;
759 9 : int rc, num_events = 0;
760 :
761 9 : if (max_events < 1) {
762 0 : errno = -EINVAL;
763 0 : return -1;
764 : }
765 :
766 : /*
767 : * Only poll for up to 32 events at a time - if more events are pending,
768 : * the next call to this function will reap them.
769 : */
770 9 : if (max_events > MAX_EVENTS_PER_POLL) {
771 0 : max_events = MAX_EVENTS_PER_POLL;
772 : }
773 :
774 36 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
775 27 : rc = sock_group_impl_poll_count(group_impl, group, max_events);
776 27 : if (rc < 0) {
777 0 : num_events = -1;
778 0 : SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
779 : group_impl->net_impl->name);
780 27 : } else if (num_events >= 0) {
781 27 : num_events += rc;
782 : }
783 : }
784 :
785 9 : return num_events;
786 : }
787 :
788 : int
789 8 : spdk_sock_group_close(struct spdk_sock_group **group)
790 : {
791 8 : struct spdk_sock_group_impl *group_impl = NULL, *tmp;
792 : int rc;
793 :
794 8 : if (*group == NULL) {
795 0 : errno = EBADF;
796 0 : return -1;
797 : }
798 :
799 28 : STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
800 22 : if (!TAILQ_EMPTY(&group_impl->socks)) {
801 2 : errno = EBUSY;
802 2 : return -1;
803 : }
804 : }
805 :
806 24 : STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
807 18 : rc = group_impl->net_impl->group_impl_close(group_impl);
808 18 : if (rc != 0) {
809 0 : SPDK_ERRLOG("group_impl_close for net failed\n");
810 : }
811 : }
812 :
813 6 : free(*group);
814 6 : *group = NULL;
815 :
816 6 : return 0;
817 : }
818 :
819 : static inline struct spdk_net_impl *
820 19 : sock_get_impl_by_name(const char *impl_name)
821 : {
822 : struct spdk_net_impl *impl;
823 :
824 19 : assert(impl_name != NULL);
825 49 : STAILQ_FOREACH(impl, &g_net_impls, link) {
826 49 : if (0 == strcmp(impl_name, impl->name)) {
827 19 : return impl;
828 : }
829 : }
830 :
831 0 : return NULL;
832 : }
833 :
834 : int
835 16 : spdk_sock_impl_get_opts(const char *impl_name, struct spdk_sock_impl_opts *opts, size_t *len)
836 : {
837 : struct spdk_net_impl *impl;
838 :
839 16 : if (!impl_name || !opts || !len) {
840 4 : errno = EINVAL;
841 4 : return -1;
842 : }
843 :
844 12 : impl = sock_get_impl_by_name(impl_name);
845 12 : if (!impl) {
846 0 : errno = EINVAL;
847 0 : return -1;
848 : }
849 :
850 12 : if (!impl->get_opts) {
851 1 : errno = ENOTSUP;
852 1 : return -1;
853 : }
854 :
855 11 : return impl->get_opts(opts, len);
856 : }
857 :
858 : int
859 6 : spdk_sock_impl_set_opts(const char *impl_name, const struct spdk_sock_impl_opts *opts, size_t len)
860 : {
861 : struct spdk_net_impl *impl;
862 :
863 6 : if (!impl_name || !opts) {
864 2 : errno = EINVAL;
865 2 : return -1;
866 : }
867 :
868 4 : impl = sock_get_impl_by_name(impl_name);
869 4 : if (!impl) {
870 0 : errno = EINVAL;
871 0 : return -1;
872 : }
873 :
874 4 : if (!impl->set_opts) {
875 1 : errno = ENOTSUP;
876 1 : return -1;
877 : }
878 :
879 3 : return impl->set_opts(opts, len);
880 : }
881 :
882 : void
883 0 : spdk_sock_write_config_json(struct spdk_json_write_ctx *w)
884 : {
885 : struct spdk_net_impl *impl;
886 0 : struct spdk_sock_impl_opts opts;
887 0 : size_t len;
888 :
889 0 : assert(w != NULL);
890 :
891 0 : spdk_json_write_array_begin(w);
892 :
893 0 : if (g_default_impl) {
894 0 : spdk_json_write_object_begin(w);
895 0 : spdk_json_write_named_string(w, "method", "sock_set_default_impl");
896 0 : spdk_json_write_named_object_begin(w, "params");
897 0 : spdk_json_write_named_string(w, "impl_name", g_default_impl->name);
898 0 : spdk_json_write_object_end(w);
899 0 : spdk_json_write_object_end(w);
900 : }
901 :
902 0 : STAILQ_FOREACH(impl, &g_net_impls, link) {
903 0 : if (!impl->get_opts) {
904 0 : continue;
905 : }
906 :
907 0 : len = sizeof(opts);
908 0 : if (impl->get_opts(&opts, &len) == 0) {
909 0 : spdk_json_write_object_begin(w);
910 0 : spdk_json_write_named_string(w, "method", "sock_impl_set_options");
911 0 : spdk_json_write_named_object_begin(w, "params");
912 0 : spdk_json_write_named_string(w, "impl_name", impl->name);
913 0 : spdk_json_write_named_uint32(w, "recv_buf_size", opts.recv_buf_size);
914 0 : spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size);
915 0 : spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe);
916 0 : spdk_json_write_named_bool(w, "enable_quickack", opts.enable_quickack);
917 0 : spdk_json_write_named_uint32(w, "enable_placement_id", opts.enable_placement_id);
918 0 : spdk_json_write_named_bool(w, "enable_zerocopy_send_server", opts.enable_zerocopy_send_server);
919 0 : spdk_json_write_named_bool(w, "enable_zerocopy_send_client", opts.enable_zerocopy_send_client);
920 0 : spdk_json_write_named_uint32(w, "zerocopy_threshold", opts.zerocopy_threshold);
921 0 : spdk_json_write_named_uint32(w, "tls_version", opts.tls_version);
922 0 : spdk_json_write_named_bool(w, "enable_ktls", opts.enable_ktls);
923 0 : spdk_json_write_object_end(w);
924 0 : spdk_json_write_object_end(w);
925 : } else {
926 0 : SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name);
927 : }
928 : }
929 :
930 0 : spdk_json_write_array_end(w);
931 0 : }
932 :
933 : void
934 3 : spdk_net_impl_register(struct spdk_net_impl *impl)
935 : {
936 3 : STAILQ_INSERT_HEAD(&g_net_impls, impl, link);
937 3 : }
938 :
939 : int
940 5 : spdk_sock_set_default_impl(const char *impl_name)
941 : {
942 : struct spdk_net_impl *impl;
943 :
944 5 : if (!impl_name) {
945 2 : errno = EINVAL;
946 2 : return -1;
947 : }
948 :
949 3 : impl = sock_get_impl_by_name(impl_name);
950 3 : if (!impl) {
951 0 : errno = EINVAL;
952 0 : return -1;
953 : }
954 :
955 3 : if (impl == g_default_impl) {
956 1 : return 0;
957 : }
958 :
959 2 : if (g_default_impl) {
960 1 : SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name,
961 : impl->name);
962 : } else {
963 1 : SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name);
964 : }
965 :
966 2 : g_default_impl = impl;
967 :
968 2 : return 0;
969 : }
970 :
971 : const char *
972 0 : spdk_sock_get_default_impl(void)
973 : {
974 0 : if (g_default_impl) {
975 0 : return g_default_impl->name;
976 : }
977 :
978 0 : return NULL;
979 : }
980 :
981 : int
982 0 : spdk_sock_group_register_interrupt(struct spdk_sock_group *group, uint32_t events,
983 : spdk_interrupt_fn fn,
984 : void *arg, const char *name)
985 : {
986 0 : struct spdk_sock_group_impl *group_impl = NULL;
987 : int rc;
988 :
989 0 : assert(group != NULL);
990 0 : assert(fn != NULL);
991 :
992 0 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
993 0 : rc = group_impl->net_impl->group_impl_register_interrupt(group_impl, events, fn, arg, name);
994 0 : if (rc != 0) {
995 0 : return rc;
996 : }
997 : }
998 :
999 0 : return 0;
1000 : }
1001 :
1002 : void
1003 0 : spdk_sock_group_unregister_interrupt(struct spdk_sock_group *group)
1004 : {
1005 0 : struct spdk_sock_group_impl *group_impl = NULL;
1006 :
1007 0 : assert(group != NULL);
1008 :
1009 0 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
1010 0 : group_impl->net_impl->group_impl_unregister_interrupt(group_impl);
1011 : }
1012 0 : }
1013 :
1014 1 : SPDK_LOG_REGISTER_COMPONENT(sock)
1015 :
1016 1 : SPDK_TRACE_REGISTER_FN(sock_trace, "sock", TRACE_GROUP_SOCK)
1017 : {
1018 0 : struct spdk_trace_tpoint_opts opts[] = {
1019 : {
1020 : "SOCK_REQ_QUEUE", TRACE_SOCK_REQ_QUEUE,
1021 : OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 1,
1022 : {
1023 : { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1024 : }
1025 : },
1026 : {
1027 : "SOCK_REQ_PEND", TRACE_SOCK_REQ_PEND,
1028 : OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 0,
1029 : {
1030 : { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1031 : }
1032 : },
1033 : {
1034 : "SOCK_REQ_COMPLETE", TRACE_SOCK_REQ_COMPLETE,
1035 : OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 0,
1036 : {
1037 : { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1038 : }
1039 : },
1040 : };
1041 :
1042 0 : spdk_trace_register_owner_type(OWNER_TYPE_SOCK, 's');
1043 0 : spdk_trace_register_object(OBJECT_SOCK_REQ, 's');
1044 0 : spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
1045 0 : }
|