Replace setsockopt() calls with calls to functions that follow setsockopt() with getsockopt() and check that the returned value and its size are the same as have been set. Signed-off-by: Konstantin Shkolnyy <kshk@xxxxxxxxxxxxx> --- tools/testing/vsock/Makefile | 8 +- tools/testing/vsock/control.c | 8 +- tools/testing/vsock/msg_zerocopy_common.c | 8 +- tools/testing/vsock/util_socket.c | 149 ++++++++++++++++++++++ tools/testing/vsock/util_socket.h | 19 +++ tools/testing/vsock/vsock_perf.c | 24 ++-- tools/testing/vsock/vsock_test.c | 40 +++--- 7 files changed, 208 insertions(+), 48 deletions(-) create mode 100644 tools/testing/vsock/util_socket.c create mode 100644 tools/testing/vsock/util_socket.h diff --git a/tools/testing/vsock/Makefile b/tools/testing/vsock/Makefile index 6e0b4e95e230..1ec0b3a67aa4 100644 --- a/tools/testing/vsock/Makefile +++ b/tools/testing/vsock/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only all: test vsock_perf test: vsock_test vsock_diag_test vsock_uring_test -vsock_test: vsock_test.o vsock_test_zerocopy.o timeout.o control.o util.o msg_zerocopy_common.o -vsock_diag_test: vsock_diag_test.o timeout.o control.o util.o -vsock_perf: vsock_perf.o msg_zerocopy_common.o +vsock_test: vsock_test.o vsock_test_zerocopy.o timeout.o control.o util.o msg_zerocopy_common.o util_socket.o +vsock_diag_test: vsock_diag_test.o timeout.o control.o util.o util_socket.o +vsock_perf: vsock_perf.o msg_zerocopy_common.o util_socket.o vsock_uring_test: LDLIBS = -luring -vsock_uring_test: control.o util.o vsock_uring_test.o timeout.o msg_zerocopy_common.o +vsock_uring_test: control.o util.o vsock_uring_test.o timeout.o msg_zerocopy_common.o util_socket.o CFLAGS += -g -O2 -Werror -Wall -I. -I../../include -I../../../usr/include -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE -D_GNU_SOURCE .PHONY: all test clean diff --git a/tools/testing/vsock/control.c b/tools/testing/vsock/control.c index d2deb4b15b94..f1fd809ac9d5 100644 --- a/tools/testing/vsock/control.c +++ b/tools/testing/vsock/control.c @@ -27,6 +27,7 @@ #include "timeout.h" #include "control.h" +#include "util_socket.h" static int control_fd = -1; @@ -50,7 +51,6 @@ void control_init(const char *control_host, for (ai = result; ai; ai = ai->ai_next) { int fd; - int val = 1; fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd < 0) @@ -65,11 +65,9 @@ void control_init(const char *control_host, break; } - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - &val, sizeof(val)) < 0) { - perror("setsockopt"); + if (!setsockopt_int_check(fd, SOL_SOCKET, SO_REUSEADDR, 1, + "setsockopt SO_REUSEADDR")) exit(EXIT_FAILURE); - } if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) goto next; diff --git a/tools/testing/vsock/msg_zerocopy_common.c b/tools/testing/vsock/msg_zerocopy_common.c index 5a4bdf7b5132..4edb1b6974c0 100644 --- a/tools/testing/vsock/msg_zerocopy_common.c +++ b/tools/testing/vsock/msg_zerocopy_common.c @@ -13,15 +13,13 @@ #include <linux/errqueue.h> #include "msg_zerocopy_common.h" +#include "util_socket.h" void enable_so_zerocopy(int fd) { - int val = 1; - - if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) { - perror("setsockopt"); + if (!setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1, + "setsockopt SO_ZEROCOPY")) exit(EXIT_FAILURE); - } } void vsock_recv_completion(int fd, const bool *zerocopied) diff --git a/tools/testing/vsock/util_socket.c b/tools/testing/vsock/util_socket.c new file mode 100644 index 000000000000..e791da160624 --- /dev/null +++ b/tools/testing/vsock/util_socket.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Socket utility functions. + * + * Copyright IBM Corp. 2024 + */ +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include "util_socket.h" + +/* Set "unsigned long long" socket option and check that it's indeed set */ +bool setsockopt_ull_check(int fd, int level, int optname, + unsigned long long val, char const *errmsg) +{ + unsigned long long chkval; + socklen_t chklen; + int err; + + err = setsockopt(fd, level, optname, &val, sizeof(val)); + if (err) { + fprintf(stderr, "setsockopt err: %s (%d)\n", + strerror(errno), errno); + goto fail; + } + + chkval = ~val; /* just make storage != val */ + chklen = sizeof(chkval); + + err = getsockopt(fd, level, optname, &chkval, &chklen); + if (err) { + fprintf(stderr, "getsockopt err: %s (%d)\n", + strerror(errno), errno); + goto fail; + } + + if (chklen != sizeof(chkval)) { + fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val), + chklen); + goto fail; + } + + if (chkval != val) { + fprintf(stderr, "value mismatch: set %llu got %llu\n", val, + chkval); + goto fail; + } + return true; +fail: + fprintf(stderr, "%s val %llu\n", errmsg, val); + return false; +} + +/* Set "int" socket option and check that it's indeed set */ +bool setsockopt_int_check(int fd, int level, int optname, int val, + char const *errmsg) +{ + int chkval; + socklen_t chklen; + int err; + + err = setsockopt(fd, level, optname, &val, sizeof(val)); + if (err) { + fprintf(stderr, "setsockopt err: %s (%d)\n", + strerror(errno), errno); + goto fail; + } + + chkval = ~val; /* just make storage != val */ + chklen = sizeof(chkval); + + err = getsockopt(fd, level, optname, &chkval, &chklen); + if (err) { + fprintf(stderr, "getsockopt err: %s (%d)\n", + strerror(errno), errno); + goto fail; + } + + if (chklen != sizeof(chkval)) { + fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val), + chklen); + goto fail; + } + + if (chkval != val) { + fprintf(stderr, "value mismatch: set %d got %d\n", + val, chkval); + goto fail; + } + return true; +fail: + fprintf(stderr, "%s val %d\n", errmsg, val); + return false; +} + +static void mem_invert(unsigned char *mem, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + mem[i] = ~mem[i]; +} + +/* Set "timeval" socket option and check that it's indeed set */ +bool setsockopt_timeval_check(int fd, int level, int optname, + struct timeval val, char const *errmsg) +{ + struct timeval chkval; + socklen_t chklen; + int err; + + err = setsockopt(fd, level, optname, &val, sizeof(val)); + if (err) { + fprintf(stderr, "setsockopt err: %s (%d)\n", + strerror(errno), errno); + goto fail; + } + + /* just make storage != val */ + chkval = val; + mem_invert((unsigned char *) &chkval, sizeof(chkval)); + chklen = sizeof(chkval); + + err = getsockopt(fd, level, optname, &chkval, &chklen); + if (err) { + fprintf(stderr, "getsockopt err: %s (%d)\n", + strerror(errno), errno); + goto fail; + } + + if (chklen != sizeof(chkval)) { + fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val), + chklen); + goto fail; + } + + if (memcmp(&chkval, &val, sizeof(val)) != 0) { + fprintf(stderr, "value mismatch: set %ld:%ld got %ld:%ld\n", + val.tv_sec, val.tv_usec, + chkval.tv_sec, chkval.tv_usec); + goto fail; + } + return true; +fail: + fprintf(stderr, "%s val %ld:%ld\n", errmsg, val.tv_sec, val.tv_usec); + return false; +} diff --git a/tools/testing/vsock/util_socket.h b/tools/testing/vsock/util_socket.h new file mode 100644 index 000000000000..38cf3decb15c --- /dev/null +++ b/tools/testing/vsock/util_socket.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Socket utility functions. + * + * Copyright IBM Corp. 2024 + */ +#ifndef UTIL_SOCKET_H +#define UTIL_SOCKET_H + +#include <stdbool.h> + +bool setsockopt_ull_check(int fd, int level, int optname, + unsigned long long val, char const *errmsg); +bool setsockopt_int_check(int fd, int level, int optname, int val, + char const *errmsg); +bool setsockopt_timeval_check(int fd, int level, int optname, + struct timeval val, char const *errmsg); + +#endif /* UTIL_SOCKET_H */ diff --git a/tools/testing/vsock/vsock_perf.c b/tools/testing/vsock/vsock_perf.c index 8e0a6c0770d3..b117e043b87b 100644 --- a/tools/testing/vsock/vsock_perf.c +++ b/tools/testing/vsock/vsock_perf.c @@ -21,6 +21,7 @@ #include <sys/mman.h> #include "msg_zerocopy_common.h" +#include "util_socket.h" #define DEFAULT_BUF_SIZE_BYTES (128 * 1024) #define DEFAULT_TO_SEND_BYTES (64 * 1024) @@ -88,13 +89,16 @@ static unsigned long memparse(const char *ptr) static void vsock_increase_buf_size(int fd) { - if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, - &vsock_buf_bytes, sizeof(vsock_buf_bytes))) - error("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); + if (!setsockopt_ull_check(fd, AF_VSOCK, + SO_VM_SOCKETS_BUFFER_MAX_SIZE, vsock_buf_bytes, + "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)")) + exit(EXIT_FAILURE); + + if (!setsockopt_ull_check(fd, AF_VSOCK, + SO_VM_SOCKETS_BUFFER_SIZE, vsock_buf_bytes, + "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)")) + exit(EXIT_FAILURE); - if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, - &vsock_buf_bytes, sizeof(vsock_buf_bytes))) - error("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); } static int vsock_connect(unsigned int cid, unsigned int port) @@ -183,10 +187,10 @@ static void run_receiver(int rcvlowat_bytes) vsock_increase_buf_size(client_fd); - if (setsockopt(client_fd, SOL_SOCKET, SO_RCVLOWAT, - &rcvlowat_bytes, - sizeof(rcvlowat_bytes))) - error("setsockopt(SO_RCVLOWAT)"); + + if (!setsockopt_int_check(client_fd, SOL_SOCKET, SO_RCVLOWAT, + rcvlowat_bytes, "setsockopt(SO_RCVLOWAT)")) + exit(EXIT_FAILURE); data = malloc(buf_size_bytes); diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index c7af23332e57..3764dca1118e 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -27,6 +27,7 @@ #include "timeout.h" #include "control.h" #include "util.h" +#include "util_socket.h" static void test_stream_connection_reset(const struct test_opts *opts) { @@ -444,17 +445,14 @@ static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) sock_buf_size = SOCK_BUF_SIZE; - if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, - &sock_buf_size, sizeof(sock_buf_size))) { - perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); + if (!setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)")) exit(EXIT_FAILURE); - } - if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, - &sock_buf_size, sizeof(sock_buf_size))) { - perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); + if (!setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, + sock_buf_size, "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)")) exit(EXIT_FAILURE); - } /* Ready to receive data. */ control_writeln("SRVREADY"); @@ -586,10 +584,9 @@ static void test_seqpacket_timeout_client(const struct test_opts *opts) tv.tv_sec = RCVTIMEO_TIMEOUT_SEC; tv.tv_usec = 0; - if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) { - perror("setsockopt(SO_RCVTIMEO)"); + if (!setsockopt_timeval_check(fd, SOL_SOCKET, SO_RCVTIMEO, tv, + "setsockopt(SO_RCVTIMEO)")) exit(EXIT_FAILURE); - } read_enter_ns = current_nsec(); @@ -855,9 +852,8 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) exit(EXIT_FAILURE); } - if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, - &lowat_val, sizeof(lowat_val))) { - perror("setsockopt(SO_RCVLOWAT)"); + if (!setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT, + lowat_val, "setsockopt(SO_RCVLOWAT)")) { exit(EXIT_FAILURE); } @@ -1383,11 +1379,9 @@ static void test_stream_credit_update_test(const struct test_opts *opts, /* size_t can be < unsigned long long */ sock_buf_size = buf_size; - if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, - &sock_buf_size, sizeof(sock_buf_size))) { - perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); + if (!setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, + sock_buf_size, "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)")) exit(EXIT_FAILURE); - } if (low_rx_bytes_test) { /* Set new SO_RCVLOWAT here. This enables sending credit @@ -1396,9 +1390,8 @@ static void test_stream_credit_update_test(const struct test_opts *opts, */ recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE; - if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, - &recv_buf_size, sizeof(recv_buf_size))) { - perror("setsockopt(SO_RCVLOWAT)"); + if (!setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT, + recv_buf_size, "setsockopt(SO_RCVLOWAT)")) { exit(EXIT_FAILURE); } } @@ -1442,9 +1435,8 @@ static void test_stream_credit_update_test(const struct test_opts *opts, recv_buf_size++; /* Updating SO_RCVLOWAT will send credit update. */ - if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, - &recv_buf_size, sizeof(recv_buf_size))) { - perror("setsockopt(SO_RCVLOWAT)"); + if (!setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT, + recv_buf_size, "setsockopt(SO_RCVLOWAT)")) { exit(EXIT_FAILURE); } } -- 2.34.1