mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Bobby Eshleman <bobbyeshleman@gmail.com>
To: David Carlier <devnexen@gmail.com>
Cc: netdev@vger.kernel.org, sgarzare@redhat.com, davem@davemloft.net,
	edumazet@kernel.org, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org, virtualization@lists.linux.dev,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v2 2/2] vsock/test: cover SO_INQ
Date: Thu, 15 Oct 2026 10:12:37 -0700	[thread overview]
Message-ID: <atEJhetXtwmGngqT@devvm29614.prn0.facebook.com> (raw)
In-Reply-To: <20261015154334.3217358-3-devnexen@gmail.com>

On Thu, Oct 15, 2026 at 04:43:34PM +0100, David Carlier wrote:
> Check the SCM_INQ value after a partial receive, after draining the
> queue and at EOF, that no cmsg is sent while the option is off, that
> accepted sockets inherit it from the listener, and that out of range
> values and SOCK_SEQPACKET are rejected.
> 
> Signed-off-by: David Carlier <devnexen@gmail.com>
> ---
>  tools/testing/vsock/vsock_test.c | 279 +++++++++++++++++++++++++++++++
>  1 file changed, 279 insertions(+)
> 
> diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
> index b4ff9f946565..10b9074fb87f 100644
> --- a/tools/testing/vsock/vsock_test.c
> +++ b/tools/testing/vsock/vsock_test.c
> @@ -2429,6 +2429,271 @@ static void test_stream_collapse_server(const struct test_opts *opts)
>  	close(fd);
>  }
>  
> +#define SO_INQ_BUF_LEN 64
> +#define SO_INQ_CHUNK_LEN 16
> +
> +static int so_inq_set(int fd, int val)
> +{
> +	return setsockopt(fd, SOL_SOCKET, SO_INQ, &val, sizeof(val));
> +}
> +
> +/* Receive @len bytes and return the SCM_INQ value, or -1 if the kernel did
> + * not attach one.
> + */
> +static int so_inq_recv(int fd, size_t len, int expected_ret)
> +{
> +	char control[CMSG_SPACE(sizeof(int))] = { 0 };
> +	unsigned char buf[SO_INQ_BUF_LEN];
> +	struct iovec iov = {
> +		.iov_base = buf,
> +		.iov_len = len,
> +	};
> +	struct msghdr msg = {
> +		.msg_iov = &iov,
> +		.msg_iovlen = 1,
> +		.msg_control = control,
> +		.msg_controllen = sizeof(control),
> +	};
> +	struct cmsghdr *cmsg;
> +	ssize_t ret;
> +	int inq;
> +
> +	ret = recvmsg(fd, &msg, 0);
> +	if (ret < 0) {
> +		perror("recvmsg");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	expect_res(ret, expected_ret, "recvmsg");
> +
> +	if (msg.msg_flags & MSG_CTRUNC) {
> +		fprintf(stderr, "SCM_INQ control message truncated\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> +		if (cmsg->cmsg_level != SOL_SOCKET ||
> +		    cmsg->cmsg_type != SCM_INQ)
> +			continue;
> +
> +		if (cmsg->cmsg_len != CMSG_LEN(sizeof(inq))) {
> +			fprintf(stderr, "unexpected SCM_INQ length %zu\n",
> +				(size_t)cmsg->cmsg_len);
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		memcpy(&inq, CMSG_DATA(cmsg), sizeof(inq));
> +		return inq;
> +	}
> +
> +	return -1;
> +}
> +
> +static void test_stream_so_inq_client(const struct test_opts *opts)
> +{
> +	int fd;
> +
> +	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
> +	if (fd < 0) {
> +		perror("connect");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	control_expectln("SENT");
> +
> +	/* Wait for the whole payload to be queued, so the values below do not
> +	 * depend on how the transport delivers it.
> +	 */
> +	if (!vsock_ioctl_int(fd, SIOCINQ, SO_INQ_BUF_LEN)) {
> +		fprintf(stderr, "Test skipped, SIOCINQ not supported.\n");
> +		goto out;
> +	}
> +
> +	/* No ancillary data unless the option is enabled. */
> +	expect_res(so_inq_recv(fd, SO_INQ_CHUNK_LEN, SO_INQ_CHUNK_LEN), -1,
> +		   "SCM_INQ with SO_INQ disabled");
> +
> +	if (so_inq_set(fd, 1)) {
> +		if (errno != ENOPROTOOPT) {
> +			perror("setsockopt(SO_INQ)");
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		fprintf(stderr, "Test skipped, SO_INQ not supported.\n");
> +		goto out;
> +	}
> +
> +	/* Partial read: the rest of the payload is still queued. */
> +	expect_res(so_inq_recv(fd, SO_INQ_CHUNK_LEN, SO_INQ_CHUNK_LEN),
> +		   SO_INQ_BUF_LEN - 2 * SO_INQ_CHUNK_LEN,
> +		   "SCM_INQ after partial receive");
> +
> +	/* Draining read while the peer stays connected. */
> +	expect_res(so_inq_recv(fd, SO_INQ_BUF_LEN - 2 * SO_INQ_CHUNK_LEN,
> +			       SO_INQ_BUF_LEN - 2 * SO_INQ_CHUNK_LEN), 0,
> +		   "SCM_INQ after draining receive");
> +
> +	control_writeln("DRAINED");
> +	vsock_wait_remote_close(fd);
> +
> +	/* Nothing is queued once the peer is gone, but 1 is reported so the
> +	 * caller keeps reading until it observes EOF, as TCP_INQ does.
> +	 */
> +	expect_res(so_inq_recv(fd, SO_INQ_CHUNK_LEN, 0), 1, "SCM_INQ at EOF");
> +
> +	if (so_inq_set(fd, 0)) {
> +		perror("setsockopt(SO_INQ)");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	expect_res(so_inq_recv(fd, SO_INQ_CHUNK_LEN, 0), -1,
> +		   "SCM_INQ after disabling SO_INQ");
> +
> +	close(fd);
> +	return;
> +
> +out:
> +	control_writeln("DRAINED");
> +	close(fd);
> +}
> +
> +static void test_stream_so_inq_server(const struct test_opts *opts)
> +{
> +	unsigned char buf[SO_INQ_BUF_LEN];
> +	int fd;
> +
> +	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
> +	if (fd < 0) {
> +		perror("accept");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	memset(buf, 'A', sizeof(buf));
> +	send_buf(fd, buf, sizeof(buf), 0, sizeof(buf));
> +	control_writeln("SENT");
> +
> +	/* Keep the connection open until the peer has drained the queue: an
> +	 * early close would turn its last SCM_INQ value into the EOF one.
> +	 */
> +	control_expectln("DRAINED");
> +	close(fd);
> +}
> +
> +static void test_stream_so_inq_inherit_client(const struct test_opts *opts)
> +{
> +	unsigned char buf[SO_INQ_BUF_LEN];
> +	int fd;
> +
> +	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
> +	if (fd < 0) {
> +		perror("connect");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	memset(buf, 'A', sizeof(buf));
> +	send_buf(fd, buf, sizeof(buf), 0, sizeof(buf));
> +	control_writeln("SENT");
> +
> +	control_expectln("DONE");
> +	close(fd);
> +}
> +
> +static void test_stream_so_inq_inherit_server(const struct test_opts *opts)
> +{
> +	bool supported = true;
> +	int listen_fd, fd;
> +
> +	listen_fd = vsock_stream_listen(VMADDR_CID_ANY, opts->peer_port);
> +
> +	/* Enable the option on the listener only. */
> +	if (so_inq_set(listen_fd, 1)) {
> +		if (errno != ENOPROTOOPT) {
> +			perror("setsockopt(SO_INQ)");
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		fprintf(stderr, "Test skipped, SO_INQ not supported.\n");
> +		supported = false;
> +	}
> +
> +	control_writeln("LISTENING");
> +
> +	timeout_begin(TIMEOUT);
> +	do {
> +		fd = accept(listen_fd, NULL, NULL);
> +		timeout_check("accept");
> +	} while (fd < 0 && errno == EINTR);
> +	timeout_end();
> +
> +	if (fd < 0) {
> +		perror("accept");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	close(listen_fd);
> +	control_expectln("SENT");
> +
> +	if (!supported)
> +		goto out;
> +
> +	if (!vsock_ioctl_int(fd, SIOCINQ, SO_INQ_BUF_LEN)) {
> +		fprintf(stderr, "Test skipped, SIOCINQ not supported.\n");
> +		goto out;
> +	}
> +
> +	/* The accepted socket reports SCM_INQ without its own setsockopt(). */
> +	expect_res(so_inq_recv(fd, SO_INQ_CHUNK_LEN, SO_INQ_CHUNK_LEN),
> +		   SO_INQ_BUF_LEN - SO_INQ_CHUNK_LEN,
> +		   "SCM_INQ inherited from the listener");
> +
> +out:
> +	control_writeln("DONE");
> +	close(fd);
> +}
> +
> +static void test_so_inq_validation_client(const struct test_opts *opts)
> +{
> +	int fd;
> +
> +	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
> +	if (fd < 0) {
> +		perror("socket");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	if (so_inq_set(fd, 1)) {
> +		if (errno != ENOPROTOOPT) {
> +			perror("setsockopt(SO_INQ)");
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		fprintf(stderr, "Test skipped, SO_INQ not supported.\n");
> +		close(fd);
> +		return;
> +	}
> +
> +	if (!so_inq_set(fd, 2) || errno != EINVAL) {
> +		fprintf(stderr, "SO_INQ accepted an out of range value\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	close(fd);
> +
> +	/* SCM_INQ counts bytes, which a message based socket cannot report. */
> +	fd = socket(AF_VSOCK, SOCK_SEQPACKET, 0);
> +	if (fd < 0) {
> +		perror("socket");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	if (!so_inq_set(fd, 1) || errno != ENOPROTOOPT) {
> +		fprintf(stderr, "SO_INQ not rejected on SOCK_SEQPACKET\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	close(fd);
> +}
> +
>  static struct test_case test_cases[] = {
>  	{
>  		.name = "SOCK_STREAM connection reset",
> @@ -2633,6 +2898,20 @@ static struct test_case test_cases[] = {
>  		.run_client = test_stream_collapse_client,
>  		.run_server = test_stream_collapse_server,
>  	},
> +	{
> +		.name = "SOCK_STREAM SO_INQ functionality",
> +		.run_client = test_stream_so_inq_client,
> +		.run_server = test_stream_so_inq_server,
> +	},
> +	{
> +		.name = "SOCK_STREAM SO_INQ inherited by accepted socket",
> +		.run_client = test_stream_so_inq_inherit_client,
> +		.run_server = test_stream_so_inq_inherit_server,
> +	},
> +	{
> +		.name = "SO_INQ option validation",
> +		.run_client = test_so_inq_validation_client,
> +	},
>  	{},
>  };
>  
> -- 
> 2.55.0
> 

Acked-by: Bobby Eshleman <bobbyeshleman@meta.com>

  reply	other threads:[~2026-10-15 17:12 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-15 15:43 [PATCH net-next v2 0/2] vsock: SO_INQ for stream sockets David Carlier
2026-10-15 15:43 ` [PATCH net-next v2 1/2] vsock: support SO_INQ on " David Carlier
2026-10-15 17:07   ` Bobby Eshleman
2026-10-16  8:14   ` Stefano Garzarella
2026-10-15 15:43 ` [PATCH net-next v2 2/2] vsock/test: cover SO_INQ David Carlier
2026-10-15 17:12   ` Bobby Eshleman [this message]
2026-10-16  8:15   ` Stefano Garzarella

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=atEJhetXtwmGngqT@devvm29614.prn0.facebook.com \
    --to=bobbyeshleman@gmail.com \
    --cc=davem@davemloft.net \
    --cc=devnexen@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sgarzare@redhat.com \
    --cc=virtualization@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®