On Wed, Jul 08, 2026 at 12:29:04PM +0200, Stefano Garzarella wrote: > From: Stefano Garzarella <[email protected]> > > Add a test that sends 2 MB of data using randomly sized small packets > (129-512 bytes) over a SOCK_STREAM connection. Packets above > GOOD_COPY_LEN (128) bypass the in-place coalescing in recv_enqueue(), > forcing each one into its own skb. > > Without receive queue collapsing, the per-skb overhead eventually > exceeds buf_alloc and the connection is reset. The test verifies > that all data arrives and that content integrity is preserved. > > Signed-off-by: Stefano Garzarella <[email protected]>
maybe cut down SO_VM_SOCKETS_BUFFER_SIZE? will make it easier to trigger? anyway Acked-by: Michael S. Tsirkin <[email protected]> > --- > tools/testing/vsock/vsock_test.c | 87 ++++++++++++++++++++++++++++++++ > 1 file changed, 87 insertions(+) > > diff --git a/tools/testing/vsock/vsock_test.c > b/tools/testing/vsock/vsock_test.c > index 76be0e4a7f0e..b4ff9f946565 100644 > --- a/tools/testing/vsock/vsock_test.c > +++ b/tools/testing/vsock/vsock_test.c > @@ -2347,6 +2347,88 @@ static void test_stream_tx_credit_bounds_server(const > struct test_opts *opts) > close(fd); > } > > +/* Test that many small packets don't cause a connection reset under pressure > + * and that data integrity is preserved. Packet sizes vary randomly between > + * 129 and 512 bytes, above GOOD_COPY_LEN (128) to bypass in-place coalescing > + * in recv_enqueue, forcing each one into its own skb. Without receive queue > + * collapsing, the per-skb overhead eventually exceeds buf_alloc and the > + * connection is reset. > + */ > +#define COLLAPSE_PKT_MIN 129 > +#define COLLAPSE_PKT_MAX 512 > +#define COLLAPSE_TOTAL (2 * 1024 * 1024) > + > +static void test_stream_collapse_client(const struct test_opts *opts) > +{ > + unsigned char *data; > + unsigned long hash; > + size_t offset = 0; > + int i, fd; > + > + data = malloc(COLLAPSE_TOTAL); > + if (!data) { > + perror("malloc"); > + exit(EXIT_FAILURE); > + } > + > + for (i = 0; i < COLLAPSE_TOTAL; i++) > + data[i] = rand() & 0xff; > + > + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); > + if (fd < 0) { > + perror("connect"); > + exit(EXIT_FAILURE); > + } > + > + while (offset < COLLAPSE_TOTAL) { > + size_t pkt_size = COLLAPSE_PKT_MIN + > + rand() % (COLLAPSE_PKT_MAX - COLLAPSE_PKT_MIN + 1); > + > + pkt_size = min(pkt_size, COLLAPSE_TOTAL - offset); > + > + send_buf(fd, data + offset, pkt_size, 0, pkt_size); > + offset += pkt_size; > + } > + > + hash = hash_djb2(data, COLLAPSE_TOTAL); > + control_writeulong(hash); > + > + free(data); > + close(fd); > +} > + > +static void test_stream_collapse_server(const struct test_opts *opts) > +{ > + unsigned long hash, remote_hash; > + unsigned char *data; > + int fd; > + > + data = malloc(COLLAPSE_TOTAL); > + if (!data) { > + perror("malloc"); > + exit(EXIT_FAILURE); > + } > + > + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); > + if (fd < 0) { > + perror("accept"); > + exit(EXIT_FAILURE); > + } > + > + recv_buf(fd, data, COLLAPSE_TOTAL, 0, COLLAPSE_TOTAL); > + > + hash = hash_djb2(data, COLLAPSE_TOTAL); > + remote_hash = control_readulong(); > + if (hash != remote_hash) { > + fprintf(stderr, "hash mismatch: local %lu remote %lu\n", > + hash, remote_hash); > + exit(EXIT_FAILURE); > + } > + > + free(data); > + close(fd); > +} > + > static struct test_case test_cases[] = { > { > .name = "SOCK_STREAM connection reset", > @@ -2546,6 +2628,11 @@ static struct test_case test_cases[] = { > .run_client = test_stream_msg_peek_client, > .run_server = test_stream_peek_after_recv_server, > }, > + { > + .name = "SOCK_STREAM small packets backpressure", > + .run_client = test_stream_collapse_client, > + .run_server = test_stream_collapse_server, > + }, > {}, > }; > > -- > 2.55.0

