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