1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * vsock_test - vsock.ko test suite |
4 | * |
5 | * Copyright (C) 2017 Red Hat, Inc. |
6 | * |
7 | * Author: Stefan Hajnoczi <stefanha@redhat.com> |
8 | */ |
9 | |
10 | #include <getopt.h> |
11 | #include <stdio.h> |
12 | #include <stdlib.h> |
13 | #include <string.h> |
14 | #include <errno.h> |
15 | #include <unistd.h> |
16 | #include <linux/kernel.h> |
17 | #include <sys/types.h> |
18 | #include <sys/socket.h> |
19 | #include <time.h> |
20 | #include <sys/mman.h> |
21 | #include <poll.h> |
22 | #include <signal.h> |
23 | |
24 | #include "vsock_test_zerocopy.h" |
25 | #include "timeout.h" |
26 | #include "control.h" |
27 | #include "util.h" |
28 | |
29 | static void test_stream_connection_reset(const struct test_opts *opts) |
30 | { |
31 | union { |
32 | struct sockaddr sa; |
33 | struct sockaddr_vm svm; |
34 | } addr = { |
35 | .svm = { |
36 | .svm_family = AF_VSOCK, |
37 | .svm_port = opts->peer_port, |
38 | .svm_cid = opts->peer_cid, |
39 | }, |
40 | }; |
41 | int ret; |
42 | int fd; |
43 | |
44 | fd = socket(AF_VSOCK, SOCK_STREAM, 0); |
45 | |
46 | timeout_begin(seconds: TIMEOUT); |
47 | do { |
48 | ret = connect(fd, &addr.sa, sizeof(addr.svm)); |
49 | timeout_check(operation: "connect" ); |
50 | } while (ret < 0 && errno == EINTR); |
51 | timeout_end(); |
52 | |
53 | if (ret != -1) { |
54 | fprintf(stderr, "expected connect(2) failure, got %d\n" , ret); |
55 | exit(EXIT_FAILURE); |
56 | } |
57 | if (errno != ECONNRESET) { |
58 | fprintf(stderr, "unexpected connect(2) errno %d\n" , errno); |
59 | exit(EXIT_FAILURE); |
60 | } |
61 | |
62 | close(fd); |
63 | } |
64 | |
65 | static void test_stream_bind_only_client(const struct test_opts *opts) |
66 | { |
67 | union { |
68 | struct sockaddr sa; |
69 | struct sockaddr_vm svm; |
70 | } addr = { |
71 | .svm = { |
72 | .svm_family = AF_VSOCK, |
73 | .svm_port = opts->peer_port, |
74 | .svm_cid = opts->peer_cid, |
75 | }, |
76 | }; |
77 | int ret; |
78 | int fd; |
79 | |
80 | /* Wait for the server to be ready */ |
81 | control_expectln(str: "BIND" ); |
82 | |
83 | fd = socket(AF_VSOCK, SOCK_STREAM, 0); |
84 | |
85 | timeout_begin(seconds: TIMEOUT); |
86 | do { |
87 | ret = connect(fd, &addr.sa, sizeof(addr.svm)); |
88 | timeout_check("connect" ); |
89 | } while (ret < 0 && errno == EINTR); |
90 | timeout_end(); |
91 | |
92 | if (ret != -1) { |
93 | fprintf(stderr, "expected connect(2) failure, got %d\n" , ret); |
94 | exit(EXIT_FAILURE); |
95 | } |
96 | if (errno != ECONNRESET) { |
97 | fprintf(stderr, "unexpected connect(2) errno %d\n" , errno); |
98 | exit(EXIT_FAILURE); |
99 | } |
100 | |
101 | /* Notify the server that the client has finished */ |
102 | control_writeln(str: "DONE" ); |
103 | |
104 | close(fd); |
105 | } |
106 | |
107 | static void test_stream_bind_only_server(const struct test_opts *opts) |
108 | { |
109 | union { |
110 | struct sockaddr sa; |
111 | struct sockaddr_vm svm; |
112 | } addr = { |
113 | .svm = { |
114 | .svm_family = AF_VSOCK, |
115 | .svm_port = opts->peer_port, |
116 | .svm_cid = VMADDR_CID_ANY, |
117 | }, |
118 | }; |
119 | int fd; |
120 | |
121 | fd = socket(AF_VSOCK, SOCK_STREAM, 0); |
122 | |
123 | if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { |
124 | perror("bind" ); |
125 | exit(EXIT_FAILURE); |
126 | } |
127 | |
128 | /* Notify the client that the server is ready */ |
129 | control_writeln(str: "BIND" ); |
130 | |
131 | /* Wait for the client to finish */ |
132 | control_expectln(str: "DONE" ); |
133 | |
134 | close(fd); |
135 | } |
136 | |
137 | static void test_stream_client_close_client(const struct test_opts *opts) |
138 | { |
139 | int fd; |
140 | |
141 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
142 | if (fd < 0) { |
143 | perror("connect" ); |
144 | exit(EXIT_FAILURE); |
145 | } |
146 | |
147 | send_byte(fd, expected_ret: 1, flags: 0); |
148 | close(fd); |
149 | } |
150 | |
151 | static void test_stream_client_close_server(const struct test_opts *opts) |
152 | { |
153 | int fd; |
154 | |
155 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
156 | if (fd < 0) { |
157 | perror("accept" ); |
158 | exit(EXIT_FAILURE); |
159 | } |
160 | |
161 | /* Wait for the remote to close the connection, before check |
162 | * -EPIPE error on send. |
163 | */ |
164 | vsock_wait_remote_close(fd); |
165 | |
166 | send_byte(fd, expected_ret: -EPIPE, flags: 0); |
167 | recv_byte(fd, expected_ret: 1, flags: 0); |
168 | recv_byte(fd, expected_ret: 0, flags: 0); |
169 | close(fd); |
170 | } |
171 | |
172 | static void test_stream_server_close_client(const struct test_opts *opts) |
173 | { |
174 | int fd; |
175 | |
176 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
177 | if (fd < 0) { |
178 | perror("connect" ); |
179 | exit(EXIT_FAILURE); |
180 | } |
181 | |
182 | /* Wait for the remote to close the connection, before check |
183 | * -EPIPE error on send. |
184 | */ |
185 | vsock_wait_remote_close(fd); |
186 | |
187 | send_byte(fd, expected_ret: -EPIPE, flags: 0); |
188 | recv_byte(fd, expected_ret: 1, flags: 0); |
189 | recv_byte(fd, expected_ret: 0, flags: 0); |
190 | close(fd); |
191 | } |
192 | |
193 | static void test_stream_server_close_server(const struct test_opts *opts) |
194 | { |
195 | int fd; |
196 | |
197 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
198 | if (fd < 0) { |
199 | perror("accept" ); |
200 | exit(EXIT_FAILURE); |
201 | } |
202 | |
203 | send_byte(fd, expected_ret: 1, flags: 0); |
204 | close(fd); |
205 | } |
206 | |
207 | /* With the standard socket sizes, VMCI is able to support about 100 |
208 | * concurrent stream connections. |
209 | */ |
210 | #define MULTICONN_NFDS 100 |
211 | |
212 | static void test_stream_multiconn_client(const struct test_opts *opts) |
213 | { |
214 | int fds[MULTICONN_NFDS]; |
215 | int i; |
216 | |
217 | for (i = 0; i < MULTICONN_NFDS; i++) { |
218 | fds[i] = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
219 | if (fds[i] < 0) { |
220 | perror("connect" ); |
221 | exit(EXIT_FAILURE); |
222 | } |
223 | } |
224 | |
225 | for (i = 0; i < MULTICONN_NFDS; i++) { |
226 | if (i % 2) |
227 | recv_byte(fd: fds[i], expected_ret: 1, flags: 0); |
228 | else |
229 | send_byte(fd: fds[i], expected_ret: 1, flags: 0); |
230 | } |
231 | |
232 | for (i = 0; i < MULTICONN_NFDS; i++) |
233 | close(fds[i]); |
234 | } |
235 | |
236 | static void test_stream_multiconn_server(const struct test_opts *opts) |
237 | { |
238 | int fds[MULTICONN_NFDS]; |
239 | int i; |
240 | |
241 | for (i = 0; i < MULTICONN_NFDS; i++) { |
242 | fds[i] = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
243 | if (fds[i] < 0) { |
244 | perror("accept" ); |
245 | exit(EXIT_FAILURE); |
246 | } |
247 | } |
248 | |
249 | for (i = 0; i < MULTICONN_NFDS; i++) { |
250 | if (i % 2) |
251 | send_byte(fd: fds[i], expected_ret: 1, flags: 0); |
252 | else |
253 | recv_byte(fd: fds[i], expected_ret: 1, flags: 0); |
254 | } |
255 | |
256 | for (i = 0; i < MULTICONN_NFDS; i++) |
257 | close(fds[i]); |
258 | } |
259 | |
260 | #define MSG_PEEK_BUF_LEN 64 |
261 | |
262 | static void test_msg_peek_client(const struct test_opts *opts, |
263 | bool seqpacket) |
264 | { |
265 | unsigned char buf[MSG_PEEK_BUF_LEN]; |
266 | int fd; |
267 | int i; |
268 | |
269 | if (seqpacket) |
270 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
271 | else |
272 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
273 | |
274 | if (fd < 0) { |
275 | perror("connect" ); |
276 | exit(EXIT_FAILURE); |
277 | } |
278 | |
279 | for (i = 0; i < sizeof(buf); i++) |
280 | buf[i] = rand() & 0xFF; |
281 | |
282 | control_expectln(str: "SRVREADY" ); |
283 | |
284 | send_buf(fd, buf, len: sizeof(buf), flags: 0, expected_ret: sizeof(buf)); |
285 | |
286 | close(fd); |
287 | } |
288 | |
289 | static void test_msg_peek_server(const struct test_opts *opts, |
290 | bool seqpacket) |
291 | { |
292 | unsigned char buf_half[MSG_PEEK_BUF_LEN / 2]; |
293 | unsigned char buf_normal[MSG_PEEK_BUF_LEN]; |
294 | unsigned char buf_peek[MSG_PEEK_BUF_LEN]; |
295 | int fd; |
296 | |
297 | if (seqpacket) |
298 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
299 | else |
300 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
301 | |
302 | if (fd < 0) { |
303 | perror("accept" ); |
304 | exit(EXIT_FAILURE); |
305 | } |
306 | |
307 | /* Peek from empty socket. */ |
308 | recv_buf(fd, buf: buf_peek, len: sizeof(buf_peek), MSG_PEEK | MSG_DONTWAIT, |
309 | expected_ret: -EAGAIN); |
310 | |
311 | control_writeln(str: "SRVREADY" ); |
312 | |
313 | /* Peek part of data. */ |
314 | recv_buf(fd, buf: buf_half, len: sizeof(buf_half), MSG_PEEK, expected_ret: sizeof(buf_half)); |
315 | |
316 | /* Peek whole data. */ |
317 | recv_buf(fd, buf: buf_peek, len: sizeof(buf_peek), MSG_PEEK, expected_ret: sizeof(buf_peek)); |
318 | |
319 | /* Compare partial and full peek. */ |
320 | if (memcmp(p: buf_half, q: buf_peek, size: sizeof(buf_half))) { |
321 | fprintf(stderr, "Partial peek data mismatch\n" ); |
322 | exit(EXIT_FAILURE); |
323 | } |
324 | |
325 | if (seqpacket) { |
326 | /* This type of socket supports MSG_TRUNC flag, |
327 | * so check it with MSG_PEEK. We must get length |
328 | * of the message. |
329 | */ |
330 | recv_buf(fd, buf: buf_half, len: sizeof(buf_half), MSG_PEEK | MSG_TRUNC, |
331 | expected_ret: sizeof(buf_peek)); |
332 | } |
333 | |
334 | recv_buf(fd, buf: buf_normal, len: sizeof(buf_normal), flags: 0, expected_ret: sizeof(buf_normal)); |
335 | |
336 | /* Compare full peek and normal read. */ |
337 | if (memcmp(p: buf_peek, q: buf_normal, size: sizeof(buf_peek))) { |
338 | fprintf(stderr, "Full peek data mismatch\n" ); |
339 | exit(EXIT_FAILURE); |
340 | } |
341 | |
342 | close(fd); |
343 | } |
344 | |
345 | static void test_stream_msg_peek_client(const struct test_opts *opts) |
346 | { |
347 | return test_msg_peek_client(opts, seqpacket: false); |
348 | } |
349 | |
350 | static void test_stream_msg_peek_server(const struct test_opts *opts) |
351 | { |
352 | return test_msg_peek_server(opts, seqpacket: false); |
353 | } |
354 | |
355 | #define SOCK_BUF_SIZE (2 * 1024 * 1024) |
356 | #define MAX_MSG_PAGES 4 |
357 | |
358 | static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) |
359 | { |
360 | unsigned long curr_hash; |
361 | size_t max_msg_size; |
362 | int page_size; |
363 | int msg_count; |
364 | int fd; |
365 | |
366 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
367 | if (fd < 0) { |
368 | perror("connect" ); |
369 | exit(EXIT_FAILURE); |
370 | } |
371 | |
372 | /* Wait, until receiver sets buffer size. */ |
373 | control_expectln(str: "SRVREADY" ); |
374 | |
375 | curr_hash = 0; |
376 | page_size = getpagesize(); |
377 | max_msg_size = MAX_MSG_PAGES * page_size; |
378 | msg_count = SOCK_BUF_SIZE / max_msg_size; |
379 | |
380 | for (int i = 0; i < msg_count; i++) { |
381 | size_t buf_size; |
382 | int flags; |
383 | void *buf; |
384 | |
385 | /* Use "small" buffers and "big" buffers. */ |
386 | if (i & 1) |
387 | buf_size = page_size + |
388 | (rand() % (max_msg_size - page_size)); |
389 | else |
390 | buf_size = 1 + (rand() % page_size); |
391 | |
392 | buf = malloc(buf_size); |
393 | |
394 | if (!buf) { |
395 | perror("malloc" ); |
396 | exit(EXIT_FAILURE); |
397 | } |
398 | |
399 | memset(buf, rand() & 0xff, buf_size); |
400 | /* Set at least one MSG_EOR + some random. */ |
401 | if (i == (msg_count / 2) || (rand() & 1)) { |
402 | flags = MSG_EOR; |
403 | curr_hash++; |
404 | } else { |
405 | flags = 0; |
406 | } |
407 | |
408 | send_buf(fd, buf, len: buf_size, flags, expected_ret: buf_size); |
409 | |
410 | /* |
411 | * Hash sum is computed at both client and server in |
412 | * the same way: |
413 | * H += hash('message data') |
414 | * Such hash "controls" both data integrity and message |
415 | * bounds. After data exchange, both sums are compared |
416 | * using control socket, and if message bounds wasn't |
417 | * broken - two values must be equal. |
418 | */ |
419 | curr_hash += hash_djb2(data: buf, len: buf_size); |
420 | free(buf); |
421 | } |
422 | |
423 | control_writeln(str: "SENDDONE" ); |
424 | control_writeulong(value: curr_hash); |
425 | close(fd); |
426 | } |
427 | |
428 | static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) |
429 | { |
430 | unsigned long sock_buf_size; |
431 | unsigned long remote_hash; |
432 | unsigned long curr_hash; |
433 | int fd; |
434 | struct msghdr msg = {0}; |
435 | struct iovec iov = {0}; |
436 | |
437 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
438 | if (fd < 0) { |
439 | perror("accept" ); |
440 | exit(EXIT_FAILURE); |
441 | } |
442 | |
443 | sock_buf_size = SOCK_BUF_SIZE; |
444 | |
445 | if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, |
446 | &sock_buf_size, sizeof(sock_buf_size))) { |
447 | perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)" ); |
448 | exit(EXIT_FAILURE); |
449 | } |
450 | |
451 | if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, |
452 | &sock_buf_size, sizeof(sock_buf_size))) { |
453 | perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)" ); |
454 | exit(EXIT_FAILURE); |
455 | } |
456 | |
457 | /* Ready to receive data. */ |
458 | control_writeln(str: "SRVREADY" ); |
459 | /* Wait, until peer sends whole data. */ |
460 | control_expectln(str: "SENDDONE" ); |
461 | iov.iov_len = MAX_MSG_PAGES * getpagesize(); |
462 | iov.iov_base = malloc(iov.iov_len); |
463 | if (!iov.iov_base) { |
464 | perror("malloc" ); |
465 | exit(EXIT_FAILURE); |
466 | } |
467 | |
468 | msg.msg_iov = &iov; |
469 | msg.msg_iovlen = 1; |
470 | |
471 | curr_hash = 0; |
472 | |
473 | while (1) { |
474 | ssize_t recv_size; |
475 | |
476 | recv_size = recvmsg(fd, &msg, 0); |
477 | |
478 | if (!recv_size) |
479 | break; |
480 | |
481 | if (recv_size < 0) { |
482 | perror("recvmsg" ); |
483 | exit(EXIT_FAILURE); |
484 | } |
485 | |
486 | if (msg.msg_flags & MSG_EOR) |
487 | curr_hash++; |
488 | |
489 | curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size); |
490 | } |
491 | |
492 | free(iov.iov_base); |
493 | close(fd); |
494 | remote_hash = control_readulong(); |
495 | |
496 | if (curr_hash != remote_hash) { |
497 | fprintf(stderr, "Message bounds broken\n" ); |
498 | exit(EXIT_FAILURE); |
499 | } |
500 | } |
501 | |
502 | #define MESSAGE_TRUNC_SZ 32 |
503 | static void test_seqpacket_msg_trunc_client(const struct test_opts *opts) |
504 | { |
505 | int fd; |
506 | char buf[MESSAGE_TRUNC_SZ]; |
507 | |
508 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
509 | if (fd < 0) { |
510 | perror("connect" ); |
511 | exit(EXIT_FAILURE); |
512 | } |
513 | |
514 | send_buf(fd, buf, len: sizeof(buf), flags: 0, expected_ret: sizeof(buf)); |
515 | |
516 | control_writeln(str: "SENDDONE" ); |
517 | close(fd); |
518 | } |
519 | |
520 | static void test_seqpacket_msg_trunc_server(const struct test_opts *opts) |
521 | { |
522 | int fd; |
523 | char buf[MESSAGE_TRUNC_SZ / 2]; |
524 | struct msghdr msg = {0}; |
525 | struct iovec iov = {0}; |
526 | |
527 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
528 | if (fd < 0) { |
529 | perror("accept" ); |
530 | exit(EXIT_FAILURE); |
531 | } |
532 | |
533 | control_expectln(str: "SENDDONE" ); |
534 | iov.iov_base = buf; |
535 | iov.iov_len = sizeof(buf); |
536 | msg.msg_iov = &iov; |
537 | msg.msg_iovlen = 1; |
538 | |
539 | ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC); |
540 | |
541 | if (ret != MESSAGE_TRUNC_SZ) { |
542 | printf("%zi\n" , ret); |
543 | perror("MSG_TRUNC doesn't work" ); |
544 | exit(EXIT_FAILURE); |
545 | } |
546 | |
547 | if (!(msg.msg_flags & MSG_TRUNC)) { |
548 | fprintf(stderr, "MSG_TRUNC expected\n" ); |
549 | exit(EXIT_FAILURE); |
550 | } |
551 | |
552 | close(fd); |
553 | } |
554 | |
555 | static time_t current_nsec(void) |
556 | { |
557 | struct timespec ts; |
558 | |
559 | if (clock_gettime(CLOCK_REALTIME, &ts)) { |
560 | perror("clock_gettime(3) failed" ); |
561 | exit(EXIT_FAILURE); |
562 | } |
563 | |
564 | return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec; |
565 | } |
566 | |
567 | #define RCVTIMEO_TIMEOUT_SEC 1 |
568 | #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */ |
569 | |
570 | static void test_seqpacket_timeout_client(const struct test_opts *opts) |
571 | { |
572 | int fd; |
573 | struct timeval tv; |
574 | char dummy; |
575 | time_t read_enter_ns; |
576 | time_t read_overhead_ns; |
577 | |
578 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
579 | if (fd < 0) { |
580 | perror("connect" ); |
581 | exit(EXIT_FAILURE); |
582 | } |
583 | |
584 | tv.tv_sec = RCVTIMEO_TIMEOUT_SEC; |
585 | tv.tv_usec = 0; |
586 | |
587 | if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) { |
588 | perror("setsockopt(SO_RCVTIMEO)" ); |
589 | exit(EXIT_FAILURE); |
590 | } |
591 | |
592 | read_enter_ns = current_nsec(); |
593 | |
594 | if (read(fd, &dummy, sizeof(dummy)) != -1) { |
595 | fprintf(stderr, |
596 | "expected 'dummy' read(2) failure\n" ); |
597 | exit(EXIT_FAILURE); |
598 | } |
599 | |
600 | if (errno != EAGAIN) { |
601 | perror("EAGAIN expected" ); |
602 | exit(EXIT_FAILURE); |
603 | } |
604 | |
605 | read_overhead_ns = current_nsec() - read_enter_ns - |
606 | 1000000000ULL * RCVTIMEO_TIMEOUT_SEC; |
607 | |
608 | if (read_overhead_ns > READ_OVERHEAD_NSEC) { |
609 | fprintf(stderr, |
610 | "too much time in read(2), %lu > %i ns\n" , |
611 | read_overhead_ns, READ_OVERHEAD_NSEC); |
612 | exit(EXIT_FAILURE); |
613 | } |
614 | |
615 | control_writeln(str: "WAITDONE" ); |
616 | close(fd); |
617 | } |
618 | |
619 | static void test_seqpacket_timeout_server(const struct test_opts *opts) |
620 | { |
621 | int fd; |
622 | |
623 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
624 | if (fd < 0) { |
625 | perror("accept" ); |
626 | exit(EXIT_FAILURE); |
627 | } |
628 | |
629 | control_expectln(str: "WAITDONE" ); |
630 | close(fd); |
631 | } |
632 | |
633 | static void test_seqpacket_bigmsg_client(const struct test_opts *opts) |
634 | { |
635 | unsigned long sock_buf_size; |
636 | socklen_t len; |
637 | void *data; |
638 | int fd; |
639 | |
640 | len = sizeof(sock_buf_size); |
641 | |
642 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
643 | if (fd < 0) { |
644 | perror("connect" ); |
645 | exit(EXIT_FAILURE); |
646 | } |
647 | |
648 | if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, |
649 | &sock_buf_size, &len)) { |
650 | perror("getsockopt" ); |
651 | exit(EXIT_FAILURE); |
652 | } |
653 | |
654 | sock_buf_size++; |
655 | |
656 | data = malloc(sock_buf_size); |
657 | if (!data) { |
658 | perror("malloc" ); |
659 | exit(EXIT_FAILURE); |
660 | } |
661 | |
662 | send_buf(fd, buf: data, len: sock_buf_size, flags: 0, expected_ret: -EMSGSIZE); |
663 | |
664 | control_writeln(str: "CLISENT" ); |
665 | |
666 | free(data); |
667 | close(fd); |
668 | } |
669 | |
670 | static void test_seqpacket_bigmsg_server(const struct test_opts *opts) |
671 | { |
672 | int fd; |
673 | |
674 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
675 | if (fd < 0) { |
676 | perror("accept" ); |
677 | exit(EXIT_FAILURE); |
678 | } |
679 | |
680 | control_expectln(str: "CLISENT" ); |
681 | |
682 | close(fd); |
683 | } |
684 | |
685 | #define BUF_PATTERN_1 'a' |
686 | #define BUF_PATTERN_2 'b' |
687 | |
688 | static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts) |
689 | { |
690 | int fd; |
691 | unsigned char *buf1; |
692 | unsigned char *buf2; |
693 | int buf_size = getpagesize() * 3; |
694 | |
695 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
696 | if (fd < 0) { |
697 | perror("connect" ); |
698 | exit(EXIT_FAILURE); |
699 | } |
700 | |
701 | buf1 = malloc(buf_size); |
702 | if (!buf1) { |
703 | perror("'malloc()' for 'buf1'" ); |
704 | exit(EXIT_FAILURE); |
705 | } |
706 | |
707 | buf2 = malloc(buf_size); |
708 | if (!buf2) { |
709 | perror("'malloc()' for 'buf2'" ); |
710 | exit(EXIT_FAILURE); |
711 | } |
712 | |
713 | memset(buf1, BUF_PATTERN_1, buf_size); |
714 | memset(buf2, BUF_PATTERN_2, buf_size); |
715 | |
716 | send_buf(fd, buf: buf1, len: buf_size, flags: 0, expected_ret: buf_size); |
717 | |
718 | send_buf(fd, buf: buf2, len: buf_size, flags: 0, expected_ret: buf_size); |
719 | |
720 | close(fd); |
721 | } |
722 | |
723 | static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts) |
724 | { |
725 | int fd; |
726 | unsigned char *broken_buf; |
727 | unsigned char *valid_buf; |
728 | int page_size = getpagesize(); |
729 | int buf_size = page_size * 3; |
730 | ssize_t res; |
731 | int prot = PROT_READ | PROT_WRITE; |
732 | int flags = MAP_PRIVATE | MAP_ANONYMOUS; |
733 | int i; |
734 | |
735 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
736 | if (fd < 0) { |
737 | perror("accept" ); |
738 | exit(EXIT_FAILURE); |
739 | } |
740 | |
741 | /* Setup first buffer. */ |
742 | broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0); |
743 | if (broken_buf == MAP_FAILED) { |
744 | perror("mmap for 'broken_buf'" ); |
745 | exit(EXIT_FAILURE); |
746 | } |
747 | |
748 | /* Unmap "hole" in buffer. */ |
749 | if (munmap(broken_buf + page_size, page_size)) { |
750 | perror("'broken_buf' setup" ); |
751 | exit(EXIT_FAILURE); |
752 | } |
753 | |
754 | valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0); |
755 | if (valid_buf == MAP_FAILED) { |
756 | perror("mmap for 'valid_buf'" ); |
757 | exit(EXIT_FAILURE); |
758 | } |
759 | |
760 | /* Try to fill buffer with unmapped middle. */ |
761 | res = read(fd, broken_buf, buf_size); |
762 | if (res != -1) { |
763 | fprintf(stderr, |
764 | "expected 'broken_buf' read(2) failure, got %zi\n" , |
765 | res); |
766 | exit(EXIT_FAILURE); |
767 | } |
768 | |
769 | if (errno != EFAULT) { |
770 | perror("unexpected errno of 'broken_buf'" ); |
771 | exit(EXIT_FAILURE); |
772 | } |
773 | |
774 | /* Try to fill valid buffer. */ |
775 | res = read(fd, valid_buf, buf_size); |
776 | if (res < 0) { |
777 | perror("unexpected 'valid_buf' read(2) failure" ); |
778 | exit(EXIT_FAILURE); |
779 | } |
780 | |
781 | if (res != buf_size) { |
782 | fprintf(stderr, |
783 | "invalid 'valid_buf' read(2), expected %i, got %zi\n" , |
784 | buf_size, res); |
785 | exit(EXIT_FAILURE); |
786 | } |
787 | |
788 | for (i = 0; i < buf_size; i++) { |
789 | if (valid_buf[i] != BUF_PATTERN_2) { |
790 | fprintf(stderr, |
791 | "invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n" , |
792 | i, BUF_PATTERN_2, valid_buf[i]); |
793 | exit(EXIT_FAILURE); |
794 | } |
795 | } |
796 | |
797 | /* Unmap buffers. */ |
798 | munmap(broken_buf, page_size); |
799 | munmap(broken_buf + page_size * 2, page_size); |
800 | munmap(valid_buf, buf_size); |
801 | close(fd); |
802 | } |
803 | |
804 | #define RCVLOWAT_BUF_SIZE 128 |
805 | |
806 | static void test_stream_poll_rcvlowat_server(const struct test_opts *opts) |
807 | { |
808 | int fd; |
809 | int i; |
810 | |
811 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
812 | if (fd < 0) { |
813 | perror("accept" ); |
814 | exit(EXIT_FAILURE); |
815 | } |
816 | |
817 | /* Send 1 byte. */ |
818 | send_byte(fd, expected_ret: 1, flags: 0); |
819 | |
820 | control_writeln(str: "SRVSENT" ); |
821 | |
822 | /* Wait until client is ready to receive rest of data. */ |
823 | control_expectln(str: "CLNSENT" ); |
824 | |
825 | for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++) |
826 | send_byte(fd, expected_ret: 1, flags: 0); |
827 | |
828 | /* Keep socket in active state. */ |
829 | control_expectln(str: "POLLDONE" ); |
830 | |
831 | close(fd); |
832 | } |
833 | |
834 | static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) |
835 | { |
836 | unsigned long lowat_val = RCVLOWAT_BUF_SIZE; |
837 | char buf[RCVLOWAT_BUF_SIZE]; |
838 | struct pollfd fds; |
839 | short poll_flags; |
840 | int fd; |
841 | |
842 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
843 | if (fd < 0) { |
844 | perror("connect" ); |
845 | exit(EXIT_FAILURE); |
846 | } |
847 | |
848 | if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, |
849 | &lowat_val, sizeof(lowat_val))) { |
850 | perror("setsockopt(SO_RCVLOWAT)" ); |
851 | exit(EXIT_FAILURE); |
852 | } |
853 | |
854 | control_expectln(str: "SRVSENT" ); |
855 | |
856 | /* At this point, server sent 1 byte. */ |
857 | fds.fd = fd; |
858 | poll_flags = POLLIN | POLLRDNORM; |
859 | fds.events = poll_flags; |
860 | |
861 | /* Try to wait for 1 sec. */ |
862 | if (poll(&fds, 1, 1000) < 0) { |
863 | perror("poll" ); |
864 | exit(EXIT_FAILURE); |
865 | } |
866 | |
867 | /* poll() must return nothing. */ |
868 | if (fds.revents) { |
869 | fprintf(stderr, "Unexpected poll result %hx\n" , |
870 | fds.revents); |
871 | exit(EXIT_FAILURE); |
872 | } |
873 | |
874 | /* Tell server to send rest of data. */ |
875 | control_writeln(str: "CLNSENT" ); |
876 | |
877 | /* Poll for data. */ |
878 | if (poll(&fds, 1, 10000) < 0) { |
879 | perror("poll" ); |
880 | exit(EXIT_FAILURE); |
881 | } |
882 | |
883 | /* Only these two bits are expected. */ |
884 | if (fds.revents != poll_flags) { |
885 | fprintf(stderr, "Unexpected poll result %hx\n" , |
886 | fds.revents); |
887 | exit(EXIT_FAILURE); |
888 | } |
889 | |
890 | /* Use MSG_DONTWAIT, if call is going to wait, EAGAIN |
891 | * will be returned. |
892 | */ |
893 | recv_buf(fd, buf, len: sizeof(buf), MSG_DONTWAIT, RCVLOWAT_BUF_SIZE); |
894 | |
895 | control_writeln(str: "POLLDONE" ); |
896 | |
897 | close(fd); |
898 | } |
899 | |
900 | #define INV_BUF_TEST_DATA_LEN 512 |
901 | |
902 | static void test_inv_buf_client(const struct test_opts *opts, bool stream) |
903 | { |
904 | unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; |
905 | ssize_t expected_ret; |
906 | int fd; |
907 | |
908 | if (stream) |
909 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
910 | else |
911 | fd = vsock_seqpacket_connect(cid: opts->peer_cid, port: opts->peer_port); |
912 | |
913 | if (fd < 0) { |
914 | perror("connect" ); |
915 | exit(EXIT_FAILURE); |
916 | } |
917 | |
918 | control_expectln(str: "SENDDONE" ); |
919 | |
920 | /* Use invalid buffer here. */ |
921 | recv_buf(fd, NULL, len: sizeof(data), flags: 0, expected_ret: -EFAULT); |
922 | |
923 | if (stream) { |
924 | /* For SOCK_STREAM we must continue reading. */ |
925 | expected_ret = sizeof(data); |
926 | } else { |
927 | /* For SOCK_SEQPACKET socket's queue must be empty. */ |
928 | expected_ret = -EAGAIN; |
929 | } |
930 | |
931 | recv_buf(fd, buf: data, len: sizeof(data), MSG_DONTWAIT, expected_ret); |
932 | |
933 | control_writeln(str: "DONE" ); |
934 | |
935 | close(fd); |
936 | } |
937 | |
938 | static void test_inv_buf_server(const struct test_opts *opts, bool stream) |
939 | { |
940 | unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; |
941 | int fd; |
942 | |
943 | if (stream) |
944 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
945 | else |
946 | fd = vsock_seqpacket_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
947 | |
948 | if (fd < 0) { |
949 | perror("accept" ); |
950 | exit(EXIT_FAILURE); |
951 | } |
952 | |
953 | send_buf(fd, buf: data, len: sizeof(data), flags: 0, expected_ret: sizeof(data)); |
954 | |
955 | control_writeln(str: "SENDDONE" ); |
956 | |
957 | control_expectln(str: "DONE" ); |
958 | |
959 | close(fd); |
960 | } |
961 | |
962 | static void test_stream_inv_buf_client(const struct test_opts *opts) |
963 | { |
964 | test_inv_buf_client(opts, stream: true); |
965 | } |
966 | |
967 | static void test_stream_inv_buf_server(const struct test_opts *opts) |
968 | { |
969 | test_inv_buf_server(opts, stream: true); |
970 | } |
971 | |
972 | static void test_seqpacket_inv_buf_client(const struct test_opts *opts) |
973 | { |
974 | test_inv_buf_client(opts, stream: false); |
975 | } |
976 | |
977 | static void test_seqpacket_inv_buf_server(const struct test_opts *opts) |
978 | { |
979 | test_inv_buf_server(opts, stream: false); |
980 | } |
981 | |
982 | #define HELLO_STR "HELLO" |
983 | #define WORLD_STR "WORLD" |
984 | |
985 | static void test_stream_virtio_skb_merge_client(const struct test_opts *opts) |
986 | { |
987 | int fd; |
988 | |
989 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
990 | if (fd < 0) { |
991 | perror("connect" ); |
992 | exit(EXIT_FAILURE); |
993 | } |
994 | |
995 | /* Send first skbuff. */ |
996 | send_buf(fd, HELLO_STR, strlen(HELLO_STR), flags: 0, strlen(HELLO_STR)); |
997 | |
998 | control_writeln(str: "SEND0" ); |
999 | /* Peer reads part of first skbuff. */ |
1000 | control_expectln(str: "REPLY0" ); |
1001 | |
1002 | /* Send second skbuff, it will be appended to the first. */ |
1003 | send_buf(fd, WORLD_STR, strlen(WORLD_STR), flags: 0, strlen(WORLD_STR)); |
1004 | |
1005 | control_writeln(str: "SEND1" ); |
1006 | /* Peer reads merged skbuff packet. */ |
1007 | control_expectln(str: "REPLY1" ); |
1008 | |
1009 | close(fd); |
1010 | } |
1011 | |
1012 | static void test_stream_virtio_skb_merge_server(const struct test_opts *opts) |
1013 | { |
1014 | size_t read = 0, to_read; |
1015 | unsigned char buf[64]; |
1016 | int fd; |
1017 | |
1018 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
1019 | if (fd < 0) { |
1020 | perror("accept" ); |
1021 | exit(EXIT_FAILURE); |
1022 | } |
1023 | |
1024 | control_expectln(str: "SEND0" ); |
1025 | |
1026 | /* Read skbuff partially. */ |
1027 | to_read = 2; |
1028 | recv_buf(fd, buf: buf + read, len: to_read, flags: 0, expected_ret: to_read); |
1029 | read += to_read; |
1030 | |
1031 | control_writeln(str: "REPLY0" ); |
1032 | control_expectln(str: "SEND1" ); |
1033 | |
1034 | /* Read the rest of both buffers */ |
1035 | to_read = strlen(HELLO_STR WORLD_STR) - read; |
1036 | recv_buf(fd, buf: buf + read, len: to_read, flags: 0, expected_ret: to_read); |
1037 | read += to_read; |
1038 | |
1039 | /* No more bytes should be there */ |
1040 | to_read = sizeof(buf) - read; |
1041 | recv_buf(fd, buf: buf + read, len: to_read, MSG_DONTWAIT, expected_ret: -EAGAIN); |
1042 | |
1043 | if (memcmp(p: buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) { |
1044 | fprintf(stderr, "pattern mismatch\n" ); |
1045 | exit(EXIT_FAILURE); |
1046 | } |
1047 | |
1048 | control_writeln(str: "REPLY1" ); |
1049 | |
1050 | close(fd); |
1051 | } |
1052 | |
1053 | static void test_seqpacket_msg_peek_client(const struct test_opts *opts) |
1054 | { |
1055 | return test_msg_peek_client(opts, seqpacket: true); |
1056 | } |
1057 | |
1058 | static void test_seqpacket_msg_peek_server(const struct test_opts *opts) |
1059 | { |
1060 | return test_msg_peek_server(opts, seqpacket: true); |
1061 | } |
1062 | |
1063 | static sig_atomic_t have_sigpipe; |
1064 | |
1065 | static void sigpipe(int signo) |
1066 | { |
1067 | have_sigpipe = 1; |
1068 | } |
1069 | |
1070 | static void test_stream_check_sigpipe(int fd) |
1071 | { |
1072 | ssize_t res; |
1073 | |
1074 | have_sigpipe = 0; |
1075 | |
1076 | res = send(fd, "A" , 1, 0); |
1077 | if (res != -1) { |
1078 | fprintf(stderr, "expected send(2) failure, got %zi\n" , res); |
1079 | exit(EXIT_FAILURE); |
1080 | } |
1081 | |
1082 | if (!have_sigpipe) { |
1083 | fprintf(stderr, "SIGPIPE expected\n" ); |
1084 | exit(EXIT_FAILURE); |
1085 | } |
1086 | |
1087 | have_sigpipe = 0; |
1088 | |
1089 | res = send(fd, "A" , 1, MSG_NOSIGNAL); |
1090 | if (res != -1) { |
1091 | fprintf(stderr, "expected send(2) failure, got %zi\n" , res); |
1092 | exit(EXIT_FAILURE); |
1093 | } |
1094 | |
1095 | if (have_sigpipe) { |
1096 | fprintf(stderr, "SIGPIPE not expected\n" ); |
1097 | exit(EXIT_FAILURE); |
1098 | } |
1099 | } |
1100 | |
1101 | static void test_stream_shutwr_client(const struct test_opts *opts) |
1102 | { |
1103 | int fd; |
1104 | |
1105 | struct sigaction act = { |
1106 | .sa_handler = sigpipe, |
1107 | }; |
1108 | |
1109 | sigaction(SIGPIPE, &act, NULL); |
1110 | |
1111 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
1112 | if (fd < 0) { |
1113 | perror("connect" ); |
1114 | exit(EXIT_FAILURE); |
1115 | } |
1116 | |
1117 | if (shutdown(fd, SHUT_WR)) { |
1118 | perror("shutdown" ); |
1119 | exit(EXIT_FAILURE); |
1120 | } |
1121 | |
1122 | test_stream_check_sigpipe(fd); |
1123 | |
1124 | control_writeln(str: "CLIENTDONE" ); |
1125 | |
1126 | close(fd); |
1127 | } |
1128 | |
1129 | static void test_stream_shutwr_server(const struct test_opts *opts) |
1130 | { |
1131 | int fd; |
1132 | |
1133 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
1134 | if (fd < 0) { |
1135 | perror("accept" ); |
1136 | exit(EXIT_FAILURE); |
1137 | } |
1138 | |
1139 | control_expectln(str: "CLIENTDONE" ); |
1140 | |
1141 | close(fd); |
1142 | } |
1143 | |
1144 | static void test_stream_shutrd_client(const struct test_opts *opts) |
1145 | { |
1146 | int fd; |
1147 | |
1148 | struct sigaction act = { |
1149 | .sa_handler = sigpipe, |
1150 | }; |
1151 | |
1152 | sigaction(SIGPIPE, &act, NULL); |
1153 | |
1154 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
1155 | if (fd < 0) { |
1156 | perror("connect" ); |
1157 | exit(EXIT_FAILURE); |
1158 | } |
1159 | |
1160 | control_expectln(str: "SHUTRDDONE" ); |
1161 | |
1162 | test_stream_check_sigpipe(fd); |
1163 | |
1164 | control_writeln(str: "CLIENTDONE" ); |
1165 | |
1166 | close(fd); |
1167 | } |
1168 | |
1169 | static void test_stream_shutrd_server(const struct test_opts *opts) |
1170 | { |
1171 | int fd; |
1172 | |
1173 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
1174 | if (fd < 0) { |
1175 | perror("accept" ); |
1176 | exit(EXIT_FAILURE); |
1177 | } |
1178 | |
1179 | if (shutdown(fd, SHUT_RD)) { |
1180 | perror("shutdown" ); |
1181 | exit(EXIT_FAILURE); |
1182 | } |
1183 | |
1184 | control_writeln(str: "SHUTRDDONE" ); |
1185 | control_expectln(str: "CLIENTDONE" ); |
1186 | |
1187 | close(fd); |
1188 | } |
1189 | |
1190 | static void test_double_bind_connect_server(const struct test_opts *opts) |
1191 | { |
1192 | int listen_fd, client_fd, i; |
1193 | struct sockaddr_vm sa_client; |
1194 | socklen_t socklen_client = sizeof(sa_client); |
1195 | |
1196 | listen_fd = vsock_stream_listen(VMADDR_CID_ANY, port: opts->peer_port); |
1197 | |
1198 | for (i = 0; i < 2; i++) { |
1199 | control_writeln(str: "LISTENING" ); |
1200 | |
1201 | timeout_begin(seconds: TIMEOUT); |
1202 | do { |
1203 | client_fd = accept(listen_fd, (struct sockaddr *)&sa_client, |
1204 | &socklen_client); |
1205 | timeout_check(operation: "accept" ); |
1206 | } while (client_fd < 0 && errno == EINTR); |
1207 | timeout_end(); |
1208 | |
1209 | if (client_fd < 0) { |
1210 | perror("accept" ); |
1211 | exit(EXIT_FAILURE); |
1212 | } |
1213 | |
1214 | /* Waiting for remote peer to close connection */ |
1215 | vsock_wait_remote_close(fd: client_fd); |
1216 | } |
1217 | |
1218 | close(listen_fd); |
1219 | } |
1220 | |
1221 | static void test_double_bind_connect_client(const struct test_opts *opts) |
1222 | { |
1223 | int i, client_fd; |
1224 | |
1225 | for (i = 0; i < 2; i++) { |
1226 | /* Wait until server is ready to accept a new connection */ |
1227 | control_expectln(str: "LISTENING" ); |
1228 | |
1229 | /* We use 'peer_port + 1' as "some" port for the 'bind()' |
1230 | * call. It is safe for overflow, but must be considered, |
1231 | * when running multiple test applications simultaneously |
1232 | * where 'peer-port' argument differs by 1. |
1233 | */ |
1234 | client_fd = vsock_bind_connect(opts->peer_cid, opts->peer_port, |
1235 | opts->peer_port + 1, SOCK_STREAM); |
1236 | |
1237 | close(client_fd); |
1238 | } |
1239 | } |
1240 | |
1241 | #define RCVLOWAT_CREDIT_UPD_BUF_SIZE (1024 * 128) |
1242 | /* This define is the same as in 'include/linux/virtio_vsock.h': |
1243 | * it is used to decide when to send credit update message during |
1244 | * reading from rx queue of a socket. Value and its usage in |
1245 | * kernel is important for this test. |
1246 | */ |
1247 | #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64) |
1248 | |
1249 | static void test_stream_rcvlowat_def_cred_upd_client(const struct test_opts *opts) |
1250 | { |
1251 | size_t buf_size; |
1252 | void *buf; |
1253 | int fd; |
1254 | |
1255 | fd = vsock_stream_connect(cid: opts->peer_cid, port: opts->peer_port); |
1256 | if (fd < 0) { |
1257 | perror("connect" ); |
1258 | exit(EXIT_FAILURE); |
1259 | } |
1260 | |
1261 | /* Send 1 byte more than peer's buffer size. */ |
1262 | buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE + 1; |
1263 | |
1264 | buf = malloc(buf_size); |
1265 | if (!buf) { |
1266 | perror("malloc" ); |
1267 | exit(EXIT_FAILURE); |
1268 | } |
1269 | |
1270 | /* Wait until peer sets needed buffer size. */ |
1271 | recv_byte(fd, expected_ret: 1, flags: 0); |
1272 | |
1273 | if (send(fd, buf, buf_size, 0) != buf_size) { |
1274 | perror("send failed" ); |
1275 | exit(EXIT_FAILURE); |
1276 | } |
1277 | |
1278 | free(buf); |
1279 | close(fd); |
1280 | } |
1281 | |
1282 | static void test_stream_credit_update_test(const struct test_opts *opts, |
1283 | bool low_rx_bytes_test) |
1284 | { |
1285 | size_t recv_buf_size; |
1286 | struct pollfd fds; |
1287 | size_t buf_size; |
1288 | void *buf; |
1289 | int fd; |
1290 | |
1291 | fd = vsock_stream_accept(VMADDR_CID_ANY, port: opts->peer_port, NULL); |
1292 | if (fd < 0) { |
1293 | perror("accept" ); |
1294 | exit(EXIT_FAILURE); |
1295 | } |
1296 | |
1297 | buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE; |
1298 | |
1299 | if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, |
1300 | &buf_size, sizeof(buf_size))) { |
1301 | perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)" ); |
1302 | exit(EXIT_FAILURE); |
1303 | } |
1304 | |
1305 | if (low_rx_bytes_test) { |
1306 | /* Set new SO_RCVLOWAT here. This enables sending credit |
1307 | * update when number of bytes if our rx queue become < |
1308 | * SO_RCVLOWAT value. |
1309 | */ |
1310 | recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE; |
1311 | |
1312 | if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, |
1313 | &recv_buf_size, sizeof(recv_buf_size))) { |
1314 | perror("setsockopt(SO_RCVLOWAT)" ); |
1315 | exit(EXIT_FAILURE); |
1316 | } |
1317 | } |
1318 | |
1319 | /* Send one dummy byte here, because 'setsockopt()' above also |
1320 | * sends special packet which tells sender to update our buffer |
1321 | * size. This 'send_byte()' will serialize such packet with data |
1322 | * reads in a loop below. Sender starts transmission only when |
1323 | * it receives this single byte. |
1324 | */ |
1325 | send_byte(fd, expected_ret: 1, flags: 0); |
1326 | |
1327 | buf = malloc(buf_size); |
1328 | if (!buf) { |
1329 | perror("malloc" ); |
1330 | exit(EXIT_FAILURE); |
1331 | } |
1332 | |
1333 | /* Wait until there will be 128KB of data in rx queue. */ |
1334 | while (1) { |
1335 | ssize_t res; |
1336 | |
1337 | res = recv(fd, buf, buf_size, MSG_PEEK); |
1338 | if (res == buf_size) |
1339 | break; |
1340 | |
1341 | if (res <= 0) { |
1342 | fprintf(stderr, "unexpected 'recv()' return: %zi\n" , res); |
1343 | exit(EXIT_FAILURE); |
1344 | } |
1345 | } |
1346 | |
1347 | /* There is 128KB of data in the socket's rx queue, dequeue first |
1348 | * 64KB, credit update is sent if 'low_rx_bytes_test' == true. |
1349 | * Otherwise, credit update is sent in 'if (!low_rx_bytes_test)'. |
1350 | */ |
1351 | recv_buf_size = VIRTIO_VSOCK_MAX_PKT_BUF_SIZE; |
1352 | recv_buf(fd, buf, len: recv_buf_size, flags: 0, expected_ret: recv_buf_size); |
1353 | |
1354 | if (!low_rx_bytes_test) { |
1355 | recv_buf_size++; |
1356 | |
1357 | /* Updating SO_RCVLOWAT will send credit update. */ |
1358 | if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, |
1359 | &recv_buf_size, sizeof(recv_buf_size))) { |
1360 | perror("setsockopt(SO_RCVLOWAT)" ); |
1361 | exit(EXIT_FAILURE); |
1362 | } |
1363 | } |
1364 | |
1365 | fds.fd = fd; |
1366 | fds.events = POLLIN | POLLRDNORM | POLLERR | |
1367 | POLLRDHUP | POLLHUP; |
1368 | |
1369 | /* This 'poll()' will return once we receive last byte |
1370 | * sent by client. |
1371 | */ |
1372 | if (poll(&fds, 1, -1) < 0) { |
1373 | perror("poll" ); |
1374 | exit(EXIT_FAILURE); |
1375 | } |
1376 | |
1377 | if (fds.revents & POLLERR) { |
1378 | fprintf(stderr, "'poll()' error\n" ); |
1379 | exit(EXIT_FAILURE); |
1380 | } |
1381 | |
1382 | if (fds.revents & (POLLIN | POLLRDNORM)) { |
1383 | recv_buf(fd, buf, len: recv_buf_size, MSG_DONTWAIT, expected_ret: recv_buf_size); |
1384 | } else { |
1385 | /* These flags must be set, as there is at |
1386 | * least 64KB of data ready to read. |
1387 | */ |
1388 | fprintf(stderr, "POLLIN | POLLRDNORM expected\n" ); |
1389 | exit(EXIT_FAILURE); |
1390 | } |
1391 | |
1392 | free(buf); |
1393 | close(fd); |
1394 | } |
1395 | |
1396 | static void test_stream_cred_upd_on_low_rx_bytes(const struct test_opts *opts) |
1397 | { |
1398 | test_stream_credit_update_test(opts, low_rx_bytes_test: true); |
1399 | } |
1400 | |
1401 | static void test_stream_cred_upd_on_set_rcvlowat(const struct test_opts *opts) |
1402 | { |
1403 | test_stream_credit_update_test(opts, low_rx_bytes_test: false); |
1404 | } |
1405 | |
1406 | static struct test_case test_cases[] = { |
1407 | { |
1408 | .name = "SOCK_STREAM connection reset" , |
1409 | .run_client = test_stream_connection_reset, |
1410 | }, |
1411 | { |
1412 | .name = "SOCK_STREAM bind only" , |
1413 | .run_client = test_stream_bind_only_client, |
1414 | .run_server = test_stream_bind_only_server, |
1415 | }, |
1416 | { |
1417 | .name = "SOCK_STREAM client close" , |
1418 | .run_client = test_stream_client_close_client, |
1419 | .run_server = test_stream_client_close_server, |
1420 | }, |
1421 | { |
1422 | .name = "SOCK_STREAM server close" , |
1423 | .run_client = test_stream_server_close_client, |
1424 | .run_server = test_stream_server_close_server, |
1425 | }, |
1426 | { |
1427 | .name = "SOCK_STREAM multiple connections" , |
1428 | .run_client = test_stream_multiconn_client, |
1429 | .run_server = test_stream_multiconn_server, |
1430 | }, |
1431 | { |
1432 | .name = "SOCK_STREAM MSG_PEEK" , |
1433 | .run_client = test_stream_msg_peek_client, |
1434 | .run_server = test_stream_msg_peek_server, |
1435 | }, |
1436 | { |
1437 | .name = "SOCK_SEQPACKET msg bounds" , |
1438 | .run_client = test_seqpacket_msg_bounds_client, |
1439 | .run_server = test_seqpacket_msg_bounds_server, |
1440 | }, |
1441 | { |
1442 | .name = "SOCK_SEQPACKET MSG_TRUNC flag" , |
1443 | .run_client = test_seqpacket_msg_trunc_client, |
1444 | .run_server = test_seqpacket_msg_trunc_server, |
1445 | }, |
1446 | { |
1447 | .name = "SOCK_SEQPACKET timeout" , |
1448 | .run_client = test_seqpacket_timeout_client, |
1449 | .run_server = test_seqpacket_timeout_server, |
1450 | }, |
1451 | { |
1452 | .name = "SOCK_SEQPACKET invalid receive buffer" , |
1453 | .run_client = test_seqpacket_invalid_rec_buffer_client, |
1454 | .run_server = test_seqpacket_invalid_rec_buffer_server, |
1455 | }, |
1456 | { |
1457 | .name = "SOCK_STREAM poll() + SO_RCVLOWAT" , |
1458 | .run_client = test_stream_poll_rcvlowat_client, |
1459 | .run_server = test_stream_poll_rcvlowat_server, |
1460 | }, |
1461 | { |
1462 | .name = "SOCK_SEQPACKET big message" , |
1463 | .run_client = test_seqpacket_bigmsg_client, |
1464 | .run_server = test_seqpacket_bigmsg_server, |
1465 | }, |
1466 | { |
1467 | .name = "SOCK_STREAM test invalid buffer" , |
1468 | .run_client = test_stream_inv_buf_client, |
1469 | .run_server = test_stream_inv_buf_server, |
1470 | }, |
1471 | { |
1472 | .name = "SOCK_SEQPACKET test invalid buffer" , |
1473 | .run_client = test_seqpacket_inv_buf_client, |
1474 | .run_server = test_seqpacket_inv_buf_server, |
1475 | }, |
1476 | { |
1477 | .name = "SOCK_STREAM virtio skb merge" , |
1478 | .run_client = test_stream_virtio_skb_merge_client, |
1479 | .run_server = test_stream_virtio_skb_merge_server, |
1480 | }, |
1481 | { |
1482 | .name = "SOCK_SEQPACKET MSG_PEEK" , |
1483 | .run_client = test_seqpacket_msg_peek_client, |
1484 | .run_server = test_seqpacket_msg_peek_server, |
1485 | }, |
1486 | { |
1487 | .name = "SOCK_STREAM SHUT_WR" , |
1488 | .run_client = test_stream_shutwr_client, |
1489 | .run_server = test_stream_shutwr_server, |
1490 | }, |
1491 | { |
1492 | .name = "SOCK_STREAM SHUT_RD" , |
1493 | .run_client = test_stream_shutrd_client, |
1494 | .run_server = test_stream_shutrd_server, |
1495 | }, |
1496 | { |
1497 | .name = "SOCK_STREAM MSG_ZEROCOPY" , |
1498 | .run_client = test_stream_msgzcopy_client, |
1499 | .run_server = test_stream_msgzcopy_server, |
1500 | }, |
1501 | { |
1502 | .name = "SOCK_SEQPACKET MSG_ZEROCOPY" , |
1503 | .run_client = test_seqpacket_msgzcopy_client, |
1504 | .run_server = test_seqpacket_msgzcopy_server, |
1505 | }, |
1506 | { |
1507 | .name = "SOCK_STREAM MSG_ZEROCOPY empty MSG_ERRQUEUE" , |
1508 | .run_client = test_stream_msgzcopy_empty_errq_client, |
1509 | .run_server = test_stream_msgzcopy_empty_errq_server, |
1510 | }, |
1511 | { |
1512 | .name = "SOCK_STREAM double bind connect" , |
1513 | .run_client = test_double_bind_connect_client, |
1514 | .run_server = test_double_bind_connect_server, |
1515 | }, |
1516 | { |
1517 | .name = "SOCK_STREAM virtio credit update + SO_RCVLOWAT" , |
1518 | .run_client = test_stream_rcvlowat_def_cred_upd_client, |
1519 | .run_server = test_stream_cred_upd_on_set_rcvlowat, |
1520 | }, |
1521 | { |
1522 | .name = "SOCK_STREAM virtio credit update + low rx_bytes" , |
1523 | .run_client = test_stream_rcvlowat_def_cred_upd_client, |
1524 | .run_server = test_stream_cred_upd_on_low_rx_bytes, |
1525 | }, |
1526 | {}, |
1527 | }; |
1528 | |
1529 | static const char optstring[] = "" ; |
1530 | static const struct option longopts[] = { |
1531 | { |
1532 | .name = "control-host" , |
1533 | .has_arg = required_argument, |
1534 | .val = 'H', |
1535 | }, |
1536 | { |
1537 | .name = "control-port" , |
1538 | .has_arg = required_argument, |
1539 | .val = 'P', |
1540 | }, |
1541 | { |
1542 | .name = "mode" , |
1543 | .has_arg = required_argument, |
1544 | .val = 'm', |
1545 | }, |
1546 | { |
1547 | .name = "peer-cid" , |
1548 | .has_arg = required_argument, |
1549 | .val = 'p', |
1550 | }, |
1551 | { |
1552 | .name = "peer-port" , |
1553 | .has_arg = required_argument, |
1554 | .val = 'q', |
1555 | }, |
1556 | { |
1557 | .name = "list" , |
1558 | .has_arg = no_argument, |
1559 | .val = 'l', |
1560 | }, |
1561 | { |
1562 | .name = "skip" , |
1563 | .has_arg = required_argument, |
1564 | .val = 's', |
1565 | }, |
1566 | { |
1567 | .name = "help" , |
1568 | .has_arg = no_argument, |
1569 | .val = '?', |
1570 | }, |
1571 | {}, |
1572 | }; |
1573 | |
1574 | static void usage(void) |
1575 | { |
1576 | fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--peer-port=<port>] [--list] [--skip=<test_id>]\n" |
1577 | "\n" |
1578 | " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n" |
1579 | " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" |
1580 | "\n" |
1581 | "Run vsock.ko tests. Must be launched in both guest\n" |
1582 | "and host. One side must use --mode=client and\n" |
1583 | "the other side must use --mode=server.\n" |
1584 | "\n" |
1585 | "A TCP control socket connection is used to coordinate tests\n" |
1586 | "between the client and the server. The server requires a\n" |
1587 | "listen address and the client requires an address to\n" |
1588 | "connect to.\n" |
1589 | "\n" |
1590 | "The CID of the other side must be given with --peer-cid=<cid>.\n" |
1591 | "During the test, two AF_VSOCK ports will be used: the port\n" |
1592 | "specified with --peer-port=<port> (or the default port)\n" |
1593 | "and the next one.\n" |
1594 | "\n" |
1595 | "Options:\n" |
1596 | " --help This help message\n" |
1597 | " --control-host <host> Server IP address to connect to\n" |
1598 | " --control-port <port> Server port to listen on/connect to\n" |
1599 | " --mode client|server Server or client mode\n" |
1600 | " --peer-cid <cid> CID of the other side\n" |
1601 | " --peer-port <port> AF_VSOCK port used for the test [default: %d]\n" |
1602 | " --list List of tests that will be executed\n" |
1603 | " --skip <test_id> Test ID to skip;\n" |
1604 | " use multiple --skip options to skip more tests\n" , |
1605 | DEFAULT_PEER_PORT |
1606 | ); |
1607 | exit(EXIT_FAILURE); |
1608 | } |
1609 | |
1610 | int main(int argc, char **argv) |
1611 | { |
1612 | const char *control_host = NULL; |
1613 | const char *control_port = NULL; |
1614 | struct test_opts opts = { |
1615 | .mode = TEST_MODE_UNSET, |
1616 | .peer_cid = VMADDR_CID_ANY, |
1617 | .peer_port = DEFAULT_PEER_PORT, |
1618 | }; |
1619 | |
1620 | srand(time(NULL)); |
1621 | init_signals(); |
1622 | |
1623 | for (;;) { |
1624 | int opt = getopt_long(argc, argv, optstring, longopts, NULL); |
1625 | |
1626 | if (opt == -1) |
1627 | break; |
1628 | |
1629 | switch (opt) { |
1630 | case 'H': |
1631 | control_host = optarg; |
1632 | break; |
1633 | case 'm': |
1634 | if (strcmp(optarg, "client" ) == 0) |
1635 | opts.mode = TEST_MODE_CLIENT; |
1636 | else if (strcmp(optarg, "server" ) == 0) |
1637 | opts.mode = TEST_MODE_SERVER; |
1638 | else { |
1639 | fprintf(stderr, "--mode must be \"client\" or \"server\"\n" ); |
1640 | return EXIT_FAILURE; |
1641 | } |
1642 | break; |
1643 | case 'p': |
1644 | opts.peer_cid = parse_cid(optarg); |
1645 | break; |
1646 | case 'q': |
1647 | opts.peer_port = parse_port(optarg); |
1648 | break; |
1649 | case 'P': |
1650 | control_port = optarg; |
1651 | break; |
1652 | case 'l': |
1653 | list_tests(test_cases); |
1654 | break; |
1655 | case 's': |
1656 | skip_test(test_cases, ARRAY_SIZE(test_cases) - 1, |
1657 | optarg); |
1658 | break; |
1659 | case '?': |
1660 | default: |
1661 | usage(); |
1662 | } |
1663 | } |
1664 | |
1665 | if (!control_port) |
1666 | usage(); |
1667 | if (opts.mode == TEST_MODE_UNSET) |
1668 | usage(); |
1669 | if (opts.peer_cid == VMADDR_CID_ANY) |
1670 | usage(); |
1671 | |
1672 | if (!control_host) { |
1673 | if (opts.mode != TEST_MODE_SERVER) |
1674 | usage(); |
1675 | control_host = "0.0.0.0" ; |
1676 | } |
1677 | |
1678 | control_init(control_host, control_port, |
1679 | server: opts.mode == TEST_MODE_SERVER); |
1680 | |
1681 | run_tests(test_cases, opts: &opts); |
1682 | |
1683 | control_cleanup(); |
1684 | return EXIT_SUCCESS; |
1685 | } |
1686 | |