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

test/vsock: MSG_ZEROCOPY flag tests

This adds three tests for MSG_ZEROCOPY feature:
1) SOCK_STREAM tx with different buffers.
2) SOCK_SEQPACKET tx with different buffers.
3) SOCK_STREAM test to read empty error queue of the socket.

Patch also works as preparation for the next patches for tools in this
patchset: vsock_perf and vsock_uring_test:
1) Adds several new functions to util.c - they will be also used by
vsock_uring_test.
2) Adds two new functions for MSG_ZEROCOPY handling to a new source
file - such source will be shared between vsock_test, vsock_perf and
vsock_uring_test, thus avoiding code copy-pasting.

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
bc36442e bac2cac1

+633 -1
+1 -1
tools/testing/vsock/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 all: test vsock_perf 3 3 test: vsock_test vsock_diag_test 4 - vsock_test: vsock_test.o timeout.o control.o util.o 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 7 7
+87
tools/testing/vsock/msg_zerocopy_common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Some common code for MSG_ZEROCOPY logic 3 + * 4 + * Copyright (C) 2023 SberDevices. 5 + * 6 + * Author: Arseniy Krasnov <avkrasnov@salutedevices.com> 7 + */ 8 + 9 + #include <stdio.h> 10 + #include <stdlib.h> 11 + #include <sys/types.h> 12 + #include <sys/socket.h> 13 + #include <linux/errqueue.h> 14 + 15 + #include "msg_zerocopy_common.h" 16 + 17 + void enable_so_zerocopy(int fd) 18 + { 19 + int val = 1; 20 + 21 + if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) { 22 + perror("setsockopt"); 23 + exit(EXIT_FAILURE); 24 + } 25 + } 26 + 27 + void vsock_recv_completion(int fd, const bool *zerocopied) 28 + { 29 + struct sock_extended_err *serr; 30 + struct msghdr msg = { 0 }; 31 + char cmsg_data[128]; 32 + struct cmsghdr *cm; 33 + ssize_t res; 34 + 35 + msg.msg_control = cmsg_data; 36 + msg.msg_controllen = sizeof(cmsg_data); 37 + 38 + res = recvmsg(fd, &msg, MSG_ERRQUEUE); 39 + if (res) { 40 + fprintf(stderr, "failed to read error queue: %zi\n", res); 41 + exit(EXIT_FAILURE); 42 + } 43 + 44 + cm = CMSG_FIRSTHDR(&msg); 45 + if (!cm) { 46 + fprintf(stderr, "cmsg: no cmsg\n"); 47 + exit(EXIT_FAILURE); 48 + } 49 + 50 + if (cm->cmsg_level != SOL_VSOCK) { 51 + fprintf(stderr, "cmsg: unexpected 'cmsg_level'\n"); 52 + exit(EXIT_FAILURE); 53 + } 54 + 55 + if (cm->cmsg_type != VSOCK_RECVERR) { 56 + fprintf(stderr, "cmsg: unexpected 'cmsg_type'\n"); 57 + exit(EXIT_FAILURE); 58 + } 59 + 60 + serr = (void *)CMSG_DATA(cm); 61 + if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) { 62 + fprintf(stderr, "serr: wrong origin: %u\n", serr->ee_origin); 63 + exit(EXIT_FAILURE); 64 + } 65 + 66 + if (serr->ee_errno) { 67 + fprintf(stderr, "serr: wrong error code: %u\n", serr->ee_errno); 68 + exit(EXIT_FAILURE); 69 + } 70 + 71 + /* This flag is used for tests, to check that transmission was 72 + * performed as expected: zerocopy or fallback to copy. If NULL 73 + * - don't care. 74 + */ 75 + if (!zerocopied) 76 + return; 77 + 78 + if (*zerocopied && (serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED)) { 79 + fprintf(stderr, "serr: was copy instead of zerocopy\n"); 80 + exit(EXIT_FAILURE); 81 + } 82 + 83 + if (!*zerocopied && !(serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED)) { 84 + fprintf(stderr, "serr: was zerocopy instead of copy\n"); 85 + exit(EXIT_FAILURE); 86 + } 87 + }
+18
tools/testing/vsock/msg_zerocopy_common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef MSG_ZEROCOPY_COMMON_H 3 + #define MSG_ZEROCOPY_COMMON_H 4 + 5 + #include <stdbool.h> 6 + 7 + #ifndef SOL_VSOCK 8 + #define SOL_VSOCK 287 9 + #endif 10 + 11 + #ifndef VSOCK_RECVERR 12 + #define VSOCK_RECVERR 1 13 + #endif 14 + 15 + void enable_so_zerocopy(int fd); 16 + void vsock_recv_completion(int fd, const bool *zerocopied); 17 + 18 + #endif /* MSG_ZEROCOPY_COMMON_H */
+133
tools/testing/vsock/util.c
··· 11 11 #include <stdio.h> 12 12 #include <stdint.h> 13 13 #include <stdlib.h> 14 + #include <string.h> 14 15 #include <signal.h> 15 16 #include <unistd.h> 16 17 #include <assert.h> 17 18 #include <sys/epoll.h> 19 + #include <sys/mman.h> 18 20 19 21 #include "timeout.h" 20 22 #include "control.h" ··· 445 443 } 446 444 447 445 return hash; 446 + } 447 + 448 + size_t iovec_bytes(const struct iovec *iov, size_t iovnum) 449 + { 450 + size_t bytes; 451 + int i; 452 + 453 + for (bytes = 0, i = 0; i < iovnum; i++) 454 + bytes += iov[i].iov_len; 455 + 456 + return bytes; 457 + } 458 + 459 + unsigned long iovec_hash_djb2(const struct iovec *iov, size_t iovnum) 460 + { 461 + unsigned long hash; 462 + size_t iov_bytes; 463 + size_t offs; 464 + void *tmp; 465 + int i; 466 + 467 + iov_bytes = iovec_bytes(iov, iovnum); 468 + 469 + tmp = malloc(iov_bytes); 470 + if (!tmp) { 471 + perror("malloc"); 472 + exit(EXIT_FAILURE); 473 + } 474 + 475 + for (offs = 0, i = 0; i < iovnum; i++) { 476 + memcpy(tmp + offs, iov[i].iov_base, iov[i].iov_len); 477 + offs += iov[i].iov_len; 478 + } 479 + 480 + hash = hash_djb2(tmp, iov_bytes); 481 + free(tmp); 482 + 483 + return hash; 484 + } 485 + 486 + /* Allocates and returns new 'struct iovec *' according pattern 487 + * in the 'test_iovec'. For each element in the 'test_iovec' it 488 + * allocates new element in the resulting 'iovec'. 'iov_len' 489 + * of the new element is copied from 'test_iovec'. 'iov_base' is 490 + * allocated depending on the 'iov_base' of 'test_iovec': 491 + * 492 + * 'iov_base' == NULL -> valid buf: mmap('iov_len'). 493 + * 494 + * 'iov_base' == MAP_FAILED -> invalid buf: 495 + * mmap('iov_len'), then munmap('iov_len'). 496 + * 'iov_base' still contains result of 497 + * mmap(). 498 + * 499 + * 'iov_base' == number -> unaligned valid buf: 500 + * mmap('iov_len') + number. 501 + * 502 + * 'iovnum' is number of elements in 'test_iovec'. 503 + * 504 + * Returns new 'iovec' or calls 'exit()' on error. 505 + */ 506 + struct iovec *alloc_test_iovec(const struct iovec *test_iovec, int iovnum) 507 + { 508 + struct iovec *iovec; 509 + int i; 510 + 511 + iovec = malloc(sizeof(*iovec) * iovnum); 512 + if (!iovec) { 513 + perror("malloc"); 514 + exit(EXIT_FAILURE); 515 + } 516 + 517 + for (i = 0; i < iovnum; i++) { 518 + iovec[i].iov_len = test_iovec[i].iov_len; 519 + 520 + iovec[i].iov_base = mmap(NULL, iovec[i].iov_len, 521 + PROT_READ | PROT_WRITE, 522 + MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, 523 + -1, 0); 524 + if (iovec[i].iov_base == MAP_FAILED) { 525 + perror("mmap"); 526 + exit(EXIT_FAILURE); 527 + } 528 + 529 + if (test_iovec[i].iov_base != MAP_FAILED) 530 + iovec[i].iov_base += (uintptr_t)test_iovec[i].iov_base; 531 + } 532 + 533 + /* Unmap "invalid" elements. */ 534 + for (i = 0; i < iovnum; i++) { 535 + if (test_iovec[i].iov_base == MAP_FAILED) { 536 + if (munmap(iovec[i].iov_base, iovec[i].iov_len)) { 537 + perror("munmap"); 538 + exit(EXIT_FAILURE); 539 + } 540 + } 541 + } 542 + 543 + for (i = 0; i < iovnum; i++) { 544 + int j; 545 + 546 + if (test_iovec[i].iov_base == MAP_FAILED) 547 + continue; 548 + 549 + for (j = 0; j < iovec[i].iov_len; j++) 550 + ((uint8_t *)iovec[i].iov_base)[j] = rand() & 0xff; 551 + } 552 + 553 + return iovec; 554 + } 555 + 556 + /* Frees 'iovec *', previously allocated by 'alloc_test_iovec()'. 557 + * On error calls 'exit()'. 558 + */ 559 + void free_test_iovec(const struct iovec *test_iovec, 560 + struct iovec *iovec, int iovnum) 561 + { 562 + int i; 563 + 564 + for (i = 0; i < iovnum; i++) { 565 + if (test_iovec[i].iov_base != MAP_FAILED) { 566 + if (test_iovec[i].iov_base) 567 + iovec[i].iov_base -= (uintptr_t)test_iovec[i].iov_base; 568 + 569 + if (munmap(iovec[i].iov_base, iovec[i].iov_len)) { 570 + perror("munmap"); 571 + exit(EXIT_FAILURE); 572 + } 573 + } 574 + } 575 + 576 + free(iovec); 448 577 }
+5
tools/testing/vsock/util.h
··· 53 53 void skip_test(struct test_case *test_cases, size_t test_cases_len, 54 54 const char *test_id_str); 55 55 unsigned long hash_djb2(const void *data, size_t len); 56 + size_t iovec_bytes(const struct iovec *iov, size_t iovnum); 57 + unsigned long iovec_hash_djb2(const struct iovec *iov, size_t iovnum); 58 + struct iovec *alloc_test_iovec(const struct iovec *test_iovec, int iovnum); 59 + void free_test_iovec(const struct iovec *test_iovec, 60 + struct iovec *iovec, int iovnum); 56 61 #endif /* UTIL_H */
+16
tools/testing/vsock/vsock_test.c
··· 21 21 #include <poll.h> 22 22 #include <signal.h> 23 23 24 + #include "vsock_test_zerocopy.h" 24 25 #include "timeout.h" 25 26 #include "control.h" 26 27 #include "util.h" ··· 1269 1268 .name = "SOCK_STREAM SHUT_RD", 1270 1269 .run_client = test_stream_shutrd_client, 1271 1270 .run_server = test_stream_shutrd_server, 1271 + }, 1272 + { 1273 + .name = "SOCK_STREAM MSG_ZEROCOPY", 1274 + .run_client = test_stream_msgzcopy_client, 1275 + .run_server = test_stream_msgzcopy_server, 1276 + }, 1277 + { 1278 + .name = "SOCK_SEQPACKET MSG_ZEROCOPY", 1279 + .run_client = test_seqpacket_msgzcopy_client, 1280 + .run_server = test_seqpacket_msgzcopy_server, 1281 + }, 1282 + { 1283 + .name = "SOCK_STREAM MSG_ZEROCOPY empty MSG_ERRQUEUE", 1284 + .run_client = test_stream_msgzcopy_empty_errq_client, 1285 + .run_server = test_stream_msgzcopy_empty_errq_server, 1272 1286 }, 1273 1287 {}, 1274 1288 };
+358
tools/testing/vsock/vsock_test_zerocopy.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* MSG_ZEROCOPY feature tests for vsock 3 + * 4 + * Copyright (C) 2023 SberDevices. 5 + * 6 + * Author: Arseniy Krasnov <avkrasnov@salutedevices.com> 7 + */ 8 + 9 + #include <stdio.h> 10 + #include <stdlib.h> 11 + #include <string.h> 12 + #include <sys/mman.h> 13 + #include <unistd.h> 14 + #include <poll.h> 15 + #include <linux/errqueue.h> 16 + #include <linux/kernel.h> 17 + #include <errno.h> 18 + 19 + #include "control.h" 20 + #include "vsock_test_zerocopy.h" 21 + #include "msg_zerocopy_common.h" 22 + 23 + #ifndef PAGE_SIZE 24 + #define PAGE_SIZE 4096 25 + #endif 26 + 27 + #define VSOCK_TEST_DATA_MAX_IOV 3 28 + 29 + struct vsock_test_data { 30 + /* This test case if for SOCK_STREAM only. */ 31 + bool stream_only; 32 + /* Data must be zerocopied. This field is checked against 33 + * field 'ee_code' of the 'struct sock_extended_err', which 34 + * contains bit to detect that zerocopy transmission was 35 + * fallbacked to copy mode. 36 + */ 37 + bool zerocopied; 38 + /* Enable SO_ZEROCOPY option on the socket. Without enabled 39 + * SO_ZEROCOPY, every MSG_ZEROCOPY transmission will behave 40 + * like without MSG_ZEROCOPY flag. 41 + */ 42 + bool so_zerocopy; 43 + /* 'errno' after 'sendmsg()' call. */ 44 + int sendmsg_errno; 45 + /* Number of valid elements in 'vecs'. */ 46 + int vecs_cnt; 47 + struct iovec vecs[VSOCK_TEST_DATA_MAX_IOV]; 48 + }; 49 + 50 + static struct vsock_test_data test_data_array[] = { 51 + /* Last element has non-page aligned size. */ 52 + { 53 + .zerocopied = true, 54 + .so_zerocopy = true, 55 + .sendmsg_errno = 0, 56 + .vecs_cnt = 3, 57 + { 58 + { NULL, PAGE_SIZE }, 59 + { NULL, PAGE_SIZE }, 60 + { NULL, 200 } 61 + } 62 + }, 63 + /* All elements have page aligned base and size. */ 64 + { 65 + .zerocopied = true, 66 + .so_zerocopy = true, 67 + .sendmsg_errno = 0, 68 + .vecs_cnt = 3, 69 + { 70 + { NULL, PAGE_SIZE }, 71 + { NULL, PAGE_SIZE * 2 }, 72 + { NULL, PAGE_SIZE * 3 } 73 + } 74 + }, 75 + /* All elements have page aligned base and size. But 76 + * data length is bigger than 64Kb. 77 + */ 78 + { 79 + .zerocopied = true, 80 + .so_zerocopy = true, 81 + .sendmsg_errno = 0, 82 + .vecs_cnt = 3, 83 + { 84 + { NULL, PAGE_SIZE * 16 }, 85 + { NULL, PAGE_SIZE * 16 }, 86 + { NULL, PAGE_SIZE * 16 } 87 + } 88 + }, 89 + /* Middle element has both non-page aligned base and size. */ 90 + { 91 + .zerocopied = true, 92 + .so_zerocopy = true, 93 + .sendmsg_errno = 0, 94 + .vecs_cnt = 3, 95 + { 96 + { NULL, PAGE_SIZE }, 97 + { (void *)1, 100 }, 98 + { NULL, PAGE_SIZE } 99 + } 100 + }, 101 + /* Middle element is unmapped. */ 102 + { 103 + .zerocopied = false, 104 + .so_zerocopy = true, 105 + .sendmsg_errno = ENOMEM, 106 + .vecs_cnt = 3, 107 + { 108 + { NULL, PAGE_SIZE }, 109 + { MAP_FAILED, PAGE_SIZE }, 110 + { NULL, PAGE_SIZE } 111 + } 112 + }, 113 + /* Valid data, but SO_ZEROCOPY is off. This 114 + * will trigger fallback to copy. 115 + */ 116 + { 117 + .zerocopied = false, 118 + .so_zerocopy = false, 119 + .sendmsg_errno = 0, 120 + .vecs_cnt = 1, 121 + { 122 + { NULL, PAGE_SIZE } 123 + } 124 + }, 125 + /* Valid data, but message is bigger than peer's 126 + * buffer, so this will trigger fallback to copy. 127 + * This test is for SOCK_STREAM only, because 128 + * for SOCK_SEQPACKET, 'sendmsg()' returns EMSGSIZE. 129 + */ 130 + { 131 + .stream_only = true, 132 + .zerocopied = false, 133 + .so_zerocopy = true, 134 + .sendmsg_errno = 0, 135 + .vecs_cnt = 1, 136 + { 137 + { NULL, 100 * PAGE_SIZE } 138 + } 139 + }, 140 + }; 141 + 142 + #define POLL_TIMEOUT_MS 100 143 + 144 + static void test_client(const struct test_opts *opts, 145 + const struct vsock_test_data *test_data, 146 + bool sock_seqpacket) 147 + { 148 + struct pollfd fds = { 0 }; 149 + struct msghdr msg = { 0 }; 150 + ssize_t sendmsg_res; 151 + struct iovec *iovec; 152 + int fd; 153 + 154 + if (sock_seqpacket) 155 + fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 156 + else 157 + fd = vsock_stream_connect(opts->peer_cid, 1234); 158 + 159 + if (fd < 0) { 160 + perror("connect"); 161 + exit(EXIT_FAILURE); 162 + } 163 + 164 + if (test_data->so_zerocopy) 165 + enable_so_zerocopy(fd); 166 + 167 + iovec = alloc_test_iovec(test_data->vecs, test_data->vecs_cnt); 168 + 169 + msg.msg_iov = iovec; 170 + msg.msg_iovlen = test_data->vecs_cnt; 171 + 172 + errno = 0; 173 + 174 + sendmsg_res = sendmsg(fd, &msg, MSG_ZEROCOPY); 175 + if (errno != test_data->sendmsg_errno) { 176 + fprintf(stderr, "expected 'errno' == %i, got %i\n", 177 + test_data->sendmsg_errno, errno); 178 + exit(EXIT_FAILURE); 179 + } 180 + 181 + if (!errno) { 182 + if (sendmsg_res != iovec_bytes(iovec, test_data->vecs_cnt)) { 183 + fprintf(stderr, "expected 'sendmsg()' == %li, got %li\n", 184 + iovec_bytes(iovec, test_data->vecs_cnt), 185 + sendmsg_res); 186 + exit(EXIT_FAILURE); 187 + } 188 + } 189 + 190 + fds.fd = fd; 191 + fds.events = 0; 192 + 193 + if (poll(&fds, 1, POLL_TIMEOUT_MS) < 0) { 194 + perror("poll"); 195 + exit(EXIT_FAILURE); 196 + } 197 + 198 + if (fds.revents & POLLERR) { 199 + vsock_recv_completion(fd, &test_data->zerocopied); 200 + } else if (test_data->so_zerocopy && !test_data->sendmsg_errno) { 201 + /* If we don't have data in the error queue, but 202 + * SO_ZEROCOPY was enabled and 'sendmsg()' was 203 + * successful - this is an error. 204 + */ 205 + fprintf(stderr, "POLLERR expected\n"); 206 + exit(EXIT_FAILURE); 207 + } 208 + 209 + if (!test_data->sendmsg_errno) 210 + control_writeulong(iovec_hash_djb2(iovec, test_data->vecs_cnt)); 211 + else 212 + control_writeulong(0); 213 + 214 + control_writeln("DONE"); 215 + free_test_iovec(test_data->vecs, iovec, test_data->vecs_cnt); 216 + close(fd); 217 + } 218 + 219 + void test_stream_msgzcopy_client(const struct test_opts *opts) 220 + { 221 + int i; 222 + 223 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) 224 + test_client(opts, &test_data_array[i], false); 225 + } 226 + 227 + void test_seqpacket_msgzcopy_client(const struct test_opts *opts) 228 + { 229 + int i; 230 + 231 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) { 232 + if (test_data_array[i].stream_only) 233 + continue; 234 + 235 + test_client(opts, &test_data_array[i], true); 236 + } 237 + } 238 + 239 + static void test_server(const struct test_opts *opts, 240 + const struct vsock_test_data *test_data, 241 + bool sock_seqpacket) 242 + { 243 + unsigned long remote_hash; 244 + unsigned long local_hash; 245 + ssize_t total_bytes_rec; 246 + unsigned char *data; 247 + size_t data_len; 248 + int fd; 249 + 250 + if (sock_seqpacket) 251 + fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 252 + else 253 + fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 254 + 255 + if (fd < 0) { 256 + perror("accept"); 257 + exit(EXIT_FAILURE); 258 + } 259 + 260 + data_len = iovec_bytes(test_data->vecs, test_data->vecs_cnt); 261 + 262 + data = malloc(data_len); 263 + if (!data) { 264 + perror("malloc"); 265 + exit(EXIT_FAILURE); 266 + } 267 + 268 + total_bytes_rec = 0; 269 + 270 + while (total_bytes_rec != data_len) { 271 + ssize_t bytes_rec; 272 + 273 + bytes_rec = read(fd, data + total_bytes_rec, 274 + data_len - total_bytes_rec); 275 + if (bytes_rec <= 0) 276 + break; 277 + 278 + total_bytes_rec += bytes_rec; 279 + } 280 + 281 + if (test_data->sendmsg_errno == 0) 282 + local_hash = hash_djb2(data, data_len); 283 + else 284 + local_hash = 0; 285 + 286 + free(data); 287 + 288 + /* Waiting for some result. */ 289 + remote_hash = control_readulong(); 290 + if (remote_hash != local_hash) { 291 + fprintf(stderr, "hash mismatch\n"); 292 + exit(EXIT_FAILURE); 293 + } 294 + 295 + control_expectln("DONE"); 296 + close(fd); 297 + } 298 + 299 + void test_stream_msgzcopy_server(const struct test_opts *opts) 300 + { 301 + int i; 302 + 303 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) 304 + test_server(opts, &test_data_array[i], false); 305 + } 306 + 307 + void test_seqpacket_msgzcopy_server(const struct test_opts *opts) 308 + { 309 + int i; 310 + 311 + for (i = 0; i < ARRAY_SIZE(test_data_array); i++) { 312 + if (test_data_array[i].stream_only) 313 + continue; 314 + 315 + test_server(opts, &test_data_array[i], true); 316 + } 317 + } 318 + 319 + void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts) 320 + { 321 + struct msghdr msg = { 0 }; 322 + char cmsg_data[128]; 323 + ssize_t res; 324 + int fd; 325 + 326 + fd = vsock_stream_connect(opts->peer_cid, 1234); 327 + if (fd < 0) { 328 + perror("connect"); 329 + exit(EXIT_FAILURE); 330 + } 331 + 332 + msg.msg_control = cmsg_data; 333 + msg.msg_controllen = sizeof(cmsg_data); 334 + 335 + res = recvmsg(fd, &msg, MSG_ERRQUEUE); 336 + if (res != -1) { 337 + fprintf(stderr, "expected 'recvmsg(2)' failure, got %zi\n", 338 + res); 339 + exit(EXIT_FAILURE); 340 + } 341 + 342 + control_writeln("DONE"); 343 + close(fd); 344 + } 345 + 346 + void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts) 347 + { 348 + int fd; 349 + 350 + fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 351 + if (fd < 0) { 352 + perror("accept"); 353 + exit(EXIT_FAILURE); 354 + } 355 + 356 + control_expectln("DONE"); 357 + close(fd); 358 + }
+15
tools/testing/vsock/vsock_test_zerocopy.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef VSOCK_TEST_ZEROCOPY_H 3 + #define VSOCK_TEST_ZEROCOPY_H 4 + #include "util.h" 5 + 6 + void test_stream_msgzcopy_client(const struct test_opts *opts); 7 + void test_stream_msgzcopy_server(const struct test_opts *opts); 8 + 9 + void test_seqpacket_msgzcopy_client(const struct test_opts *opts); 10 + void test_seqpacket_msgzcopy_server(const struct test_opts *opts); 11 + 12 + void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts); 13 + void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts); 14 + 15 + #endif /* VSOCK_TEST_ZEROCOPY_H */