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