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 0 : spdk_sock_get_impl_name(struct spdk_sock *sock)
237 : {
238 0 : return sock->net_impl->name;
239 : }
240 :
241 : void
242 40 : spdk_sock_get_default_opts(struct spdk_sock_opts *opts)
243 : {
244 40 : assert(opts);
245 :
246 40 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) {
247 38 : opts->priority = SPDK_SOCK_DEFAULT_PRIORITY;
248 : }
249 :
250 40 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) {
251 38 : opts->zcopy = SPDK_SOCK_DEFAULT_ZCOPY;
252 : }
253 :
254 40 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, ack_timeout)) {
255 38 : opts->ack_timeout = SPDK_SOCK_DEFAULT_ACK_TIMEOUT;
256 : }
257 :
258 40 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
259 38 : opts->impl_opts = NULL;
260 : }
261 :
262 40 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts_size)) {
263 38 : opts->impl_opts_size = 0;
264 : }
265 40 : }
266 :
267 : /*
268 : * opts The opts allocated in the current library.
269 : * opts_user The opts passed by the caller.
270 : * */
271 : static void
272 18 : sock_init_opts(struct spdk_sock_opts *opts, struct spdk_sock_opts *opts_user)
273 : {
274 18 : assert(opts);
275 18 : assert(opts_user);
276 :
277 18 : opts->opts_size = sizeof(*opts);
278 18 : spdk_sock_get_default_opts(opts);
279 :
280 : /* reset the size according to the user */
281 18 : opts->opts_size = opts_user->opts_size;
282 18 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) {
283 18 : opts->priority = opts_user->priority;
284 : }
285 :
286 18 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) {
287 18 : opts->zcopy = opts_user->zcopy;
288 : }
289 :
290 18 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, ack_timeout)) {
291 18 : opts->ack_timeout = opts_user->ack_timeout;
292 : }
293 :
294 18 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
295 18 : opts->impl_opts = opts_user->impl_opts;
296 : }
297 :
298 18 : if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
299 18 : opts->impl_opts_size = opts_user->impl_opts_size;
300 : }
301 18 : }
302 :
303 : struct spdk_sock *
304 8 : spdk_sock_connect(const char *ip, int port, const char *impl_name)
305 : {
306 8 : struct spdk_sock_opts opts;
307 :
308 8 : opts.opts_size = sizeof(opts);
309 8 : spdk_sock_get_default_opts(&opts);
310 8 : return spdk_sock_connect_ext(ip, port, impl_name, &opts);
311 : }
312 :
313 : struct spdk_sock *
314 10 : spdk_sock_connect_ext(const char *ip, int port, const char *_impl_name, struct spdk_sock_opts *opts)
315 : {
316 10 : struct spdk_net_impl *impl = NULL;
317 : struct spdk_sock *sock;
318 10 : struct spdk_sock_opts opts_local;
319 10 : const char *impl_name = NULL;
320 :
321 10 : if (opts == NULL) {
322 0 : SPDK_ERRLOG("the opts should not be NULL pointer\n");
323 0 : return NULL;
324 : }
325 :
326 10 : if (_impl_name) {
327 10 : impl_name = _impl_name;
328 0 : } else if (g_default_impl) {
329 0 : impl_name = g_default_impl->name;
330 : }
331 :
332 26 : STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
333 26 : if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
334 16 : continue;
335 : }
336 :
337 10 : SPDK_DEBUGLOG(sock, "Creating a client socket using impl %s\n", impl->name);
338 10 : sock_init_opts(&opts_local, opts);
339 10 : sock = impl->connect(ip, port, &opts_local);
340 10 : if (sock != NULL) {
341 : /* Copy the contents, both the two structures are the same ABI version */
342 10 : memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
343 : /* Clear out impl_opts to make sure we don't keep reference to a dangling
344 : * pointer */
345 10 : sock->opts.impl_opts = NULL;
346 10 : sock->net_impl = impl;
347 10 : TAILQ_INIT(&sock->queued_reqs);
348 10 : TAILQ_INIT(&sock->pending_reqs);
349 :
350 10 : return sock;
351 : }
352 : }
353 :
354 0 : return NULL;
355 : }
356 :
357 : struct spdk_sock *
358 6 : spdk_sock_listen(const char *ip, int port, const char *impl_name)
359 : {
360 6 : struct spdk_sock_opts opts;
361 :
362 6 : opts.opts_size = sizeof(opts);
363 6 : spdk_sock_get_default_opts(&opts);
364 6 : return spdk_sock_listen_ext(ip, port, impl_name, &opts);
365 : }
366 :
367 : struct spdk_sock *
368 8 : spdk_sock_listen_ext(const char *ip, int port, const char *_impl_name, struct spdk_sock_opts *opts)
369 : {
370 8 : struct spdk_net_impl *impl = NULL;
371 : struct spdk_sock *sock;
372 8 : struct spdk_sock_opts opts_local;
373 8 : const char *impl_name = NULL;
374 :
375 8 : if (opts == NULL) {
376 0 : SPDK_ERRLOG("the opts should not be NULL pointer\n");
377 0 : return NULL;
378 : }
379 :
380 8 : if (_impl_name) {
381 8 : impl_name = _impl_name;
382 0 : } else if (g_default_impl) {
383 0 : impl_name = g_default_impl->name;
384 : }
385 :
386 20 : STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
387 20 : if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
388 12 : continue;
389 : }
390 :
391 8 : SPDK_DEBUGLOG(sock, "Creating a listening socket using impl %s\n", impl->name);
392 8 : sock_init_opts(&opts_local, opts);
393 8 : sock = impl->listen(ip, port, &opts_local);
394 8 : if (sock != NULL) {
395 : /* Copy the contents, both the two structures are the same ABI version */
396 8 : memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
397 : /* Clear out impl_opts to make sure we don't keep reference to a dangling
398 : * pointer */
399 8 : sock->opts.impl_opts = NULL;
400 8 : sock->net_impl = impl;
401 : /* Don't need to initialize the request queues for listen
402 : * sockets. */
403 8 : return sock;
404 : }
405 : }
406 :
407 0 : return NULL;
408 : }
409 :
410 : struct spdk_sock *
411 13 : spdk_sock_accept(struct spdk_sock *sock)
412 : {
413 : struct spdk_sock *new_sock;
414 :
415 13 : new_sock = sock->net_impl->accept(sock);
416 13 : if (new_sock != NULL) {
417 : /* Inherit the opts from the "accept sock" */
418 9 : new_sock->opts = sock->opts;
419 9 : memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts));
420 9 : new_sock->net_impl = sock->net_impl;
421 9 : TAILQ_INIT(&new_sock->queued_reqs);
422 9 : TAILQ_INIT(&new_sock->pending_reqs);
423 : }
424 :
425 13 : return new_sock;
426 : }
427 :
428 : int
429 30 : spdk_sock_close(struct spdk_sock **_sock)
430 : {
431 30 : struct spdk_sock *sock = *_sock;
432 :
433 30 : if (sock == NULL) {
434 0 : errno = EBADF;
435 0 : return -1;
436 : }
437 :
438 30 : if (sock->cb_fn != NULL) {
439 : /* This sock is still part of a sock_group. */
440 2 : errno = EBUSY;
441 2 : return -1;
442 : }
443 :
444 : /* Beyond this point the socket is considered closed. */
445 28 : *_sock = NULL;
446 :
447 28 : sock->flags.closed = true;
448 :
449 28 : if (sock->cb_cnt > 0) {
450 : /* Let the callback unwind before destroying the socket */
451 1 : return 0;
452 : }
453 :
454 27 : spdk_sock_abort_requests(sock);
455 :
456 27 : return sock->net_impl->close(sock);
457 : }
458 :
459 : ssize_t
460 10 : spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len)
461 : {
462 10 : if (sock == NULL || sock->flags.closed) {
463 0 : errno = EBADF;
464 0 : return -1;
465 : }
466 :
467 10 : return sock->net_impl->recv(sock, buf, len);
468 : }
469 :
470 : ssize_t
471 4 : spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
472 : {
473 4 : if (sock == NULL || sock->flags.closed) {
474 0 : errno = EBADF;
475 0 : return -1;
476 : }
477 :
478 4 : return sock->net_impl->readv(sock, iov, iovcnt);
479 : }
480 :
481 : ssize_t
482 10 : spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
483 : {
484 10 : if (sock == NULL || sock->flags.closed) {
485 0 : errno = EBADF;
486 0 : return -1;
487 : }
488 :
489 10 : return sock->net_impl->writev(sock, iov, iovcnt);
490 : }
491 :
492 : void
493 2 : spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req)
494 : {
495 2 : assert(req->cb_fn != NULL);
496 :
497 2 : if (sock == NULL || sock->flags.closed) {
498 0 : req->cb_fn(req->cb_arg, -EBADF);
499 0 : return;
500 : }
501 :
502 2 : sock->net_impl->writev_async(sock, req);
503 : }
504 :
505 : int
506 0 : spdk_sock_recv_next(struct spdk_sock *sock, void **buf, void **ctx)
507 : {
508 0 : if (sock == NULL || sock->flags.closed) {
509 0 : errno = EBADF;
510 0 : return -1;
511 : }
512 :
513 0 : if (sock->group_impl == NULL) {
514 0 : errno = ENOTSUP;
515 0 : return -1;
516 : }
517 :
518 0 : return sock->net_impl->recv_next(sock, buf, ctx);
519 : }
520 :
521 : int
522 2 : spdk_sock_flush(struct spdk_sock *sock)
523 : {
524 2 : if (sock == NULL || sock->flags.closed) {
525 1 : errno = EBADF;
526 1 : return -1;
527 : }
528 :
529 1 : return sock->net_impl->flush(sock);
530 : }
531 :
532 : int
533 2 : spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
534 : {
535 2 : return sock->net_impl->set_recvlowat(sock, nbytes);
536 : }
537 :
538 : int
539 2 : spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
540 : {
541 2 : return sock->net_impl->set_recvbuf(sock, sz);
542 : }
543 :
544 : int
545 2 : spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
546 : {
547 2 : return sock->net_impl->set_sendbuf(sock, sz);
548 : }
549 :
550 : bool
551 2 : spdk_sock_is_ipv6(struct spdk_sock *sock)
552 : {
553 2 : return sock->net_impl->is_ipv6(sock);
554 : }
555 :
556 : bool
557 2 : spdk_sock_is_ipv4(struct spdk_sock *sock)
558 : {
559 2 : return sock->net_impl->is_ipv4(sock);
560 : }
561 :
562 : bool
563 6 : spdk_sock_is_connected(struct spdk_sock *sock)
564 : {
565 6 : return sock->net_impl->is_connected(sock);
566 : }
567 :
568 : struct spdk_sock_group *
569 6 : spdk_sock_group_create(void *ctx)
570 : {
571 6 : struct spdk_net_impl *impl = NULL;
572 : struct spdk_sock_group *group;
573 : struct spdk_sock_group_impl *group_impl;
574 :
575 6 : group = calloc(1, sizeof(*group));
576 6 : if (group == NULL) {
577 0 : return NULL;
578 : }
579 :
580 6 : STAILQ_INIT(&group->group_impls);
581 6 : STAILQ_INIT(&group->pool);
582 :
583 24 : STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
584 18 : group_impl = impl->group_impl_create();
585 18 : if (group_impl != NULL) {
586 18 : STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
587 18 : TAILQ_INIT(&group_impl->socks);
588 18 : group_impl->net_impl = impl;
589 18 : group_impl->group = group;
590 : }
591 : }
592 :
593 6 : group->ctx = ctx;
594 :
595 6 : return group;
596 : }
597 :
598 : void *
599 2 : spdk_sock_group_get_ctx(struct spdk_sock_group *group)
600 : {
601 2 : if (group == NULL) {
602 1 : return NULL;
603 : }
604 :
605 1 : return group->ctx;
606 : }
607 :
608 : int
609 10 : spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
610 : spdk_sock_cb cb_fn, void *cb_arg)
611 : {
612 10 : struct spdk_sock_group_impl *group_impl = NULL;
613 : int rc;
614 :
615 10 : if (cb_fn == NULL) {
616 2 : errno = EINVAL;
617 2 : return -1;
618 : }
619 :
620 8 : if (sock->group_impl != NULL) {
621 : /*
622 : * This sock is already part of a sock_group.
623 : */
624 2 : errno = EINVAL;
625 2 : return -1;
626 : }
627 :
628 6 : group_impl = sock_get_group_impl_from_group(sock, group);
629 6 : if (group_impl == NULL) {
630 0 : errno = EINVAL;
631 0 : return -1;
632 : }
633 :
634 6 : rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
635 6 : if (rc != 0) {
636 0 : return rc;
637 : }
638 :
639 6 : TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
640 6 : sock->group_impl = group_impl;
641 6 : sock->cb_fn = cb_fn;
642 6 : sock->cb_arg = cb_arg;
643 :
644 6 : return 0;
645 : }
646 :
647 : int
648 6 : spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
649 : {
650 6 : struct spdk_sock_group_impl *group_impl = NULL;
651 : int rc;
652 :
653 6 : group_impl = sock_get_group_impl_from_group(sock, group);
654 6 : if (group_impl == NULL) {
655 0 : errno = EINVAL;
656 0 : return -1;
657 : }
658 :
659 6 : assert(group_impl == sock->group_impl);
660 :
661 6 : rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
662 6 : if (rc == 0) {
663 6 : TAILQ_REMOVE(&group_impl->socks, sock, link);
664 6 : sock->group_impl = NULL;
665 6 : sock->cb_fn = NULL;
666 6 : sock->cb_arg = NULL;
667 : }
668 :
669 6 : return rc;
670 : }
671 :
672 : int
673 0 : spdk_sock_group_provide_buf(struct spdk_sock_group *group, void *buf, size_t len, void *ctx)
674 : {
675 : struct spdk_sock_group_provided_buf *provided;
676 :
677 0 : provided = (struct spdk_sock_group_provided_buf *)buf;
678 :
679 0 : provided->len = len;
680 0 : provided->ctx = ctx;
681 0 : STAILQ_INSERT_HEAD(&group->pool, provided, link);
682 :
683 0 : return 0;
684 : }
685 :
686 : size_t
687 0 : spdk_sock_group_get_buf(struct spdk_sock_group *group, void **buf, void **ctx)
688 : {
689 : struct spdk_sock_group_provided_buf *provided;
690 :
691 0 : provided = STAILQ_FIRST(&group->pool);
692 0 : if (provided == NULL) {
693 0 : *buf = NULL;
694 0 : return 0;
695 : }
696 0 : STAILQ_REMOVE_HEAD(&group->pool, link);
697 :
698 0 : *buf = provided;
699 0 : *ctx = provided->ctx;
700 0 : return provided->len;
701 : }
702 :
703 : int
704 5 : spdk_sock_group_poll(struct spdk_sock_group *group)
705 : {
706 5 : return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
707 : }
708 :
709 : static int
710 27 : sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
711 : struct spdk_sock_group *group,
712 : int max_events)
713 : {
714 27 : struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
715 : int num_events, i;
716 :
717 27 : if (TAILQ_EMPTY(&group_impl->socks)) {
718 18 : return 0;
719 : }
720 :
721 9 : num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
722 9 : if (num_events == -1) {
723 0 : return -1;
724 : }
725 :
726 15 : for (i = 0; i < num_events; i++) {
727 6 : struct spdk_sock *sock = socks[i];
728 6 : assert(sock->cb_fn != NULL);
729 6 : sock->cb_fn(sock->cb_arg, group, sock);
730 : }
731 :
732 9 : return num_events;
733 : }
734 :
735 : int
736 9 : spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
737 : {
738 9 : struct spdk_sock_group_impl *group_impl = NULL;
739 9 : int rc, num_events = 0;
740 :
741 9 : if (max_events < 1) {
742 0 : errno = -EINVAL;
743 0 : return -1;
744 : }
745 :
746 : /*
747 : * Only poll for up to 32 events at a time - if more events are pending,
748 : * the next call to this function will reap them.
749 : */
750 9 : if (max_events > MAX_EVENTS_PER_POLL) {
751 0 : max_events = MAX_EVENTS_PER_POLL;
752 : }
753 :
754 36 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
755 27 : rc = sock_group_impl_poll_count(group_impl, group, max_events);
756 27 : if (rc < 0) {
757 0 : num_events = -1;
758 0 : SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
759 : group_impl->net_impl->name);
760 27 : } else if (num_events >= 0) {
761 27 : num_events += rc;
762 : }
763 : }
764 :
765 9 : return num_events;
766 : }
767 :
768 : int
769 8 : spdk_sock_group_close(struct spdk_sock_group **group)
770 : {
771 8 : struct spdk_sock_group_impl *group_impl = NULL, *tmp;
772 : int rc;
773 :
774 8 : if (*group == NULL) {
775 0 : errno = EBADF;
776 0 : return -1;
777 : }
778 :
779 28 : STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
780 22 : if (!TAILQ_EMPTY(&group_impl->socks)) {
781 2 : errno = EBUSY;
782 2 : return -1;
783 : }
784 : }
785 :
786 24 : STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
787 18 : rc = group_impl->net_impl->group_impl_close(group_impl);
788 18 : if (rc != 0) {
789 0 : SPDK_ERRLOG("group_impl_close for net failed\n");
790 : }
791 : }
792 :
793 6 : free(*group);
794 6 : *group = NULL;
795 :
796 6 : return 0;
797 : }
798 :
799 : static inline struct spdk_net_impl *
800 17 : sock_get_impl_by_name(const char *impl_name)
801 : {
802 : struct spdk_net_impl *impl;
803 :
804 17 : assert(impl_name != NULL);
805 43 : STAILQ_FOREACH(impl, &g_net_impls, link) {
806 43 : if (0 == strcmp(impl_name, impl->name)) {
807 17 : return impl;
808 : }
809 : }
810 :
811 0 : return NULL;
812 : }
813 :
814 : int
815 14 : spdk_sock_impl_get_opts(const char *impl_name, struct spdk_sock_impl_opts *opts, size_t *len)
816 : {
817 : struct spdk_net_impl *impl;
818 :
819 14 : if (!impl_name || !opts || !len) {
820 4 : errno = EINVAL;
821 4 : return -1;
822 : }
823 :
824 10 : impl = sock_get_impl_by_name(impl_name);
825 10 : if (!impl) {
826 0 : errno = EINVAL;
827 0 : return -1;
828 : }
829 :
830 10 : if (!impl->get_opts) {
831 1 : errno = ENOTSUP;
832 1 : return -1;
833 : }
834 :
835 9 : return impl->get_opts(opts, len);
836 : }
837 :
838 : int
839 6 : spdk_sock_impl_set_opts(const char *impl_name, const struct spdk_sock_impl_opts *opts, size_t len)
840 : {
841 : struct spdk_net_impl *impl;
842 :
843 6 : if (!impl_name || !opts) {
844 2 : errno = EINVAL;
845 2 : return -1;
846 : }
847 :
848 4 : impl = sock_get_impl_by_name(impl_name);
849 4 : if (!impl) {
850 0 : errno = EINVAL;
851 0 : return -1;
852 : }
853 :
854 4 : if (!impl->set_opts) {
855 1 : errno = ENOTSUP;
856 1 : return -1;
857 : }
858 :
859 3 : return impl->set_opts(opts, len);
860 : }
861 :
862 : void
863 0 : spdk_sock_write_config_json(struct spdk_json_write_ctx *w)
864 : {
865 : struct spdk_net_impl *impl;
866 0 : struct spdk_sock_impl_opts opts;
867 0 : size_t len;
868 :
869 0 : assert(w != NULL);
870 :
871 0 : spdk_json_write_array_begin(w);
872 :
873 0 : if (g_default_impl) {
874 0 : spdk_json_write_object_begin(w);
875 0 : spdk_json_write_named_string(w, "method", "sock_set_default_impl");
876 0 : spdk_json_write_named_object_begin(w, "params");
877 0 : spdk_json_write_named_string(w, "impl_name", g_default_impl->name);
878 0 : spdk_json_write_object_end(w);
879 0 : spdk_json_write_object_end(w);
880 : }
881 :
882 0 : STAILQ_FOREACH(impl, &g_net_impls, link) {
883 0 : if (!impl->get_opts) {
884 0 : continue;
885 : }
886 :
887 0 : len = sizeof(opts);
888 0 : if (impl->get_opts(&opts, &len) == 0) {
889 0 : spdk_json_write_object_begin(w);
890 0 : spdk_json_write_named_string(w, "method", "sock_impl_set_options");
891 0 : spdk_json_write_named_object_begin(w, "params");
892 0 : spdk_json_write_named_string(w, "impl_name", impl->name);
893 0 : spdk_json_write_named_uint32(w, "recv_buf_size", opts.recv_buf_size);
894 0 : spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size);
895 0 : spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe);
896 0 : spdk_json_write_named_bool(w, "enable_quickack", opts.enable_quickack);
897 0 : spdk_json_write_named_uint32(w, "enable_placement_id", opts.enable_placement_id);
898 0 : spdk_json_write_named_bool(w, "enable_zerocopy_send_server", opts.enable_zerocopy_send_server);
899 0 : spdk_json_write_named_bool(w, "enable_zerocopy_send_client", opts.enable_zerocopy_send_client);
900 0 : spdk_json_write_named_uint32(w, "zerocopy_threshold", opts.zerocopy_threshold);
901 0 : spdk_json_write_named_uint32(w, "tls_version", opts.tls_version);
902 0 : spdk_json_write_named_bool(w, "enable_ktls", opts.enable_ktls);
903 0 : spdk_json_write_object_end(w);
904 0 : spdk_json_write_object_end(w);
905 : } else {
906 0 : SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name);
907 : }
908 : }
909 :
910 0 : spdk_json_write_array_end(w);
911 0 : }
912 :
913 : void
914 3 : spdk_net_impl_register(struct spdk_net_impl *impl)
915 : {
916 3 : STAILQ_INSERT_HEAD(&g_net_impls, impl, link);
917 3 : }
918 :
919 : int
920 5 : spdk_sock_set_default_impl(const char *impl_name)
921 : {
922 : struct spdk_net_impl *impl;
923 :
924 5 : if (!impl_name) {
925 2 : errno = EINVAL;
926 2 : return -1;
927 : }
928 :
929 3 : impl = sock_get_impl_by_name(impl_name);
930 3 : if (!impl) {
931 0 : errno = EINVAL;
932 0 : return -1;
933 : }
934 :
935 3 : if (impl == g_default_impl) {
936 1 : return 0;
937 : }
938 :
939 2 : if (g_default_impl) {
940 1 : SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name,
941 : impl->name);
942 : } else {
943 1 : SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name);
944 : }
945 :
946 2 : g_default_impl = impl;
947 :
948 2 : return 0;
949 : }
950 :
951 : const char *
952 0 : spdk_sock_get_default_impl(void)
953 : {
954 0 : if (g_default_impl) {
955 0 : return g_default_impl->name;
956 : }
957 :
958 0 : return NULL;
959 : }
960 :
961 : int
962 0 : spdk_sock_group_register_interrupt(struct spdk_sock_group *group, uint32_t events,
963 : spdk_interrupt_fn fn,
964 : void *arg, const char *name)
965 : {
966 0 : struct spdk_sock_group_impl *group_impl = NULL;
967 : int rc;
968 :
969 0 : assert(group != NULL);
970 0 : assert(fn != NULL);
971 :
972 0 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
973 0 : rc = group_impl->net_impl->group_impl_register_interrupt(group_impl, events, fn, arg, name);
974 0 : if (rc != 0) {
975 0 : return rc;
976 : }
977 : }
978 :
979 0 : return 0;
980 : }
981 :
982 : void
983 0 : spdk_sock_group_unregister_interrupt(struct spdk_sock_group *group)
984 : {
985 0 : struct spdk_sock_group_impl *group_impl = NULL;
986 :
987 0 : assert(group != NULL);
988 :
989 0 : STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
990 0 : group_impl->net_impl->group_impl_unregister_interrupt(group_impl);
991 : }
992 0 : }
993 :
994 1 : SPDK_LOG_REGISTER_COMPONENT(sock)
995 :
996 1 : SPDK_TRACE_REGISTER_FN(sock_trace, "sock", TRACE_GROUP_SOCK)
997 : {
998 0 : struct spdk_trace_tpoint_opts opts[] = {
999 : {
1000 : "SOCK_REQ_QUEUE", TRACE_SOCK_REQ_QUEUE,
1001 : OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 1,
1002 : {
1003 : { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1004 : }
1005 : },
1006 : {
1007 : "SOCK_REQ_PEND", TRACE_SOCK_REQ_PEND,
1008 : OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 0,
1009 : {
1010 : { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1011 : }
1012 : },
1013 : {
1014 : "SOCK_REQ_COMPLETE", TRACE_SOCK_REQ_COMPLETE,
1015 : OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 0,
1016 : {
1017 : { "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
1018 : }
1019 : },
1020 : };
1021 :
1022 0 : spdk_trace_register_owner_type(OWNER_TYPE_SOCK, 's');
1023 0 : spdk_trace_register_object(OBJECT_SOCK_REQ, 's');
1024 0 : spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
1025 0 : }
|