All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
To: Stefan Hajnoczi <stefanha@redhat.com>,
	Stefano Garzarella <sgarzare@redhat.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	Jason Wang <jasowang@redhat.com>,
	"David S. Miller" <davem@davemloft.net>,
	"Jakub Kicinski" <kuba@kernel.org>,
	Paolo Abeni <pabeni@redhat.com>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"kvm@vger.kernel.org" <kvm@vger.kernel.org>,
	"virtualization@lists.linux-foundation.org" 
	<virtualization@lists.linux-foundation.org>,
	"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	kernel <kernel@sberdevices.ru>,
	Krasnov Arseniy <oxffffaa@gmail.com>,
	Arseniy Krasnov <AVKrasnov@sberdevices.ru>
Subject: [RFC PATCH v1 7/8] test/vsock: add receive zerocopy tests
Date: Thu, 12 May 2022 05:20:50 +0000	[thread overview]
Message-ID: <fc1af486-f29a-7a70-d9a1-b767e8ca2185@sberdevices.ru> (raw)
In-Reply-To: <7cdcb1e1-7c97-c054-19cf-5caeacae981d@sberdevices.ru>

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 <AVKrasnov@sberdevices.ru>
---
 tools/include/uapi/linux/virtio_vsock.h |  10 +
 tools/include/uapi/linux/vm_sockets.h   |   7 +
 tools/testing/vsock/control.c           |  34 +++
 tools/testing/vsock/control.h           |   2 +
 tools/testing/vsock/vsock_test.c        | 284 ++++++++++++++++++++++++
 5 files changed, 337 insertions(+)
 create mode 100644 tools/include/uapi/linux/virtio_vsock.h
 create mode 100644 tools/include/uapi/linux/vm_sockets.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..df04e50b3dd7
--- /dev/null
+++ b/tools/include/uapi/linux/virtio_vsock.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _UAPI_LINUX_VIRTIO_VSOCK_H
+#define _UAPI_LINUX_VIRTIO_VSOCK_H
+#include <linux/types.h>
+
+struct virtio_vsock_usr_hdr {
+	u32 flags;
+	u32 len;
+} __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..001aaba03eea
--- /dev/null
+++ b/tools/include/uapi/linux/vm_sockets.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _UAPI_LINUX_VM_SOCKETS_H
+#define _UAPI_LINUX_VM_SOCKETS_H
+
+#define SO_VM_SOCKETS_ZEROCOPY 9
+
+#endif /* _UAPI_LINUX_VM_SOCKETS_H */
diff --git a/tools/testing/vsock/control.c b/tools/testing/vsock/control.c
index 4874872fc5a3..00a654e8f137 100644
--- a/tools/testing/vsock/control.c
+++ b/tools/testing/vsock/control.c
@@ -141,6 +141,40 @@ void control_writeln(const char *str)
 	timeout_end();
 }
 
+void control_writelong(long value)
+{
+	char str[32];
+
+	if (snprintf(str, sizeof(str), "%li", value) >= sizeof(str)) {
+		perror("snprintf");
+		exit(EXIT_FAILURE);
+	}
+
+	control_writeln(str);
+}
+
+long control_readlong(bool *ok)
+{
+	long value = -1;
+	char *str;
+
+	if (ok)
+		*ok = false;
+
+	str = control_readln();
+
+	if (str == NULL)
+		return value;
+
+	value = strtol(str, NULL, 10);
+	free(str);
+
+	if (ok)
+		*ok = true;
+
+	return value;
+}
+
 /* Return the next line from the control socket (without the trailing newline).
  *
  * The program terminates if a timeout occurs.
diff --git a/tools/testing/vsock/control.h b/tools/testing/vsock/control.h
index 51814b4f9ac1..5272ad20e850 100644
--- a/tools/testing/vsock/control.h
+++ b/tools/testing/vsock/control.h
@@ -9,7 +9,9 @@ void control_init(const char *control_host, const char *control_port,
 void control_cleanup(void);
 void control_writeln(const char *str);
 char *control_readln(void);
+long control_readlong(bool *ok);
 void control_expectln(const char *str);
 bool control_cmpln(char *line, const char *str, bool fail);
+void control_writelong(long value);
 
 #endif /* CONTROL_H */
diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
index dc577461afc2..0d887c7d9474 100644
--- a/tools/testing/vsock/vsock_test.c
+++ b/tools/testing/vsock/vsock_test.c
@@ -18,11 +18,16 @@
 #include <sys/socket.h>
 #include <time.h>
 #include <sys/mman.h>
+#include <poll.h>
+#include <uapi/linux/virtio_vsock.h>
+#include <uapi/linux/vm_sockets.h>
 
 #include "timeout.h"
 #include "control.h"
 #include "util.h"
 
+#define PAGE_SIZE 4096
+
 static void test_stream_connection_reset(const struct test_opts *opts)
 {
 	union {
@@ -596,6 +601,274 @@ static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opt
 	close(fd);
 }
 
+static void test_stream_zerocopy_rx_client(const struct test_opts *opts)
+{
+	unsigned long total_sum;
+	size_t rx_map_len;
+	long rec_value;
+	void *rx_va;
+	int fd;
+
+	fd = vsock_stream_connect(opts->peer_cid, 1234);
+	if (fd < 0) {
+		perror("connect");
+		exit(EXIT_FAILURE);
+	}
+
+	rx_map_len = PAGE_SIZE * 3;
+
+	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) {
+		struct pollfd fds = { 0 };
+		int hungup = 0;
+		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);
+		}
+
+		if (fds.revents & POLLIN) {
+			struct virtio_vsock_usr_hdr *hdr;
+			uintptr_t tmp_rx_va = (uintptr_t)rx_va;
+			unsigned char *data_va;
+			unsigned char *end_va;
+			socklen_t len = sizeof(tmp_rx_va);
+
+			if (getsockopt(fd, AF_VSOCK,
+					SO_VM_SOCKETS_ZEROCOPY,
+					&tmp_rx_va, &len) < 0) {
+				perror("getsockopt");
+				exit(EXIT_FAILURE);
+			}
+
+			hdr = (struct virtio_vsock_usr_hdr *)rx_va;
+			/* Skip headers page for data. */
+			data_va = rx_va + PAGE_SIZE;
+			end_va = (unsigned char *)(tmp_rx_va + rx_map_len);
+
+			while (data_va != end_va) {
+				int data_len = hdr->len;
+
+				if (!hdr->len) {
+					if (fds.revents & (POLLHUP | POLLRDHUP)) {
+						if (hdr == rx_va)
+							hungup = 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;
+				}
+
+				hdr++;
+			}
+
+			if (madvise((void *)rx_va, rx_map_len,
+					MADV_DONTNEED)) {
+				perror("madvise");
+				exit(EXIT_FAILURE);
+			}
+
+			if (hungup)
+				break;
+		}
+	}
+
+	if (munmap(rx_va, rx_map_len)) {
+		perror("munmap");
+		exit(EXIT_FAILURE);
+	}
+
+	rec_value = control_readlong(NULL);
+
+	if (total_sum != rec_value) {
+		fprintf(stderr, "sum mismatch %lu != %lu\n",
+				total_sum, rec_value);
+		exit(EXIT_FAILURE);
+	}
+
+	close(fd);
+}
+
+static void test_stream_zerocopy_rx_server(const struct test_opts *opts)
+{
+	size_t max_buf_size = 40000;
+	long total_sum = 0;
+	int n = 10;
+	int fd;
+
+	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+	if (fd < 0) {
+		perror("accept");
+		exit(EXIT_FAILURE);
+	}
+
+	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_writelong(total_sum);
+
+	close(fd);
+}
+
+static void test_stream_zerocopy_rx_inv_client(const struct test_opts *opts)
+{
+	size_t map_size = PAGE_SIZE * 5;
+	socklen_t len;
+	void *map_va;
+	int fd;
+
+	fd = vsock_stream_connect(opts->peer_cid, 1234);
+	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_ZEROCOPY,
+			&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_ZEROCOPY,
+			&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");
+		exit(EXIT_FAILURE);
+	}
+
+	//tmp_rx_va = (uintptr_t)map_va;
+
+	if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_ZEROCOPY,
+			&map_va, &len) == 0) {
+		perror("getsockopt");
+		exit(EXIT_FAILURE);
+	}
+
+	if (munmap(map_va, PAGE_SIZE)) {
+		perror("munmap");
+		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);
+	}
+
+	//tmp_rx_va = (uintptr_t)map_va + PAGE_SIZE;
+	map_va += PAGE_SIZE;
+
+	if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_ZEROCOPY,
+			&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);
+}
+
+static 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);
+}
+
 static struct test_case test_cases[] = {
 	{
 		.name = "SOCK_STREAM connection reset",
@@ -646,6 +919,16 @@ static struct test_case test_cases[] = {
 		.run_client = test_seqpacket_invalid_rec_buffer_client,
 		.run_server = test_seqpacket_invalid_rec_buffer_server,
 	},
+	{
+		.name = "SOCK_STREAM zerocopy receive",
+		.run_client = test_stream_zerocopy_rx_client,
+		.run_server = test_stream_zerocopy_rx_server,
+	},
+	{
+		.name = "SOCK_STREAM zerocopy invalid",
+		.run_client = test_stream_zerocopy_rx_inv_client,
+		.run_server = test_stream_zerocopy_rx_inv_server,
+	},
 	{},
 };
 
@@ -729,6 +1012,7 @@ int main(int argc, char **argv)
 		.peer_cid = VMADDR_CID_ANY,
 	};
 
