Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

test/vsock: io_uring rx/tx tests

This adds set of tests which use io_uring for rx/tx. This test suite is
implemented as separated util like 'vsock_test' and has the same set of
input arguments as 'vsock_test'. These tests only cover cases of data
transmission (no connect/bind/accept etc).

Signed-off-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Arseniy Krasnov and committed by
David S. Miller
8d211285 e846d679

+348 -2
+1
tools/testing/vsock/.gitignore
··· 3 3 vsock_test 4 4 vsock_diag_test 5 5 vsock_perf 6 + vsock_uring_test
+5 -2
tools/testing/vsock/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 all: test vsock_perf 3 - test: vsock_test vsock_diag_test 3 + test: vsock_test vsock_diag_test vsock_uring_test 4 4 vsock_test: vsock_test.o vsock_test_zerocopy.o timeout.o control.o util.o msg_zerocopy_common.o 5 5 vsock_diag_test: vsock_diag_test.o timeout.o control.o util.o 6 6 vsock_perf: vsock_perf.o msg_zerocopy_common.o 7 7 8 + vsock_uring_test: LDLIBS = -luring 9 + vsock_uring_test: control.o util.o vsock_uring_test.o timeout.o msg_zerocopy_common.o 10 + 8 11 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 9 12 .PHONY: all test clean 10 13 clean: 11 - ${RM} *.o *.d vsock_test vsock_diag_test vsock_perf 14 + ${RM} *.o *.d vsock_test vsock_diag_test vsock_perf vsock_uring_test 12 15 -include *.d
+342
tools/testing/vsock/vsock_uring_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* io_uring tests for vsock 3 + * 4 + * Copyright (C) 2023 SberDevices. 5 + * 6 + * Author: Arseniy Krasnov <avkrasnov@salutedevices.com> 7 + */ 8 + 9 + #include <getopt.h> 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + #include <liburing.h> 14 + #include <unistd.h> 15 + #include <sys/mman.h> 16 + #include <linux/kernel.h> 17 + #include <error.h> 18 + 19 + #include "util.h" 20 + #include "control.h" 21 + #include "msg_zerocopy_common.h" 22 + 23 + #ifndef PAGE_SIZE 24 + #define PAGE_SIZE 4096 25 + #endif 26 + 27 + #define RING_ENTRIES_NUM 4 28 + 29 + #define VSOCK_TEST_DATA_MAX_IOV 3 30 + 31 + struct vsock_io_uring_test { 32 + /* Number of valid elements in 'vecs'. */ 33 + int vecs_cnt; 34 + struct iovec vecs[VSOCK_TEST_DATA_MAX_IOV]; 35 + }; 36 + 37 + static struct vsock_io_uring_test test_data_array[] = { 38 + /* All elements have page aligned base and size. */ 39 + { 40 + .vecs_cnt = 3, 41 + { 42 + { NULL, PAGE_SIZE }, 43 + { NULL, 2 * PAGE_SIZE }, 44 + { NULL, 3 * PAGE_SIZE }, 45 + } 46 + }, 47 + /* Middle element has both non-page aligned base and size. */ 48 + { 49 + .vecs_cnt = 3, 50 + { 51 + { NULL, PAGE_SIZE }, 52 + { (void *)1, 200 }, 53 + { NULL, 3 * PAGE_SIZE }, 54 + } 55 + } 56 + }; 57 + 58 + static void vsock_io_uring_client(const struct test_opts *opts, 59 + const struct vsock_io_uring_test *test_data, 60 + bool msg_zerocopy) 61 + { 62 + struct io_uring_sqe *sqe; 63 + struct io_uring_cqe *cqe; 64 + struct io_uring ring; 65 + struct iovec *iovec; 66 + struct msghdr msg; 67 + int fd; 68 + 69 + fd = vsock_stream_connect(opts->peer_cid, 1234); 70 + if (fd < 0) { 71 + perror("connect"); 72 + exit(EXIT_FAILURE); 73 + } 74 + 75 + if (msg_zerocopy) 76 + enable_so_zerocopy(fd); 77 + 78 + iovec = alloc_test_iovec(test_data->vecs, test_data->vecs_cnt); 79 + 80 + if (io_uring_queue_init(RING_ENTRIES_NUM, &ring, 0)) 81 + error(1, errno, "io_uring_queue_init"); 82 + 83 + if (io_uring_register_buffers(&ring, iovec, test_data->vecs_cnt)) 84 + error(1, errno, "io_uring_register_buffers"); 85 + 86 + memset(&msg, 0, sizeof(msg)); 87 + msg.msg_iov = iovec; 88 + msg.msg_iovlen = test_data->vecs_cnt; 89 + sqe = io_uring_get_sqe(&ring); 90 + 91 + if (msg_zerocopy) 92 + io_uring_prep_sendmsg_zc(sqe, fd, &msg, 0); 93 + else 94 + io_uring_prep_sendmsg(sqe, fd, &msg, 0); 95 + 96 + if (io_uring_submit(&ring) != 1) 97 + error(1, errno, "io_uring_submit"); 98 + 99 + if (io_uring_wait_cqe(&ring, &cqe)) 100 + error(1, errno, "io_uring_wait_cqe"); 101 + 102 + io_uring_cqe_seen(&ring, cqe); 103 + 104 + control_writeulong(iovec_hash_djb2(iovec, test_data->vecs_cnt)); 105 + 106 + control_writeln("DONE"); 107 + io_uring_queue_exit(&ring); 108 + free_test_iovec(test_data->vecs, iovec, test_data->vecs_cnt); 109 + close(fd); 110 + } 111 + 112 + static void vsock_io_uring_server(const struct test_opts *opts, 113 + const struct vsock_io_uring_test *test_data) 114 + { 115 + unsigned long remote_hash; 116 + unsigned long local_hash; 117 + struct io_uring ring; 118 + size_t data_len; 119 + size_t recv_len; 120 + void *data; 121 + int fd; 122 + 123 + fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 124 + if (fd < 0) { 125 + perror("accept"); 126 + exit(EXIT_FAILURE); 127 + } 128 + 129 + data_len = iovec_bytes(test_data->vecs, test_data->vecs_cnt); 130 + 131 + data = malloc(data_len); 132 + if (!data) { 133 + perror("malloc"); 134 + exit(EXIT_FAILURE); 135 + } 136 + 137 + if (io_uring_queue_init(RING_ENTRIES_NUM, &ring, 0)) 138 + error(1, errno, "io_uring_queue_init"); 139 + 140 + recv_len = 0; 141 + 142 + while (recv_len < data_len) { 143 + struct io_uring_sqe *sqe; 144 + struct io_uring_cqe *cqe; 145 + struct iovec iovec; 146 + 147 + sqe = io_uring_get_sqe(&ring); 148 + iovec.iov_base = data + recv_len; 149 + iovec.iov_len = data_len; 150 + 151 + io_uring_prep_readv(sqe, fd, &iovec, 1, 0); 152 + 153 + if (io_uring_submit(&ring) != 1) 154 + error(1, errno, "io_uring_submit"); 155 + 156 + if (io_uring_wait_cqe(&ring, &cqe)) 157 + error(1, errno, "io_uring_wait_cqe"); 158 + 159 + recv_len += cqe->res; 160 + io_uring_cqe_seen(&ring, cqe); 161 + } 162 + 163 + if (recv_len != data_len) { 164 + fprintf(stderr, "expected %zu, got %zu\n", data_len, 165 + recv_len); 166 + exit(EXIT_FAILURE); 167 + } 168 + 169 + local_hash = hash_djb2(data, data_len); 170 + 171 + remote_hash = control_readulong(); 172 + if (remote_hash != local_hash) { 173 + fprintf(stderr, "hash mismatch\n"); 174 + exit(EXIT_FAILURE); 175 + } 176 + 177 + control_expectln("DONE"); 178 + io_uring_queue_exit(&ring); 179 + free(data); 180 + } 181 + 182 + void test_stream_uring_server(const struct test_opts *opts) 183 + { 184 + int i; 185 + 186 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) 187 + vsock_io_uring_server(opts, &test_data_array[i]); 188 + } 189 + 190 + void test_stream_uring_client(const struct test_opts *opts) 191 + { 192 + int i; 193 + 194 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) 195 + vsock_io_uring_client(opts, &test_data_array[i], false); 196 + } 197 + 198 + void test_stream_uring_msg_zc_server(const struct test_opts *opts) 199 + { 200 + int i; 201 + 202 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) 203 + vsock_io_uring_server(opts, &test_data_array[i]); 204 + } 205 + 206 + void test_stream_uring_msg_zc_client(const struct test_opts *opts) 207 + { 208 + int i; 209 + 210 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) 211 + vsock_io_uring_client(opts, &test_data_array[i], true); 212 + } 213 + 214 + static struct test_case test_cases[] = { 215 + { 216 + .name = "SOCK_STREAM io_uring test", 217 + .run_server = test_stream_uring_server, 218 + .run_client = test_stream_uring_client, 219 + }, 220 + { 221 + .name = "SOCK_STREAM io_uring MSG_ZEROCOPY test", 222 + .run_server = test_stream_uring_msg_zc_server, 223 + .run_client = test_stream_uring_msg_zc_client, 224 + }, 225 + {}, 226 + }; 227 + 228 + static const char optstring[] = ""; 229 + static const struct option longopts[] = { 230 + { 231 + .name = "control-host", 232 + .has_arg = required_argument, 233 + .val = 'H', 234 + }, 235 + { 236 + .name = "control-port", 237 + .has_arg = required_argument, 238 + .val = 'P', 239 + }, 240 + { 241 + .name = "mode", 242 + .has_arg = required_argument, 243 + .val = 'm', 244 + }, 245 + { 246 + .name = "peer-cid", 247 + .has_arg = required_argument, 248 + .val = 'p', 249 + }, 250 + { 251 + .name = "help", 252 + .has_arg = no_argument, 253 + .val = '?', 254 + }, 255 + {}, 256 + }; 257 + 258 + static void usage(void) 259 + { 260 + fprintf(stderr, "Usage: vsock_uring_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid>\n" 261 + "\n" 262 + " Server: vsock_uring_test --control-port=1234 --mode=server --peer-cid=3\n" 263 + " Client: vsock_uring_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" 264 + "\n" 265 + "Run transmission tests using io_uring. Usage is the same as\n" 266 + "in ./vsock_test\n" 267 + "\n" 268 + "Options:\n" 269 + " --help This help message\n" 270 + " --control-host <host> Server IP address to connect to\n" 271 + " --control-port <port> Server port to listen on/connect to\n" 272 + " --mode client|server Server or client mode\n" 273 + " --peer-cid <cid> CID of the other side\n" 274 + ); 275 + exit(EXIT_FAILURE); 276 + } 277 + 278 + int main(int argc, char **argv) 279 + { 280 + const char *control_host = NULL; 281 + const char *control_port = NULL; 282 + struct test_opts opts = { 283 + .mode = TEST_MODE_UNSET, 284 + .peer_cid = VMADDR_CID_ANY, 285 + }; 286 + 287 + init_signals(); 288 + 289 + for (;;) { 290 + int opt = getopt_long(argc, argv, optstring, longopts, NULL); 291 + 292 + if (opt == -1) 293 + break; 294 + 295 + switch (opt) { 296 + case 'H': 297 + control_host = optarg; 298 + break; 299 + case 'm': 300 + if (strcmp(optarg, "client") == 0) { 301 + opts.mode = TEST_MODE_CLIENT; 302 + } else if (strcmp(optarg, "server") == 0) { 303 + opts.mode = TEST_MODE_SERVER; 304 + } else { 305 + fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); 306 + return EXIT_FAILURE; 307 + } 308 + break; 309 + case 'p': 310 + opts.peer_cid = parse_cid(optarg); 311 + break; 312 + case 'P': 313 + control_port = optarg; 314 + break; 315 + case '?': 316 + default: 317 + usage(); 318 + } 319 + } 320 + 321 + if (!control_port) 322 + usage(); 323 + if (opts.mode == TEST_MODE_UNSET) 324 + usage(); 325 + if (opts.peer_cid == VMADDR_CID_ANY) 326 + usage(); 327 + 328 + if (!control_host) { 329 + if (opts.mode != TEST_MODE_SERVER) 330 + usage(); 331 + control_host = "0.0.0.0"; 332 + } 333 + 334 + control_init(control_host, control_port, 335 + opts.mode == TEST_MODE_SERVER); 336 + 337 + run_tests(test_cases, &opts); 338 + 339 + control_cleanup(); 340 + 341 + return 0; 342 + }