diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/spdk/lib/sock | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/lib/sock')
-rw-r--r-- | src/spdk/lib/sock/Makefile | 44 | ||||
-rw-r--r-- | src/spdk/lib/sock/net_framework.c | 70 | ||||
-rw-r--r-- | src/spdk/lib/sock/posix/Makefile | 40 | ||||
-rw-r--r-- | src/spdk/lib/sock/posix/posix.c | 604 | ||||
-rw-r--r-- | src/spdk/lib/sock/sock.c | 373 | ||||
-rw-r--r-- | src/spdk/lib/sock/vpp/Makefile | 41 | ||||
-rw-r--r-- | src/spdk/lib/sock/vpp/vpp.c | 663 |
7 files changed, 1835 insertions, 0 deletions
diff --git a/src/spdk/lib/sock/Makefile b/src/spdk/lib/sock/Makefile new file mode 100644 index 00000000..8860556d --- /dev/null +++ b/src/spdk/lib/sock/Makefile @@ -0,0 +1,44 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = sock.c net_framework.c + +LIBNAME = sock + +DIRS-y += posix +DIRS-$(CONFIG_VPP) += vpp + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/sock/net_framework.c b/src/spdk/lib/sock/net_framework.c new file mode 100644 index 00000000..5d5a568f --- /dev/null +++ b/src/spdk/lib/sock/net_framework.c @@ -0,0 +1,70 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/log.h" +#include "spdk/net.h" +#include "spdk/queue.h" + +static STAILQ_HEAD(, spdk_net_framework) g_net_frameworks = + STAILQ_HEAD_INITIALIZER(g_net_frameworks); + +int spdk_net_framework_start(void) +{ + struct spdk_net_framework *net_framework = NULL; + int rc; + + STAILQ_FOREACH_FROM(net_framework, &g_net_frameworks, link) { + rc = net_framework->init(); + if (rc != 0) { + SPDK_ERRLOG("Net framework %s failed to initalize\n", net_framework->name); + return rc; + } + } + + return 0; +} + +void spdk_net_framework_fini(void) +{ + struct spdk_net_framework *net_framework = NULL; + + STAILQ_FOREACH_FROM(net_framework, &g_net_frameworks, link) { + net_framework->fini(); + } +} + +void +spdk_net_framework_register(struct spdk_net_framework *frame) +{ + STAILQ_INSERT_TAIL(&g_net_frameworks, frame, link); +} diff --git a/src/spdk/lib/sock/posix/Makefile b/src/spdk/lib/sock/posix/Makefile new file mode 100644 index 00000000..540694c4 --- /dev/null +++ b/src/spdk/lib/sock/posix/Makefile @@ -0,0 +1,40 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +LIBNAME = sock_posix +C_SRCS = posix.c + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/sock/posix/posix.c b/src/spdk/lib/sock/posix/posix.c new file mode 100644 index 00000000..565d3892 --- /dev/null +++ b/src/spdk/lib/sock/posix/posix.c @@ -0,0 +1,604 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#if defined(__linux__) +#include <sys/epoll.h> +#elif defined(__FreeBSD__) +#include <sys/event.h> +#endif + +#include "spdk/log.h" +#include "spdk/sock.h" +#include "spdk_internal/sock.h" + +#define MAX_TMPBUF 1024 +#define PORTNUMLEN 32 + +struct spdk_posix_sock { + struct spdk_sock base; + int fd; +}; + +struct spdk_posix_sock_group_impl { + struct spdk_sock_group_impl base; + int fd; +}; + +static int +get_addr_str(struct sockaddr *sa, char *host, size_t hlen) +{ + const char *result = NULL; + + if (sa == NULL || host == NULL) { + return -1; + } + + switch (sa->sa_family) { + case AF_INET: + result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), + host, hlen); + break; + case AF_INET6: + result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), + host, hlen); + break; + default: + break; + } + + if (result != NULL) { + return 0; + } else { + return -1; + } +} + +#define __posix_sock(sock) (struct spdk_posix_sock *)sock +#define __posix_group_impl(group) (struct spdk_posix_sock_group_impl *)group + +static int +spdk_posix_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport, + char *caddr, int clen, uint16_t *cport) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + struct sockaddr_storage sa; + socklen_t salen; + int rc; + + assert(sock != NULL); + + memset(&sa, 0, sizeof sa); + salen = sizeof sa; + rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen); + if (rc != 0) { + SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno); + return -1; + } + + switch (sa.ss_family) { + case AF_UNIX: + /* Acceptable connection types that don't have IPs */ + return 0; + case AF_INET: + case AF_INET6: + /* Code below will get IP addresses */ + break; + default: + /* Unsupported socket family */ + return -1; + } + + rc = get_addr_str((struct sockaddr *)&sa, saddr, slen); + if (rc != 0) { + SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno); + return -1; + } + + if (sport) { + if (sa.ss_family == AF_INET) { + *sport = ntohs(((struct sockaddr_in *) &sa)->sin_port); + } else if (sa.ss_family == AF_INET6) { + *sport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port); + } + } + + memset(&sa, 0, sizeof sa); + salen = sizeof sa; + rc = getpeername(sock->fd, (struct sockaddr *) &sa, &salen); + if (rc != 0) { + SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno); + return -1; + } + + rc = get_addr_str((struct sockaddr *)&sa, caddr, clen); + if (rc != 0) { + SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno); + return -1; + } + + if (cport) { + if (sa.ss_family == AF_INET) { + *cport = ntohs(((struct sockaddr_in *) &sa)->sin_port); + } else if (sa.ss_family == AF_INET6) { + *cport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port); + } + } + + return 0; +} + +enum spdk_posix_sock_create_type { + SPDK_SOCK_CREATE_LISTEN, + SPDK_SOCK_CREATE_CONNECT, +}; + +static struct spdk_sock * +spdk_posix_sock_create(const char *ip, int port, enum spdk_posix_sock_create_type type) +{ + struct spdk_posix_sock *sock; + char buf[MAX_TMPBUF]; + char portnum[PORTNUMLEN]; + char *p; + struct addrinfo hints, *res, *res0; + int fd, flag; + int val = 1; + int rc; + + if (ip == NULL) { + return NULL; + } + if (ip[0] == '[') { + snprintf(buf, sizeof(buf), "%s", ip + 1); + p = strchr(buf, ']'); + if (p != NULL) { + *p = '\0'; + } + ip = (const char *) &buf[0]; + } + + snprintf(portnum, sizeof portnum, "%d", port); + memset(&hints, 0, sizeof hints); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + hints.ai_flags |= AI_PASSIVE; + hints.ai_flags |= AI_NUMERICHOST; + rc = getaddrinfo(ip, portnum, &hints, &res0); + if (rc != 0) { + SPDK_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno); + return NULL; + } + + /* try listen */ + fd = -1; + for (res = res0; res != NULL; res = res->ai_next) { +retry: + fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (fd < 0) { + /* error */ + continue; + } + rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val); + if (rc != 0) { + close(fd); + /* error */ + continue; + } + rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val); + if (rc != 0) { + close(fd); + /* error */ + continue; + } + + if (res->ai_family == AF_INET6) { + rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val); + if (rc != 0) { + close(fd); + /* error */ + continue; + } + } + + if (type == SPDK_SOCK_CREATE_LISTEN) { + rc = bind(fd, res->ai_addr, res->ai_addrlen); + if (rc != 0) { + SPDK_ERRLOG("bind() failed, errno = %d\n", errno); + switch (errno) { + case EINTR: + /* interrupted? */ + close(fd); + goto retry; + case EADDRNOTAVAIL: + SPDK_ERRLOG("IP address %s not available. " + "Verify IP address in config file " + "and make sure setup script is " + "run before starting spdk app.\n", ip); + /* FALLTHROUGH */ + default: + /* try next family */ + close(fd); + fd = -1; + continue; + } + } + /* bind OK */ + rc = listen(fd, 512); + if (rc != 0) { + SPDK_ERRLOG("listen() failed, errno = %d\n", errno); + close(fd); + fd = -1; + break; + } + } else if (type == SPDK_SOCK_CREATE_CONNECT) { + rc = connect(fd, res->ai_addr, res->ai_addrlen); + if (rc != 0) { + SPDK_ERRLOG("connect() failed, errno = %d\n", errno); + /* try next family */ + close(fd); + fd = -1; + continue; + } + } + + flag = fcntl(fd, F_GETFL); + if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) { + SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", fd, errno); + close(fd); + fd = -1; + break; + } + break; + } + freeaddrinfo(res0); + + if (fd < 0) { + return NULL; + } + + sock = calloc(1, sizeof(*sock)); + if (sock == NULL) { + SPDK_ERRLOG("sock allocation failed\n"); + close(fd); + return NULL; + } + + sock->fd = fd; + return &sock->base; +} + +static struct spdk_sock * +spdk_posix_sock_listen(const char *ip, int port) +{ + return spdk_posix_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN); +} + +static struct spdk_sock * +spdk_posix_sock_connect(const char *ip, int port) +{ + return spdk_posix_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT); +} + +static struct spdk_sock * +spdk_posix_sock_accept(struct spdk_sock *_sock) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + struct sockaddr_storage sa; + socklen_t salen; + int rc; + struct spdk_posix_sock *new_sock; + int flag; + + memset(&sa, 0, sizeof(sa)); + salen = sizeof(sa); + + assert(sock != NULL); + + rc = accept(sock->fd, (struct sockaddr *)&sa, &salen); + + if (rc == -1) { + return NULL; + } + + flag = fcntl(rc, F_GETFL); + if ((!(flag & O_NONBLOCK)) && (fcntl(rc, F_SETFL, flag | O_NONBLOCK) < 0)) { + SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", rc, errno); + close(rc); + return NULL; + } + + new_sock = calloc(1, sizeof(*sock)); + if (new_sock == NULL) { + SPDK_ERRLOG("sock allocation failed\n"); + close(rc); + return NULL; + } + + new_sock->fd = rc; + return &new_sock->base; +} + +static int +spdk_posix_sock_close(struct spdk_sock *_sock) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + int rc; + + rc = close(sock->fd); + if (rc == 0) { + free(sock); + } + + return rc; +} + +static ssize_t +spdk_posix_sock_recv(struct spdk_sock *_sock, void *buf, size_t len) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + + return recv(sock->fd, buf, len, MSG_DONTWAIT); +} + +static ssize_t +spdk_posix_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + + return writev(sock->fd, iov, iovcnt); +} + +static int +spdk_posix_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + int val; + int rc; + + assert(sock != NULL); + + val = nbytes; + rc = setsockopt(sock->fd, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val); + if (rc != 0) { + return -1; + } + return 0; +} + +static int +spdk_posix_sock_set_recvbuf(struct spdk_sock *_sock, int sz) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + + assert(sock != NULL); + + return setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, + &sz, sizeof(sz)); +} + +static int +spdk_posix_sock_set_sendbuf(struct spdk_sock *_sock, int sz) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + + assert(sock != NULL); + + return setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, + &sz, sizeof(sz)); +} + +static bool +spdk_posix_sock_is_ipv6(struct spdk_sock *_sock) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + struct sockaddr_storage sa; + socklen_t salen; + int rc; + + assert(sock != NULL); + + memset(&sa, 0, sizeof sa); + salen = sizeof sa; + rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen); + if (rc != 0) { + SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno); + return false; + } + + return (sa.ss_family == AF_INET6); +} + +static bool +spdk_posix_sock_is_ipv4(struct spdk_sock *_sock) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + struct sockaddr_storage sa; + socklen_t salen; + int rc; + + assert(sock != NULL); + + memset(&sa, 0, sizeof sa); + salen = sizeof sa; + rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen); + if (rc != 0) { + SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno); + return false; + } + + return (sa.ss_family == AF_INET); +} + +static struct spdk_sock_group_impl * +spdk_posix_sock_group_impl_create(void) +{ + struct spdk_posix_sock_group_impl *group_impl; + int fd; + +#if defined(__linux__) + fd = epoll_create1(0); +#elif defined(__FreeBSD__) + fd = kqueue(); +#endif + if (fd == -1) { + return NULL; + } + + group_impl = calloc(1, sizeof(*group_impl)); + if (group_impl == NULL) { + SPDK_ERRLOG("group_impl allocation failed\n"); + close(fd); + return NULL; + } + + group_impl->fd = fd; + + return &group_impl->base; +} + +static int +spdk_posix_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) +{ + struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group); + struct spdk_posix_sock *sock = __posix_sock(_sock); + int rc; + +#if defined(__linux__) + struct epoll_event event; + + event.events = EPOLLIN; + event.data.ptr = sock; + + rc = epoll_ctl(group->fd, EPOLL_CTL_ADD, sock->fd, &event); +#elif defined(__FreeBSD__) + struct kevent event; + struct timespec ts = {0}; + + EV_SET(&event, sock->fd, EVFILT_READ, EV_ADD, 0, 0, sock); + + rc = kevent(group->fd, &event, 1, NULL, 0, &ts); +#endif + return rc; +} + +static int +spdk_posix_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) +{ + struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group); + struct spdk_posix_sock *sock = __posix_sock(_sock); + int rc; +#if defined(__linux__) + struct epoll_event event; + + /* Event parameter is ignored but some old kernel version still require it. */ + rc = epoll_ctl(group->fd, EPOLL_CTL_DEL, sock->fd, &event); +#elif defined(__FreeBSD__) + struct kevent event; + struct timespec ts = {0}; + + EV_SET(&event, sock->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + + rc = kevent(group->fd, &event, 1, NULL, 0, &ts); + if (rc == 0 && event.flags & EV_ERROR) { + rc = -1; + errno = event.data; + } +#endif + return rc; +} + +static int +spdk_posix_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events, + struct spdk_sock **socks) +{ + struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group); + int num_events, i; + +#if defined(__linux__) + struct epoll_event events[MAX_EVENTS_PER_POLL]; + + num_events = epoll_wait(group->fd, events, max_events, 0); +#elif defined(__FreeBSD__) + struct kevent events[MAX_EVENTS_PER_POLL]; + struct timespec ts = {0}; + + num_events = kevent(group->fd, NULL, 0, events, max_events, &ts); +#endif + + if (num_events == -1) { + return -1; + } + + for (i = 0; i < num_events; i++) { +#if defined(__linux__) + socks[i] = events[i].data.ptr; +#elif defined(__FreeBSD__) + socks[i] = events[i].udata; +#endif + } + + return num_events; +} + +static int +spdk_posix_sock_group_impl_close(struct spdk_sock_group_impl *_group) +{ + struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group); + + return close(group->fd); +} + +static struct spdk_net_impl g_posix_net_impl = { + .name = "posix", + .getaddr = spdk_posix_sock_getaddr, + .connect = spdk_posix_sock_connect, + .listen = spdk_posix_sock_listen, + .accept = spdk_posix_sock_accept, + .close = spdk_posix_sock_close, + .recv = spdk_posix_sock_recv, + .writev = spdk_posix_sock_writev, + .set_recvlowat = spdk_posix_sock_set_recvlowat, + .set_recvbuf = spdk_posix_sock_set_recvbuf, + .set_sendbuf = spdk_posix_sock_set_sendbuf, + .is_ipv6 = spdk_posix_sock_is_ipv6, + .is_ipv4 = spdk_posix_sock_is_ipv4, + .group_impl_create = spdk_posix_sock_group_impl_create, + .group_impl_add_sock = spdk_posix_sock_group_impl_add_sock, + .group_impl_remove_sock = spdk_posix_sock_group_impl_remove_sock, + .group_impl_poll = spdk_posix_sock_group_impl_poll, + .group_impl_close = spdk_posix_sock_group_impl_close, +}; + +SPDK_NET_IMPL_REGISTER(posix, &g_posix_net_impl); diff --git a/src/spdk/lib/sock/sock.c b/src/spdk/lib/sock/sock.c new file mode 100644 index 00000000..d31aa9b0 --- /dev/null +++ b/src/spdk/lib/sock/sock.c @@ -0,0 +1,373 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk/log.h" +#include "spdk/sock.h" +#include "spdk_internal/sock.h" +#include "spdk/queue.h" + +static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls); + +int +spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, + char *caddr, int clen, uint16_t *cport) +{ + return sock->net_impl->getaddr(sock, saddr, slen, sport, caddr, clen, cport); +} + +struct spdk_sock * +spdk_sock_connect(const char *ip, int port) +{ + struct spdk_net_impl *impl = NULL; + struct spdk_sock *sock; + + STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { + sock = impl->connect(ip, port); + if (sock != NULL) { + sock->net_impl = impl; + return sock; + } + } + + return NULL; +} + +struct spdk_sock * +spdk_sock_listen(const char *ip, int port) +{ + struct spdk_net_impl *impl = NULL; + struct spdk_sock *sock; + + STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { + sock = impl->listen(ip, port); + if (sock != NULL) { + sock->net_impl = impl; + return sock; + } + } + + return NULL; +} + +struct spdk_sock * +spdk_sock_accept(struct spdk_sock *sock) +{ + struct spdk_sock *new_sock; + + new_sock = sock->net_impl->accept(sock); + if (new_sock != NULL) { + new_sock->net_impl = sock->net_impl; + } + + return new_sock; +} + +int +spdk_sock_close(struct spdk_sock **sock) +{ + int rc; + + if (*sock == NULL) { + errno = EBADF; + return -1; + } + + if ((*sock)->cb_fn != NULL) { + /* This sock is still part of a sock_group. */ + errno = EBUSY; + return -1; + } + + rc = (*sock)->net_impl->close(*sock); + if (rc == 0) { + *sock = NULL; + } + + return rc; +} + +ssize_t +spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len) +{ + if (sock == NULL) { + errno = EBADF; + return -1; + } + + return sock->net_impl->recv(sock, buf, len); +} + +ssize_t +spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) +{ + if (sock == NULL) { + errno = EBADF; + return -1; + } + + return sock->net_impl->writev(sock, iov, iovcnt); +} + + +int +spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes) +{ + return sock->net_impl->set_recvlowat(sock, nbytes); +} + +int +spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz) +{ + return sock->net_impl->set_recvbuf(sock, sz); +} + +int +spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz) +{ + return sock->net_impl->set_sendbuf(sock, sz); +} + +bool +spdk_sock_is_ipv6(struct spdk_sock *sock) +{ + return sock->net_impl->is_ipv6(sock); +} + +bool +spdk_sock_is_ipv4(struct spdk_sock *sock) +{ + return sock->net_impl->is_ipv4(sock); +} + +struct spdk_sock_group * +spdk_sock_group_create(void) +{ + struct spdk_net_impl *impl = NULL; + struct spdk_sock_group *group; + struct spdk_sock_group_impl *group_impl; + + group = calloc(1, sizeof(*group)); + if (group == NULL) { + return NULL; + } + + STAILQ_INIT(&group->group_impls); + + STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { + group_impl = impl->group_impl_create(); + if (group_impl != NULL) { + STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link); + TAILQ_INIT(&group_impl->socks); + group_impl->net_impl = impl; + } + } + + return group; +} + +int +spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, + spdk_sock_cb cb_fn, void *cb_arg) +{ + struct spdk_sock_group_impl *group_impl = NULL; + int rc; + + if (cb_fn == NULL) { + errno = EINVAL; + return -1; + } + + if (sock->cb_fn != NULL) { + /* + * This sock is already part of a sock_group. Currently we don't + * support this. + */ + errno = EBUSY; + return -1; + } + + STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { + if (sock->net_impl == group_impl->net_impl) { + break; + } + } + + if (group_impl == NULL) { + errno = EINVAL; + return -1; + } + + rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock); + if (rc == 0) { + TAILQ_INSERT_TAIL(&group_impl->socks, sock, link); + sock->cb_fn = cb_fn; + sock->cb_arg = cb_arg; + } + + return rc; +} + +int +spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock) +{ + struct spdk_sock_group_impl *group_impl = NULL; + int rc; + + STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { + if (sock->net_impl == group_impl->net_impl) { + break; + } + } + + if (group_impl == NULL) { + errno = EINVAL; + return -1; + } + + rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock); + if (rc == 0) { + TAILQ_REMOVE(&group_impl->socks, sock, link); + sock->cb_fn = NULL; + sock->cb_arg = NULL; + } + + return rc; +} + +int +spdk_sock_group_poll(struct spdk_sock_group *group) +{ + return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL); +} + +static int +spdk_sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl, + struct spdk_sock_group *group, + int max_events) +{ + struct spdk_sock *socks[MAX_EVENTS_PER_POLL]; + int num_events, i; + + if (TAILQ_EMPTY(&group_impl->socks)) { + return 0; + } + + num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks); + if (num_events == -1) { + return -1; + } + + for (i = 0; i < num_events; i++) { + struct spdk_sock *sock = socks[i]; + + assert(sock->cb_fn != NULL); + sock->cb_fn(sock->cb_arg, group, sock); + } + return 0; +} + +int +spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events) +{ + struct spdk_sock_group_impl *group_impl = NULL; + int rc, final_rc = 0; + + if (max_events < 1) { + errno = -EINVAL; + return -1; + } + + /* + * Only poll for up to 32 events at a time - if more events are pending, + * the next call to this function will reap them. + */ + if (max_events > MAX_EVENTS_PER_POLL) { + max_events = MAX_EVENTS_PER_POLL; + } + + STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { + rc = spdk_sock_group_impl_poll_count(group_impl, group, max_events); + if (rc != 0) { + final_rc = rc; + SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n", + group_impl->net_impl->name); + } + } + + return final_rc; +} + +int +spdk_sock_group_close(struct spdk_sock_group **group) +{ + struct spdk_sock_group_impl *group_impl = NULL, *tmp; + int rc; + + if (*group == NULL) { + errno = EBADF; + return -1; + } + + STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { + if (!TAILQ_EMPTY(&group_impl->socks)) { + errno = EBUSY; + return -1; + } + } + + STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { + rc = group_impl->net_impl->group_impl_close(group_impl); + if (rc != 0) { + SPDK_ERRLOG("group_impl_close for net(%s) failed\n", + group_impl->net_impl->name); + } + free(group_impl); + } + + free(*group); + *group = NULL; + + return 0; +} + +void +spdk_net_impl_register(struct spdk_net_impl *impl) +{ + if (!strcmp("posix", impl->name)) { + STAILQ_INSERT_TAIL(&g_net_impls, impl, link); + } else { + STAILQ_INSERT_HEAD(&g_net_impls, impl, link); + } +} diff --git a/src/spdk/lib/sock/vpp/Makefile b/src/spdk/lib/sock/vpp/Makefile new file mode 100644 index 00000000..614fd2e3 --- /dev/null +++ b/src/spdk/lib/sock/vpp/Makefile @@ -0,0 +1,41 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS += vpp.c + +LIBNAME = sock_vpp + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/sock/vpp/vpp.c b/src/spdk/lib/sock/vpp/vpp.c new file mode 100644 index 00000000..752250eb --- /dev/null +++ b/src/spdk/lib/sock/vpp/vpp.c @@ -0,0 +1,663 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk/log.h" +#include "spdk/sock.h" +#include "spdk/net.h" +#include "spdk/string.h" +#include "spdk_internal/sock.h" +#include <vcl/vppcom.h> + +#define MAX_TMPBUF 1024 +#define PORTNUMLEN 32 + +static bool g_vpp_initialized = false; + +struct spdk_vpp_sock { + struct spdk_sock base; + int fd; +}; + +struct spdk_vpp_sock_group_impl { + struct spdk_sock_group_impl base; + int fd; +}; + +static int +get_addr_str(struct sockaddr *sa, char *host, size_t hlen) +{ + const char *result = NULL; + + if (sa == NULL || host == NULL) { + return -1; + } + + if (sa->sa_family == AF_INET) { + result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), + host, hlen); + } else { + result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), + host, hlen); + } + + if (result == NULL) { + return -1; + } + + return 0; +} + +#define __vpp_sock(sock) (struct spdk_vpp_sock *)sock +#define __vpp_group_impl(group) (struct spdk_vpp_sock_group_impl *)group + +static inline void +vcom_socket_copy_ep_to_sockaddr(struct sockaddr *addr, socklen_t *len, vppcom_endpt_t *ep) +{ + int sa_len, copy_len; + + assert(ep->vrf == VPPCOM_VRF_DEFAULT); + + if (ep->is_ip4 == VPPCOM_IS_IP4) { + addr->sa_family = AF_INET; + ((struct sockaddr_in *) addr)->sin_port = ep->port; + if (*len > sizeof(struct sockaddr_in)) { + *len = sizeof(struct sockaddr_in); + } + sa_len = sizeof(struct sockaddr_in) - sizeof(struct in_addr); + copy_len = *len - sa_len; + if (copy_len > 0) { + memcpy(&((struct sockaddr_in *) addr)->sin_addr, ep->ip, copy_len); + } + } else { + addr->sa_family = AF_INET6; + ((struct sockaddr_in6 *) addr)->sin6_port = ep->port; + if (*len > sizeof(struct sockaddr_in6)) { + *len = sizeof(struct sockaddr_in6); + } + sa_len = sizeof(struct sockaddr_in6) - sizeof(struct in6_addr); + copy_len = *len - sa_len; + if (copy_len > 0) { + memcpy(&((struct sockaddr_in6 *) addr)->sin6_addr, ep->ip, copy_len); + } + } +} + +static int +getsockname_vpp(int fd, struct sockaddr *addr, socklen_t *len) +{ + vppcom_endpt_t ep; + uint32_t size = sizeof(ep); + uint8_t addr_buf[sizeof(struct in6_addr)]; + int rc; + + if (!addr || !len) { + return -EFAULT; + } + + ep.ip = addr_buf; + + rc = vppcom_session_attr(fd, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size); + if (rc == VPPCOM_OK) { + vcom_socket_copy_ep_to_sockaddr(addr, len, &ep); + } + + return rc; +} + + +static int +getpeername_vpp(int sock, struct sockaddr *addr, socklen_t *len) +{ + vppcom_endpt_t ep; + uint32_t size = sizeof(ep); + uint8_t addr_buf[sizeof(struct in6_addr)]; + int rc; + + if (!addr || !len) { + return -EFAULT; + } + + ep.ip = addr_buf; + + rc = vppcom_session_attr(sock, VPPCOM_ATTR_GET_PEER_ADDR, &ep, &size); + if (rc == VPPCOM_OK) { + vcom_socket_copy_ep_to_sockaddr(addr, len, &ep); + } + + return rc; +} + +static int +spdk_vpp_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport, + char *caddr, int clen, uint16_t *cport) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + struct sockaddr sa; + socklen_t salen; + int rc; + + assert(sock != NULL); + assert(g_vpp_initialized); + + memset(&sa, 0, sizeof(sa)); + salen = sizeof(sa); + rc = getsockname_vpp(sock->fd, &sa, &salen); + if (rc != 0) { + errno = -rc; + SPDK_ERRLOG("getsockname_vpp() failed (errno=%d)\n", errno); + return -1; + } + + rc = get_addr_str(&sa, saddr, slen); + if (rc != 0) { + /* Errno already set by get_addr_str() */ + SPDK_ERRLOG("get_addr_str() failed (errno=%d)\n", errno); + return -1; + } + + if (sport) { + if (sa.ss_family == AF_INET) { + *sport = ntohs(((struct sockaddr_in *) &sa)->sin_port); + } else if (sa.ss_family == AF_INET6) { + *sport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port); + } + } + + memset(&sa, 0, sizeof(sa)); + salen = sizeof(sa); + rc = getpeername_vpp(sock->fd, &sa, &salen); + if (rc != 0) { + errno = -rc; + SPDK_ERRLOG("getpeername_vpp() failed (errno=%d)\n", errno); + return -1; + } + + rc = get_addr_str(&sa, caddr, clen); + if (rc != 0) { + /* Errno already set by get_addr_str() */ + SPDK_ERRLOG("get_addr_str() failed (errno=%d)\n", errno); + return -1; + } + + if (cport) { + if (sa.ss_family == AF_INET) { + *cport = ntohs(((struct sockaddr_in *) &sa)->sin_port); + } else if (sa.ss_family == AF_INET6) { + *cport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port); + } + } + + return 0; +} + +enum spdk_vpp_create_type { + SPDK_SOCK_CREATE_LISTEN, + SPDK_SOCK_CREATE_CONNECT, +}; + +static struct spdk_sock * +spdk_vpp_sock_create(const char *ip, int port, enum spdk_vpp_create_type type) +{ + struct spdk_vpp_sock *sock; + int fd, rc; + vppcom_endpt_t endpt; + uint8_t addr_buf[sizeof(struct in6_addr)]; + + if (ip == NULL) { + return NULL; + } + + /* Check address family */ + if (inet_pton(AF_INET, ip, &addr_buf)) { + endpt.is_ip4 = VPPCOM_IS_IP4; + } else if (inet_pton(AF_INET6, ip, &addr_buf)) { + endpt.is_ip4 = VPPCOM_IS_IP6; + } else { + SPDK_ERRLOG("IP address with invalid format\n"); + return NULL; + } + endpt.vrf = VPPCOM_VRF_DEFAULT; + endpt.ip = (uint8_t *)&addr_buf; + endpt.port = htons(port); + + fd = vppcom_session_create(VPPCOM_VRF_DEFAULT, VPPCOM_PROTO_TCP, 1 /* is_nonblocking */); + if (fd < 0) { + errno = -fd; + SPDK_ERRLOG("vppcom_session_create() failed, errno = %d\n", errno); + return NULL; + } + + if (type == SPDK_SOCK_CREATE_LISTEN) { + rc = vppcom_session_bind(fd, &endpt); + if (rc != VPPCOM_OK) { + errno = -rc; + SPDK_ERRLOG("vppcom_session_bind() failed, errno = %d\n", errno); + vppcom_session_close(fd); + return NULL; + } + + rc = vppcom_session_listen(fd, 512); + if (rc != VPPCOM_OK) { + errno = -rc; + SPDK_ERRLOG("vppcom_session_listen() failed, errno = %d\n", errno); + vppcom_session_close(fd); + return NULL; + } + } else if (type == SPDK_SOCK_CREATE_CONNECT) { + rc = vppcom_session_connect(fd, &endpt); + if (rc != VPPCOM_OK) { + errno = -rc; + SPDK_ERRLOG("vppcom_session_connect() failed, errno = %d\n", errno); + vppcom_session_close(fd); + return NULL; + } + } + + sock = calloc(1, sizeof(*sock)); + if (sock == NULL) { + errno = -ENOMEM; + SPDK_ERRLOG("sock allocation failed\n"); + vppcom_session_close(fd); + return NULL; + } + + sock->fd = fd; + return &sock->base; +} + +static struct spdk_sock * +spdk_vpp_sock_listen(const char *ip, int port) +{ + if (!g_vpp_initialized) { + return NULL; + } + + return spdk_vpp_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN); +} + +static struct spdk_sock * +spdk_vpp_sock_connect(const char *ip, int port) +{ + if (!g_vpp_initialized) { + return NULL; + } + + return spdk_vpp_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT); +} + +static struct spdk_sock * +spdk_vpp_sock_accept(struct spdk_sock *_sock) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + vppcom_endpt_t endpt; + uint8_t ip[16]; + int rc; + struct spdk_vpp_sock *new_sock; + double wait_time = -1.0; + + endpt.ip = ip; + + assert(sock != NULL); + assert(g_vpp_initialized); + + rc = vppcom_session_accept(sock->fd, &endpt, O_NONBLOCK, wait_time); + if (rc < 0) { + errno = -rc; + return NULL; + } + + new_sock = calloc(1, sizeof(*sock)); + if (new_sock == NULL) { + SPDK_ERRLOG("sock allocation failed\n"); + vppcom_session_close(rc); + return NULL; + } + + new_sock->fd = rc; + return &new_sock->base; +} + +static int +spdk_vpp_sock_close(struct spdk_sock *_sock) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + int rc; + + assert(sock != NULL); + assert(g_vpp_initialized); + + rc = vppcom_session_close(sock->fd); + if (rc != VPPCOM_OK) { + errno = -rc; + return -1; + } + free(sock); + + return 0; +} + +static ssize_t +spdk_vpp_sock_recv(struct spdk_sock *_sock, void *buf, size_t len) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + int rc; + + assert(sock != NULL); + assert(g_vpp_initialized); + + rc = vppcom_session_read(sock->fd, buf, len); + if (rc < 0) { + errno = -rc; + return -1; + } + return rc; +} + +static ssize_t +spdk_vpp_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + ssize_t total = 0; + int i, rc; + + assert(sock != NULL); + assert(g_vpp_initialized); + + for (i = 0; i < iovcnt; ++i) { + rc = vppcom_session_write(sock->fd, iov[i].iov_base, iov[i].iov_len); + if (rc < 0) { + if (total > 0) { + break; + } else { + errno = -rc; + return -1; + } + } else { + total += rc; + } + } + return total; +} + + +/* + * TODO: Check if there are similar parameters to configure in VPP + * to three below. + */ +static int +spdk_vpp_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes) +{ + assert(g_vpp_initialized); + + return 0; +} + +static int +spdk_vpp_sock_set_recvbuf(struct spdk_sock *_sock, int sz) +{ + assert(g_vpp_initialized); + + return 0; +} + +static int +spdk_vpp_sock_set_sendbuf(struct spdk_sock *_sock, int sz) +{ + assert(g_vpp_initialized); + + return 0; +} + +static bool +spdk_vpp_sock_is_ipv6(struct spdk_sock *_sock) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + vppcom_endpt_t ep; + uint32_t size = sizeof(ep); + uint8_t addr_buf[sizeof(struct in6_addr)]; + int rc; + + assert(sock != NULL); + assert(g_vpp_initialized); + + ep.ip = addr_buf; + + rc = vppcom_session_attr(sock->fd, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size); + if (rc != VPPCOM_OK) { + errno = -rc; + return false; + } + + return (ep.is_ip4 == VPPCOM_IS_IP6); +} + +static bool +spdk_vpp_sock_is_ipv4(struct spdk_sock *_sock) +{ + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + vppcom_endpt_t ep; + uint32_t size = sizeof(ep); + uint8_t addr_buf[sizeof(struct in6_addr)]; + int rc; + + assert(sock != NULL); + assert(g_vpp_initialized); + + ep.ip = addr_buf; + + rc = vppcom_session_attr(sock->fd, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size); + if (rc != VPPCOM_OK) { + errno = -rc; + return false; + } + + return (ep.is_ip4 == VPPCOM_IS_IP4); +} + +static struct spdk_sock_group_impl * +spdk_vpp_sock_group_impl_create(void) +{ + struct spdk_vpp_sock_group_impl *group_impl; + int fd; + + if (!g_vpp_initialized) { + return NULL; + } + + group_impl = calloc(1, sizeof(*group_impl)); + if (group_impl == NULL) { + SPDK_ERRLOG("sock_group allocation failed\n"); + return NULL; + } + + fd = vppcom_epoll_create(); + if (fd < 0) { + free(group_impl); + return NULL; + } + + group_impl->fd = fd; + + return &group_impl->base; +} + +static int +spdk_vpp_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) +{ + struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group); + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + int rc; + struct epoll_event event; + + assert(sock != NULL); + assert(group != NULL); + assert(g_vpp_initialized); + + event.events = EPOLLIN; + event.data.ptr = sock; + + rc = vppcom_epoll_ctl(group->fd, EPOLL_CTL_ADD, sock->fd, &event); + if (rc != VPPCOM_OK) { + errno = -rc; + return -1; + } + + return 0; +} + +static int +spdk_vpp_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) +{ + struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group); + struct spdk_vpp_sock *sock = __vpp_sock(_sock); + int rc; + struct epoll_event event; + + assert(sock != NULL); + assert(group != NULL); + assert(g_vpp_initialized); + + rc = vppcom_epoll_ctl(group->fd, EPOLL_CTL_DEL, sock->fd, &event); + if (rc != VPPCOM_OK) { + errno = -rc; + return -1; + } + + return 0; +} + +static int +spdk_vpp_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events, + struct spdk_sock **socks) +{ + struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group); + int num_events, i; + struct epoll_event events[MAX_EVENTS_PER_POLL]; + + assert(group != NULL); + assert(socks != NULL); + assert(g_vpp_initialized); + + num_events = vppcom_epoll_wait(group->fd, events, max_events, 0); + if (num_events < 0) { + errno = -num_events; + return -1; + } + + for (i = 0; i < num_events; i++) { + socks[i] = events[i].data.ptr; + } + + return num_events; +} + +static int +spdk_vpp_sock_group_impl_close(struct spdk_sock_group_impl *_group) +{ + struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group); + int rc; + + assert(group != NULL); + assert(g_vpp_initialized); + + rc = vppcom_session_close(group->fd); + if (rc != VPPCOM_OK) { + errno = -rc; + return -1; + } + + return 0; +} + +static struct spdk_net_impl g_vpp_net_impl = { + .name = "vpp", + .getaddr = spdk_vpp_sock_getaddr, + .connect = spdk_vpp_sock_connect, + .listen = spdk_vpp_sock_listen, + .accept = spdk_vpp_sock_accept, + .close = spdk_vpp_sock_close, + .recv = spdk_vpp_sock_recv, + .writev = spdk_vpp_sock_writev, + .set_recvlowat = spdk_vpp_sock_set_recvlowat, + .set_recvbuf = spdk_vpp_sock_set_recvbuf, + .set_sendbuf = spdk_vpp_sock_set_sendbuf, + .is_ipv6 = spdk_vpp_sock_is_ipv6, + .is_ipv4 = spdk_vpp_sock_is_ipv4, + .group_impl_create = spdk_vpp_sock_group_impl_create, + .group_impl_add_sock = spdk_vpp_sock_group_impl_add_sock, + .group_impl_remove_sock = spdk_vpp_sock_group_impl_remove_sock, + .group_impl_poll = spdk_vpp_sock_group_impl_poll, + .group_impl_close = spdk_vpp_sock_group_impl_close, +}; + +SPDK_NET_IMPL_REGISTER(vpp, &g_vpp_net_impl); + +static int +spdk_vpp_net_framework_init(void) +{ + int rc; + char *app_name; + + app_name = spdk_sprintf_alloc("SPDK_%d", getpid()); + if (app_name == NULL) { + SPDK_ERRLOG("Cannot alloc memory for SPDK app name\n"); + return -ENOMEM; + } + + rc = vppcom_app_create(app_name); + if (rc == 0) { + g_vpp_initialized = true; + } + + free(app_name); + + return 0; +} + +static void +spdk_vpp_net_framework_fini(void) +{ + if (g_vpp_initialized) { + vppcom_app_destroy(); + } +} + +static struct spdk_net_framework g_vpp_net_framework = { + .name = "vpp", + .init = spdk_vpp_net_framework_init, + .fini = spdk_vpp_net_framework_fini, +}; + +SPDK_NET_FRAMEWORK_REGISTER(vpp, &g_vpp_net_framework); |