+	srand(time(NULL));
 	init_signals();
 
 	for (;;) {
-- 
2.25.1

  parent reply	other threads:[~2022-05-12  5:21 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-12  5:04 [RFC PATCH v1 0/8] virtio/vsock: experimental zerocopy receive Arseniy Krasnov
2022-05-12  5:06 ` [RFC PATCH v1 1/8] virtio/vsock: rework packet allocation logic Arseniy Krasnov
2022-05-12  5:09 ` [RFC PATCH v1 2/8] vhost/vsock: " Arseniy Krasnov
2022-05-12  5:12 ` [RFC PATCH v1 3/8] af_vsock: add zerocopy receive logic Arseniy Krasnov
2022-05-12  5:14 ` [RFC PATCH v1 4/8] virtio/vsock: add transport zerocopy callback Arseniy Krasnov
2022-05-12  5:17 ` [RFC PATCH v1 5/8] vhost/vsock: enable " Arseniy Krasnov
2022-05-12  5:18 ` [RFC PATCH v1 6/8] virtio/vsock: " Arseniy Krasnov
2022-05-12  5:20 ` Arseniy Krasnov [this message]
2022-05-12  5:22 ` [RFC PATCH v1 8/8] test/vsock: vsock rx zerocopy utility Arseniy Krasnov
2022-05-17 15:14 ` [RFC PATCH v1 0/8] virtio/vsock: experimental zerocopy receive Stefano Garzarella
2022-05-17 15:14   ` Stefano Garzarella
2022-05-18 11:04   ` Arseniy Krasnov
2022-05-19  7:42     ` Stefano Garzarella
2022-05-19  7:42       ` Stefano Garzarella
2022-05-20 11:09       ` Arseniy Krasnov
2022-05-24  7:32         ` Stefano Garzarella
2022-05-24  7:32           ` Stefano Garzarella
2022-06-07 10:26           ` Arseniy Krasnov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fc1af486-f29a-7a70-d9a1-b767e8ca2185@sberdevices.ru \
    --to=avkrasnov@sberdevices.ru \
    --cc=davem@davemloft.net \
    --cc=jasowang@redhat.com \
    --cc=kernel@sberdevices.ru \
    --cc=kuba@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=oxffffaa@gmail.com \
    --cc=pabeni@redhat.com \
    --cc=sgarzare@redhat.com \
    --cc=stefanha@redhat.com \
    --cc=virtualization@lists.linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.