diff --git a/include/spdk/sock.h b/include/spdk/sock.h index 8d5c6a74a..6b8463520 100644 --- a/include/spdk/sock.h +++ b/include/spdk/sock.h @@ -126,6 +126,17 @@ ssize_t spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len); */ ssize_t spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt); +/** + * Read message from the given socket to the I/O vector array. + * + * \param sock Socket to receive message. + * \param iov I/O vector. + * \param iovcnt Number of I/O vectors in the array. + * + * \return the length of the received message on success, -1 on failure. + */ +ssize_t spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt); + /** * Set the value used to specify the low water mark (in bytes) for this socket. * diff --git a/include/spdk_internal/sock.h b/include/spdk_internal/sock.h index d5542bf33..33ee81371 100644 --- a/include/spdk_internal/sock.h +++ b/include/spdk_internal/sock.h @@ -75,6 +75,7 @@ struct spdk_net_impl { struct spdk_sock *(*accept)(struct spdk_sock *sock); int (*close)(struct spdk_sock *sock); ssize_t (*recv)(struct spdk_sock *sock, void *buf, size_t len); + ssize_t (*readv)(struct spdk_sock *sock, struct iovec *iov, int iovcnt); ssize_t (*writev)(struct spdk_sock *sock, struct iovec *iov, int iovcnt); int (*set_recvlowat)(struct spdk_sock *sock, int nbytes); diff --git a/lib/sock/posix/posix.c b/lib/sock/posix/posix.c index 3da0ff549..f71193343 100644 --- a/lib/sock/posix/posix.c +++ b/lib/sock/posix/posix.c @@ -372,6 +372,14 @@ spdk_posix_sock_recv(struct spdk_sock *_sock, void *buf, size_t len) return recv(sock->fd, buf, len, MSG_DONTWAIT); } +static ssize_t +spdk_posix_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) +{ + struct spdk_posix_sock *sock = __posix_sock(_sock); + + return readv(sock->fd, iov, iovcnt); +} + static ssize_t spdk_posix_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) { @@ -588,6 +596,7 @@ static struct spdk_net_impl g_posix_net_impl = { .accept = spdk_posix_sock_accept, .close = spdk_posix_sock_close, .recv = spdk_posix_sock_recv, + .readv = spdk_posix_sock_readv, .writev = spdk_posix_sock_writev, .set_recvlowat = spdk_posix_sock_set_recvlowat, .set_recvbuf = spdk_posix_sock_set_recvbuf, diff --git a/lib/sock/sock.c b/lib/sock/sock.c index d31aa9b07..8cf7ee6cd 100644 --- a/lib/sock/sock.c +++ b/lib/sock/sock.c @@ -129,6 +129,17 @@ spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len) return sock->net_impl->recv(sock, buf, len); } +ssize_t +spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt) +{ + if (sock == NULL) { + errno = EBADF; + return -1; + } + + return sock->net_impl->readv(sock, iov, iovcnt); +} + ssize_t spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) { @@ -140,7 +151,6 @@ spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) return sock->net_impl->writev(sock, iov, iovcnt); } - int spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes) { diff --git a/lib/sock/vpp/vpp.c b/lib/sock/vpp/vpp.c index c10c5fcb4..43825a642 100644 --- a/lib/sock/vpp/vpp.c +++ b/lib/sock/vpp/vpp.c @@ -385,6 +385,36 @@ spdk_vpp_sock_recv(struct spdk_sock *_sock, void *buf, size_t len) return rc; } +static ssize_t +spdk_vpp_sock_readv(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_read(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; + if (rc < iov[i].iov_len) { + /* Read less than buffer provided, no point to continue. */ + break; + } + } + } + return total; +} + static ssize_t spdk_vpp_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) { @@ -411,7 +441,6 @@ spdk_vpp_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) return total; } - /* * TODO: Check if there are similar parameters to configure in VPP * to three below. @@ -609,6 +638,7 @@ static struct spdk_net_impl g_vpp_net_impl = { .accept = spdk_vpp_sock_accept, .close = spdk_vpp_sock_close, .recv = spdk_vpp_sock_recv, + .readv = spdk_vpp_sock_readv, .writev = spdk_vpp_sock_writev, .set_recvlowat = spdk_vpp_sock_set_recvlowat, .set_recvbuf = spdk_vpp_sock_set_recvbuf, diff --git a/test/unit/lib/sock/sock.c/sock_ut.c b/test/unit/lib/sock/sock.c/sock_ut.c index df520accd..c43ac3045 100644 --- a/test/unit/lib/sock/sock.c/sock_ut.c +++ b/test/unit/lib/sock/sock.c/sock_ut.c @@ -171,6 +171,31 @@ spdk_ut_sock_recv(struct spdk_sock *_sock, void *buf, size_t len) return len; } +static ssize_t +spdk_ut_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) +{ + struct spdk_ut_sock *sock = __ut_sock(_sock); + size_t len; + char tmp[256]; + + /* Test implementation only supports single iov for now. */ + CU_ASSERT(iovcnt == 1); + + len = spdk_min(iov[0].iov_len, sock->bytes_avail); + + if (len == 0) { + errno = EAGAIN; + return -1; + } + + memcpy(iov[0].iov_base, sock->buf, len); + memcpy(tmp, &sock->buf[len], sock->bytes_avail - len); + memcpy(sock->buf, tmp, sock->bytes_avail - len); + sock->bytes_avail -= len; + + return len; +} + static ssize_t spdk_ut_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) { @@ -285,6 +310,7 @@ static struct spdk_net_impl g_ut_net_impl = { .accept = spdk_ut_sock_accept, .close = spdk_ut_sock_close, .recv = spdk_ut_sock_recv, + .readv = spdk_ut_sock_readv, .writev = spdk_ut_sock_writev, .set_recvlowat = spdk_ut_sock_set_recvlowat, .set_recvbuf = spdk_ut_sock_set_recvbuf, @@ -331,6 +357,7 @@ _sock(const char *ip, int port) server_sock = spdk_sock_accept(listen_sock); SPDK_CU_ASSERT_FATAL(server_sock != NULL); + /* Test spdk_sock_recv */ iov.iov_base = test_string; iov.iov_len = 7; bytes_written = spdk_sock_writev(client_sock, &iov, 1); @@ -348,6 +375,30 @@ _sock(const char *ip, int port) CU_ASSERT(strncmp(test_string, buffer, 7) == 0); + /* Test spdk_sock_readv */ + iov.iov_base = test_string; + iov.iov_len = 7; + bytes_written = spdk_sock_writev(client_sock, &iov, 1); + CU_ASSERT(bytes_written == 7); + + usleep(1000); + + iov.iov_base = buffer; + iov.iov_len = 2; + bytes_read = spdk_sock_readv(server_sock, &iov, 1); + CU_ASSERT(bytes_read == 2); + + usleep(1000); + + iov.iov_base = buffer + 2; + iov.iov_len = 5; + bytes_read += spdk_sock_readv(server_sock, &iov, 1); + CU_ASSERT(bytes_read == 7); + + usleep(1000); + + CU_ASSERT(strncmp(test_string, buffer, 7) == 0); + rc = spdk_sock_close(&client_sock); CU_ASSERT(client_sock == NULL); CU_ASSERT(rc == 0);