From patchwork Sun Nov 6 19:51:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arseniy Krasnov X-Patchwork-Id: 13033555 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7DBB2C433FE for ; Sun, 6 Nov 2022 19:52:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230321AbiKFTwb (ORCPT ); Sun, 6 Nov 2022 14:52:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48972 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230085AbiKFTwa (ORCPT ); Sun, 6 Nov 2022 14:52:30 -0500 Received: from mx.sberdevices.ru (mx.sberdevices.ru [45.89.227.171]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0A9E210B5A; Sun, 6 Nov 2022 11:52:28 -0800 (PST) Received: from s-lin-edge02.sberdevices.ru (localhost [127.0.0.1]) by mx.sberdevices.ru (Postfix) with ESMTP id 4F7125FD03; Sun, 6 Nov 2022 22:52:26 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sberdevices.ru; s=mail; t=1667764346; bh=gkvy/9shRw8d/tUYq9QGxng4hQ6wEGNdn6OjSeac5Qk=; h=From:To:Subject:Date:Message-ID:Content-Type:MIME-Version; b=dp9GorC2YJARu3hVnsjnbplvYohV9PDLX509Ma2/E7RgLkFWUHaMUvji3QZDtB4Zc wHSf+cvrPzAAT4MHiEuvXZEk4fl7oEC4b5KixBgmoFjLDbZQWbob+n0po7snI9kjML XQS5y4Ggds9InqLO7VvzP6JsG1c0gAc281tqykdb26JdoleGmIY/fPnp0zHeIC/1mT fa3ECa8yDL1TBUYmcZA5p/V2rsPWJaCaEpQsyGKcpuBvBabAq123pjfLtTSAmAl/G6 13eJPVyCF4L2WexgqdbLLmXRO4TNeU+T7bV6kGHv5CV7ajKmd5J5ctCYkvRWnSgEja IQuuRtTJyIiqQ== Received: from S-MS-EXCH02.sberdevices.ru (S-MS-EXCH02.sberdevices.ru [172.16.1.5]) by mx.sberdevices.ru (Postfix) with ESMTP; Sun, 6 Nov 2022 22:52:25 +0300 (MSK) From: Arseniy Krasnov To: Stefano Garzarella , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , "David S. Miller" , "edumazet@google.com" , Jakub Kicinski , Paolo Abeni , Krasnov Arseniy CC: "linux-kernel@vger.kernel.org" , "kvm@vger.kernel.org" , "virtualization@lists.linux-foundation.org" , "netdev@vger.kernel.org" , kernel Subject: [RFC PATCH v3 10/11] test/vsock: add receive zerocopy tests Thread-Topic: [RFC PATCH v3 10/11] test/vsock: add receive zerocopy tests Thread-Index: AQHY8hk4EUPAFCDBikm4E+sDar4nhA== Date: Sun, 6 Nov 2022 19:51:55 +0000 Message-ID: In-Reply-To: Accept-Language: en-US, ru-RU Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [172.16.1.12] Content-ID: MIME-Version: 1.0 X-KSMG-Rule-ID: 4 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Status: not scanned, disabled by settings X-KSMG-AntiSpam-Interceptor-Info: not scanned X-KSMG-AntiPhishing: not scanned, disabled by settings X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 1.1.2.30, bases: 2022/11/06 18:31:00 #20575158 X-KSMG-AntiVirus-Status: Clean, skipped Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-State: RFC This adds tests for zerocopy feature: one test checks data transmission with simple integrity control. Second test covers 'error' branches in zerocopy logic(to check invalid arguments handling). Signed-off-by: Arseniy Krasnov --- tools/include/uapi/linux/virtio_vsock.h | 15 + tools/include/uapi/linux/vm_sockets.h | 8 + tools/testing/vsock/Makefile | 2 +- tools/testing/vsock/util.c | 27 +- tools/testing/vsock/util.h | 4 + tools/testing/vsock/vsock_test.c | 21 + tools/testing/vsock/vsock_test_zerocopy.c | 530 ++++++++++++++++++++++ tools/testing/vsock/vsock_test_zerocopy.h | 14 + 8 files changed, 617 insertions(+), 4 deletions(-) create mode 100644 tools/include/uapi/linux/virtio_vsock.h create mode 100644 tools/include/uapi/linux/vm_sockets.h create mode 100644 tools/testing/vsock/vsock_test_zerocopy.c create mode 100644 tools/testing/vsock/vsock_test_zerocopy.h diff --git a/tools/include/uapi/linux/virtio_vsock.h b/tools/include/uapi/linux/virtio_vsock.h new file mode 100644 index 000000000000..f393062e0394 --- /dev/null +++ b/tools/include/uapi/linux/virtio_vsock.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _UAPI_LINUX_VIRTIO_VSOCK_H +#define _UAPI_LINUX_VIRTIO_VSOCK_H +#include + +struct virtio_vsock_usr_hdr { + u32 flags; + u32 len; +} __attribute__((packed)); + +struct virtio_vsock_usr_hdr_pref { + u32 poll_value; + u32 hdr_num; +} __attribute__((packed)); +#endif /* _UAPI_LINUX_VIRTIO_VSOCK_H */ diff --git a/tools/include/uapi/linux/vm_sockets.h b/tools/include/uapi/linux/vm_sockets.h new file mode 100644 index 000000000000..cac0bc3a7041 --- /dev/null +++ b/tools/include/uapi/linux/vm_sockets.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _UAPI_LINUX_VM_SOCKETS_H +#define _UAPI_LINUX_VM_SOCKETS_H + +#define SO_VM_SOCKETS_MAP_RX 9 +#define SO_VM_SOCKETS_ZEROCOPY 10 + +#endif /* _UAPI_LINUX_VM_SOCKETS_H */ diff --git a/tools/testing/vsock/Makefile b/tools/testing/vsock/Makefile index f8293c6910c9..7172c21fbd8d 100644 --- a/tools/testing/vsock/Makefile +++ b/tools/testing/vsock/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only all: test test: vsock_test vsock_diag_test -vsock_test: vsock_test.o timeout.o control.o util.o +vsock_test: vsock_test.o vsock_test_zerocopy.o timeout.o control.o util.o vsock_diag_test: vsock_diag_test.o timeout.o control.o util.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 diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 351903836774..7ae5219d0fe8 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -84,7 +84,8 @@ void vsock_wait_remote_close(int fd) } /* Connect to and return the file descriptor. */ -static int vsock_connect(unsigned int cid, unsigned int port, int type) +static int vsock_connect(unsigned int cid, unsigned int port, int type, + int optname, void *optval, socklen_t optlen) { union { struct sockaddr sa; @@ -103,6 +104,13 @@ static int vsock_connect(unsigned int cid, unsigned int port, int type) fd = socket(AF_VSOCK, type, 0); + if (optval) { + if (setsockopt(fd, AF_VSOCK, optname, optval, optlen)) { + close(fd); + return -1; + } + } + timeout_begin(TIMEOUT); do { ret = connect(fd, &addr.sa, sizeof(addr.svm)); @@ -122,12 +130,25 @@ static int vsock_connect(unsigned int cid, unsigned int port, int type) int vsock_stream_connect(unsigned int cid, unsigned int port) { - return vsock_connect(cid, port, SOCK_STREAM); + return vsock_connect(cid, port, SOCK_STREAM, 0, NULL, 0); +} + +int vsock_stream_connect_opt(unsigned int cid, unsigned int port, + int optname, void *optval, socklen_t optlen) +{ + return vsock_connect(cid, port, SOCK_STREAM, optname, optval, optlen); } int vsock_seqpacket_connect(unsigned int cid, unsigned int port) { - return vsock_connect(cid, port, SOCK_SEQPACKET); + return vsock_connect(cid, port, SOCK_SEQPACKET, 0, NULL, 0); +} + +int vsock_seqpacket_connect_opt(unsigned int cid, unsigned int port, + int optname, void *optval, socklen_t optlen) +{ + return vsock_connect(cid, port, SOCK_SEQPACKET, optname, optval, + optlen); } /* Listen on and return the first incoming connection. The remote diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index 988cc69a4642..23f9f0c6853d 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -36,7 +36,11 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); int vsock_stream_connect(unsigned int cid, unsigned int port); +int vsock_stream_connect_opt(unsigned int cid, unsigned int port, + int optname, void *optval, socklen_t optlen); int vsock_seqpacket_connect(unsigned int cid, unsigned int port); +int vsock_seqpacket_connect_opt(unsigned int cid, unsigned int port, + int optname, void *optval, socklen_t optlen); int vsock_stream_accept(unsigned int cid, unsigned int port, struct sockaddr_vm *clientaddrp); int vsock_seqpacket_accept(unsigned int cid, unsigned int port, diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index bb4e8657f1d6..a6ed076e42f4 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -23,6 +23,7 @@ #include "timeout.h" #include "control.h" #include "util.h" +#include "vsock_test_zerocopy.h" static void test_stream_connection_reset(const struct test_opts *opts) { @@ -904,6 +905,26 @@ static struct test_case test_cases[] = { .run_client = test_stream_poll_rcvlowat_client, .run_server = test_stream_poll_rcvlowat_server, }, + { + .name = "SOCK_STREAM zerocopy receive", + .run_client = test_stream_zerocopy_rx_client, + .run_server = test_stream_zerocopy_rx_server, + }, + { + .name = "SOCK_SEQPACKET zerocopy receive", + .run_client = test_seqpacket_zerocopy_rx_client, + .run_server = test_seqpacket_zerocopy_rx_server, + }, + { + .name = "SOCK_STREAM zerocopy receive loop poll", + .run_client = test_stream_zerocopy_rx_client_loop_poll, + .run_server = test_stream_zerocopy_rx_server_loop_poll, + }, + { + .name = "SOCK_STREAM zerocopy invalid", + .run_client = test_stream_zerocopy_rx_inv_client, + .run_server = test_stream_zerocopy_rx_inv_server, + }, {}, }; diff --git a/tools/testing/vsock/vsock_test_zerocopy.c b/tools/testing/vsock/vsock_test_zerocopy.c new file mode 100644 index 000000000000..1876f14c0cec --- /dev/null +++ b/tools/testing/vsock/vsock_test_zerocopy.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * + * + * Copyright (C) 2022 Sberdevices, Inc. + * + * Author: Arseniy Krasnov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "timeout.h" +#include "control.h" +#include "util.h" +#include "vsock_test_zerocopy.h" + +#define PAGE_SIZE 4096 +#define RX_MAPPING_PAGES 3 + +#define TX_BUF_SIZE 40000 +#define TX_SEND_LOOPS 3 + +static void test_connectible_zerocopy_rx_client(const struct test_opts *opts, + bool stream) +{ + unsigned long remote_hash; + unsigned long curr_hash; + unsigned long total_sum; + unsigned long msg_bytes; + unsigned long zc_on; + size_t rx_map_len; + void *rx_va; + int fd; + + zc_on = 1; + + if (stream) + fd = vsock_stream_connect_opt(opts->peer_cid, 1234, + SO_VM_SOCKETS_ZEROCOPY, + (void *)&zc_on, sizeof(zc_on)); + else + fd = vsock_seqpacket_connect_opt(opts->peer_cid, 1234, + SO_VM_SOCKETS_ZEROCOPY, + (void *)&zc_on, sizeof(zc_on)); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + rx_map_len = PAGE_SIZE * RX_MAPPING_PAGES; + + rx_va = mmap(NULL, rx_map_len, PROT_READ, MAP_SHARED, fd, 0); + if (rx_va == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + + total_sum = 0; + msg_bytes = 0; + curr_hash = 0; + + while (1) { + struct pollfd fds = { 0 }; + int leave_loop; + int res; + + fds.fd = fd; + fds.events = POLLIN | POLLERR | POLLHUP | + POLLRDHUP | POLLNVAL; + + res = poll(&fds, 1, -1); + + if (res < 0) { + perror("poll"); + exit(EXIT_FAILURE); + } + + if (fds.revents & POLLERR) { + perror("poll error"); + exit(EXIT_FAILURE); + } + + leave_loop = 0; + + if (fds.revents & POLLIN) { + struct virtio_vsock_usr_hdr_pref *poll_hdr; + struct virtio_vsock_usr_hdr *data_hdr; + unsigned char *data_va; + unsigned char *end_va; + socklen_t len; + int hdr_cnt; + + poll_hdr = (struct virtio_vsock_usr_hdr_pref *)rx_va; + len = sizeof(rx_va); + + if (getsockopt(fd, AF_VSOCK, + SO_VM_SOCKETS_MAP_RX, + &rx_va, &len) < 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + data_hdr = (struct virtio_vsock_usr_hdr *)(poll_hdr + 1); + /* Skip headers page for data. */ + data_va = rx_va + PAGE_SIZE; + end_va = (unsigned char *)(rx_va + rx_map_len); + hdr_cnt = 0; + + while (data_va != end_va) { + int data_len = data_hdr->len; + + if (!data_hdr->len) { + if (fds.revents & (POLLHUP | POLLRDHUP) && + !hdr_cnt) + leave_loop = 1; + + break; + } + + while (data_len > 0) { + int i; + int to_read = (data_len < PAGE_SIZE) ? + data_len : PAGE_SIZE; + + for (i = 0; i < to_read; i++) + total_sum += data_va[i]; + + data_va += PAGE_SIZE; + data_len -= PAGE_SIZE; + } + + if (!stream) { + msg_bytes += data_hdr->len; + + if (data_hdr->flags) { + curr_hash += msg_bytes; + curr_hash = djb2(&curr_hash, + sizeof(curr_hash)); + msg_bytes = 0; + } + } + + data_hdr++; + hdr_cnt++; + } + + if (madvise((void *)rx_va, + rx_map_len, + MADV_DONTNEED)) { + perror("madvise"); + exit(EXIT_FAILURE); + } + + if (leave_loop) + break; + } + } + + curr_hash += total_sum; + curr_hash = djb2(&curr_hash, sizeof(curr_hash)); + + if (munmap(rx_va, rx_map_len)) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + remote_hash = control_readulong(NULL); + + if (curr_hash != remote_hash) { + fprintf(stderr, "sum mismatch %lu != %lu\n", + curr_hash, remote_hash); + exit(EXIT_FAILURE); + } + + close(fd); +} + +void test_seqpacket_zerocopy_rx_client(const struct test_opts *opts) +{ + test_connectible_zerocopy_rx_client(opts, false); +} + +void test_stream_zerocopy_rx_client(const struct test_opts *opts) +{ + test_connectible_zerocopy_rx_client(opts, true); +} + +static void test_connectible_zerocopy_rx_server(const struct test_opts *opts, + bool stream) +{ + size_t max_buf_size = TX_BUF_SIZE; + unsigned long curr_hash; + long total_sum = 0; + int n = TX_SEND_LOOPS; + int fd; + + if (stream) + fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + else + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); + + if (fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + curr_hash = 0; + + while (n) { + unsigned char *data; + size_t send_size; + size_t buf_size; + int i; + + buf_size = 1 + (rand() % max_buf_size); + + data = malloc(buf_size); + + if (!data) { + perror("malloc"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < buf_size; i++) { + data[i] = rand() & 0xff; + total_sum += data[i]; + } + + send_size = write(fd, data, buf_size); + + if (send_size != buf_size) { + perror("write"); + exit(EXIT_FAILURE); + } + + if (!stream) { + curr_hash += send_size; + curr_hash = djb2(&curr_hash, sizeof(curr_hash)); + } + + free(data); + n--; + } + + curr_hash += total_sum; + curr_hash = djb2(&curr_hash, sizeof(curr_hash)); + control_writeulong(curr_hash); + + close(fd); +} + +void test_stream_zerocopy_rx_server(const struct test_opts *opts) +{ + test_connectible_zerocopy_rx_server(opts, true); +} + +void test_seqpacket_zerocopy_rx_server(const struct test_opts *opts) +{ + test_connectible_zerocopy_rx_server(opts, false); +} + +void test_stream_zerocopy_rx_client_loop_poll(const struct test_opts *opts) +{ + unsigned long remote_sum; + unsigned long total_sum; + unsigned long zc_on = 1; + size_t rx_map_len; + u32 poll_value = 0; + void *rx_va; + int fd; + + fd = vsock_stream_connect_opt(opts->peer_cid, 1234, + SO_VM_SOCKETS_ZEROCOPY, + (void *)&zc_on, sizeof(zc_on)); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + rx_map_len = PAGE_SIZE * RX_MAPPING_PAGES; + + rx_va = mmap(NULL, rx_map_len, PROT_READ, MAP_SHARED, fd, 0); + if (rx_va == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + + total_sum = 0; + + while (1) { + volatile struct virtio_vsock_usr_hdr_pref *poll_hdr; + struct virtio_vsock_usr_hdr *data_hdr; + unsigned char *data_va; + unsigned char *end_va; + int leave_loop; + socklen_t len; + int hdr_cnt; + + poll_hdr = (struct virtio_vsock_usr_hdr_pref *)rx_va; + + if (poll_value != ~0) { + do { + poll_value = poll_hdr->poll_value; + } while (!poll_value); + } + + len = sizeof(rx_va); + + if (getsockopt(fd, AF_VSOCK, + SO_VM_SOCKETS_MAP_RX, + &rx_va, &len) < 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + data_va = rx_va + PAGE_SIZE; + end_va = (unsigned char *)(rx_va + rx_map_len); + data_hdr = (struct virtio_vsock_usr_hdr *)(poll_hdr + 1); + hdr_cnt = 0; + leave_loop = 0; + + while (data_va != end_va) { + int data_len = data_hdr->len; + + if (!data_hdr->len) { + /* Zero length in first header and there will + * be no more data, leave processing loop. + */ + if (!hdr_cnt && (poll_value == ~0)) + leave_loop = 1; + + break; + } + + while (data_len > 0) { + int i; + int to_read = (data_len < PAGE_SIZE) ? + data_len : PAGE_SIZE; + + for (i = 0; i < to_read; i++) + total_sum += data_va[i]; + + data_va += PAGE_SIZE; + data_len -= PAGE_SIZE; + } + + data_hdr++; + hdr_cnt++; + } + + if (madvise((void *)rx_va + PAGE_SIZE, + rx_map_len - PAGE_SIZE, + MADV_DONTNEED)) { + perror("madvise"); + exit(EXIT_FAILURE); + } + + if (leave_loop) + break; + } + + if (munmap(rx_va, rx_map_len)) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + remote_sum = control_readulong(NULL); + + if (total_sum != remote_sum) { + fprintf(stderr, "loop sum mismatch %lu != %lu\n", + total_sum, remote_sum); + exit(EXIT_FAILURE); + } + + close(fd); +} + +void test_stream_zerocopy_rx_server_loop_poll(const struct test_opts *opts) +{ + size_t max_buf_size = TX_BUF_SIZE; + unsigned long total_sum; + int n = TX_SEND_LOOPS; + int fd; + + fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + if (fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + total_sum = 0; + + while (n) { + unsigned char *data; + size_t buf_size; + int i; + + buf_size = 1 + (rand() % max_buf_size); + + data = malloc(buf_size); + + if (!data) { + perror("malloc"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < buf_size; i++) { + data[i] = rand() & 0xff; + total_sum += data[i]; + } + + if (write(fd, data, buf_size) != buf_size) { + perror("write"); + exit(EXIT_FAILURE); + } + + free(data); + n--; + } + + control_writeulong(total_sum); + + close(fd); +} + +void test_stream_zerocopy_rx_inv_client(const struct test_opts *opts) +{ + size_t map_size = PAGE_SIZE * 5; + unsigned long zc_on = 1; + socklen_t len; + void *map_va; + int fd; + + /* Try zerocopy with disable option. */ + fd = vsock_stream_connect_opt(opts->peer_cid, 1234, SO_VM_SOCKETS_ZEROCOPY, + (void *)&zc_on, sizeof(zc_on)); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + len = sizeof(map_va); + map_va = 0; + + /* Try zerocopy with invalid mapping address. */ + if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_MAP_RX, + &map_va, &len) == 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + /* Try zerocopy with valid, but not socket mapping. */ + map_va = mmap(NULL, map_size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (map_va == MAP_FAILED) { + perror("anon mmap"); + exit(EXIT_FAILURE); + } + + if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_MAP_RX, + &map_va, &len) == 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + if (munmap(map_va, map_size)) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + /* Try zerocopy with valid, but too small mapping. */ + map_va = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); + if (map_va != MAP_FAILED) { + perror("socket mmap small"); + exit(EXIT_FAILURE); + } + + if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_MAP_RX, + &map_va, &len) == 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + /* Try zerocopy with valid mapping, but not from first byte. */ + map_va = mmap(NULL, map_size, PROT_READ, MAP_SHARED, fd, 0); + if (map_va == MAP_FAILED) { + perror("socket mmap"); + exit(EXIT_FAILURE); + } + + map_va += PAGE_SIZE; + + if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_MAP_RX, + &map_va, &len) == 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + if (munmap(map_va - PAGE_SIZE, map_size)) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + control_writeln("DONE"); + + close(fd); +} + +void test_stream_zerocopy_rx_inv_server(const struct test_opts *opts) +{ + int fd; + + fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); + + if (fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + control_expectln("DONE"); + + close(fd); +} + diff --git a/tools/testing/vsock/vsock_test_zerocopy.h b/tools/testing/vsock/vsock_test_zerocopy.h new file mode 100644 index 000000000000..a818bd65b376 --- /dev/null +++ b/tools/testing/vsock/vsock_test_zerocopy.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef VSOCK_TEST_ZEROCOPY_H +#define VSOCK_TEST_ZEROCOPY_H + +void test_stream_zerocopy_rx_client(const struct test_opts *opts); +void test_stream_zerocopy_rx_server(const struct test_opts *opts); +void test_seqpacket_zerocopy_rx_client(const struct test_opts *opts); +void test_seqpacket_zerocopy_rx_server(const struct test_opts *opts); +void test_stream_zerocopy_rx_client_loop_poll(const struct test_opts *opts); +void test_stream_zerocopy_rx_server_loop_poll(const struct test_opts *opts); +void test_stream_zerocopy_rx_inv_client(const struct test_opts *opts); +void test_stream_zerocopy_rx_inv_server(const struct test_opts *opts); + +#endif /* VSOCK_TEST_ZEROCOPY_H */