Merge branch 'for-5.15-verbose-console' into for-linus
[linux-2.6-microblaze.git] / tools / testing / vsock / vsock_test.c
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
20 #include "timeout.h"
21 #include "control.h"
22 #include "util.h"
23
24 static void test_stream_connection_reset(const struct test_opts *opts)
25 {
26         union {
27                 struct sockaddr sa;
28                 struct sockaddr_vm svm;
29         } addr = {
30                 .svm = {
31                         .svm_family = AF_VSOCK,
32                         .svm_port = 1234,
33                         .svm_cid = opts->peer_cid,
34                 },
35         };
36         int ret;
37         int fd;
38
39         fd = socket(AF_VSOCK, SOCK_STREAM, 0);
40
41         timeout_begin(TIMEOUT);
42         do {
43                 ret = connect(fd, &addr.sa, sizeof(addr.svm));
44                 timeout_check("connect");
45         } while (ret < 0 && errno == EINTR);
46         timeout_end();
47
48         if (ret != -1) {
49                 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
50                 exit(EXIT_FAILURE);
51         }
52         if (errno != ECONNRESET) {
53                 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
54                 exit(EXIT_FAILURE);
55         }
56
57         close(fd);
58 }
59
60 static void test_stream_bind_only_client(const struct test_opts *opts)
61 {
62         union {
63                 struct sockaddr sa;
64                 struct sockaddr_vm svm;
65         } addr = {
66                 .svm = {
67                         .svm_family = AF_VSOCK,
68                         .svm_port = 1234,
69                         .svm_cid = opts->peer_cid,
70                 },
71         };
72         int ret;
73         int fd;
74
75         /* Wait for the server to be ready */
76         control_expectln("BIND");
77
78         fd = socket(AF_VSOCK, SOCK_STREAM, 0);
79
80         timeout_begin(TIMEOUT);
81         do {
82                 ret = connect(fd, &addr.sa, sizeof(addr.svm));
83                 timeout_check("connect");
84         } while (ret < 0 && errno == EINTR);
85         timeout_end();
86
87         if (ret != -1) {
88                 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
89                 exit(EXIT_FAILURE);
90         }
91         if (errno != ECONNRESET) {
92                 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
93                 exit(EXIT_FAILURE);
94         }
95
96         /* Notify the server that the client has finished */
97         control_writeln("DONE");
98
99         close(fd);
100 }
101
102 static void test_stream_bind_only_server(const struct test_opts *opts)
103 {
104         union {
105                 struct sockaddr sa;
106                 struct sockaddr_vm svm;
107         } addr = {
108                 .svm = {
109                         .svm_family = AF_VSOCK,
110                         .svm_port = 1234,
111                         .svm_cid = VMADDR_CID_ANY,
112                 },
113         };
114         int fd;
115
116         fd = socket(AF_VSOCK, SOCK_STREAM, 0);
117
118         if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
119                 perror("bind");
120                 exit(EXIT_FAILURE);
121         }
122
123         /* Notify the client that the server is ready */
124         control_writeln("BIND");
125
126         /* Wait for the client to finish */
127         control_expectln("DONE");
128
129         close(fd);
130 }
131
132 static void test_stream_client_close_client(const struct test_opts *opts)
133 {
134         int fd;
135
136         fd = vsock_stream_connect(opts->peer_cid, 1234);
137         if (fd < 0) {
138                 perror("connect");
139                 exit(EXIT_FAILURE);
140         }
141
142         send_byte(fd, 1, 0);
143         close(fd);
144 }
145
146 static void test_stream_client_close_server(const struct test_opts *opts)
147 {
148         int fd;
149
150         fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
151         if (fd < 0) {
152                 perror("accept");
153                 exit(EXIT_FAILURE);
154         }
155
156         /* Wait for the remote to close the connection, before check
157          * -EPIPE error on send.
158          */
159         vsock_wait_remote_close(fd);
160
161         send_byte(fd, -EPIPE, 0);
162         recv_byte(fd, 1, 0);
163         recv_byte(fd, 0, 0);
164         close(fd);
165 }
166
167 static void test_stream_server_close_client(const struct test_opts *opts)
168 {
169         int fd;
170
171         fd = vsock_stream_connect(opts->peer_cid, 1234);
172         if (fd < 0) {
173                 perror("connect");
174                 exit(EXIT_FAILURE);
175         }
176
177         /* Wait for the remote to close the connection, before check
178          * -EPIPE error on send.
179          */
180         vsock_wait_remote_close(fd);
181
182         send_byte(fd, -EPIPE, 0);
183         recv_byte(fd, 1, 0);
184         recv_byte(fd, 0, 0);
185         close(fd);
186 }
187
188 static void test_stream_server_close_server(const struct test_opts *opts)
189 {
190         int fd;
191
192         fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
193         if (fd < 0) {
194                 perror("accept");
195                 exit(EXIT_FAILURE);
196         }
197
198         send_byte(fd, 1, 0);
199         close(fd);
200 }
201
202 /* With the standard socket sizes, VMCI is able to support about 100
203  * concurrent stream connections.
204  */
205 #define MULTICONN_NFDS 100
206
207 static void test_stream_multiconn_client(const struct test_opts *opts)
208 {
209         int fds[MULTICONN_NFDS];
210         int i;
211
212         for (i = 0; i < MULTICONN_NFDS; i++) {
213                 fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
214                 if (fds[i] < 0) {
215                         perror("connect");
216                         exit(EXIT_FAILURE);
217                 }
218         }
219
220         for (i = 0; i < MULTICONN_NFDS; i++) {
221                 if (i % 2)
222                         recv_byte(fds[i], 1, 0);
223                 else
224                         send_byte(fds[i], 1, 0);
225         }
226
227         for (i = 0; i < MULTICONN_NFDS; i++)
228                 close(fds[i]);
229 }
230
231 static void test_stream_multiconn_server(const struct test_opts *opts)
232 {
233         int fds[MULTICONN_NFDS];
234         int i;
235
236         for (i = 0; i < MULTICONN_NFDS; i++) {
237                 fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
238                 if (fds[i] < 0) {
239                         perror("accept");
240                         exit(EXIT_FAILURE);
241                 }
242         }
243
244         for (i = 0; i < MULTICONN_NFDS; i++) {
245                 if (i % 2)
246                         send_byte(fds[i], 1, 0);
247                 else
248                         recv_byte(fds[i], 1, 0);
249         }
250
251         for (i = 0; i < MULTICONN_NFDS; i++)
252                 close(fds[i]);
253 }
254
255 static void test_stream_msg_peek_client(const struct test_opts *opts)
256 {
257         int fd;
258
259         fd = vsock_stream_connect(opts->peer_cid, 1234);
260         if (fd < 0) {
261                 perror("connect");
262                 exit(EXIT_FAILURE);
263         }
264
265         send_byte(fd, 1, 0);
266         close(fd);
267 }
268
269 static void test_stream_msg_peek_server(const struct test_opts *opts)
270 {
271         int fd;
272
273         fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
274         if (fd < 0) {
275                 perror("accept");
276                 exit(EXIT_FAILURE);
277         }
278
279         recv_byte(fd, 1, MSG_PEEK);
280         recv_byte(fd, 1, 0);
281         close(fd);
282 }
283
284 #define MESSAGES_CNT 7
285 static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
286 {
287         int fd;
288
289         fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
290         if (fd < 0) {
291                 perror("connect");
292                 exit(EXIT_FAILURE);
293         }
294
295         /* Send several messages, one with MSG_EOR flag */
296         for (int i = 0; i < MESSAGES_CNT; i++)
297                 send_byte(fd, 1, 0);
298
299         control_writeln("SENDDONE");
300         close(fd);
301 }
302
303 static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
304 {
305         int fd;
306         char buf[16];
307         struct msghdr msg = {0};
308         struct iovec iov = {0};
309
310         fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
311         if (fd < 0) {
312                 perror("accept");
313                 exit(EXIT_FAILURE);
314         }
315
316         control_expectln("SENDDONE");
317         iov.iov_base = buf;
318         iov.iov_len = sizeof(buf);
319         msg.msg_iov = &iov;
320         msg.msg_iovlen = 1;
321
322         for (int i = 0; i < MESSAGES_CNT; i++) {
323                 if (recvmsg(fd, &msg, 0) != 1) {
324                         perror("message bound violated");
325                         exit(EXIT_FAILURE);
326                 }
327         }
328
329         close(fd);
330 }
331
332 #define MESSAGE_TRUNC_SZ 32
333 static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
334 {
335         int fd;
336         char buf[MESSAGE_TRUNC_SZ];
337
338         fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
339         if (fd < 0) {
340                 perror("connect");
341                 exit(EXIT_FAILURE);
342         }
343
344         if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
345                 perror("send failed");
346                 exit(EXIT_FAILURE);
347         }
348
349         control_writeln("SENDDONE");
350         close(fd);
351 }
352
353 static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
354 {
355         int fd;
356         char buf[MESSAGE_TRUNC_SZ / 2];
357         struct msghdr msg = {0};
358         struct iovec iov = {0};
359
360         fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
361         if (fd < 0) {
362                 perror("accept");
363                 exit(EXIT_FAILURE);
364         }
365
366         control_expectln("SENDDONE");
367         iov.iov_base = buf;
368         iov.iov_len = sizeof(buf);
369         msg.msg_iov = &iov;
370         msg.msg_iovlen = 1;
371
372         ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
373
374         if (ret != MESSAGE_TRUNC_SZ) {
375                 printf("%zi\n", ret);
376                 perror("MSG_TRUNC doesn't work");
377                 exit(EXIT_FAILURE);
378         }
379
380         if (!(msg.msg_flags & MSG_TRUNC)) {
381                 fprintf(stderr, "MSG_TRUNC expected\n");
382                 exit(EXIT_FAILURE);
383         }
384
385         close(fd);
386 }
387
388 static struct test_case test_cases[] = {
389         {
390                 .name = "SOCK_STREAM connection reset",
391                 .run_client = test_stream_connection_reset,
392         },
393         {
394                 .name = "SOCK_STREAM bind only",
395                 .run_client = test_stream_bind_only_client,
396                 .run_server = test_stream_bind_only_server,
397         },
398         {
399                 .name = "SOCK_STREAM client close",
400                 .run_client = test_stream_client_close_client,
401                 .run_server = test_stream_client_close_server,
402         },
403         {
404                 .name = "SOCK_STREAM server close",
405                 .run_client = test_stream_server_close_client,
406                 .run_server = test_stream_server_close_server,
407         },
408         {
409                 .name = "SOCK_STREAM multiple connections",
410                 .run_client = test_stream_multiconn_client,
411                 .run_server = test_stream_multiconn_server,
412         },
413         {
414                 .name = "SOCK_STREAM MSG_PEEK",
415                 .run_client = test_stream_msg_peek_client,
416                 .run_server = test_stream_msg_peek_server,
417         },
418         {
419                 .name = "SOCK_SEQPACKET msg bounds",
420                 .run_client = test_seqpacket_msg_bounds_client,
421                 .run_server = test_seqpacket_msg_bounds_server,
422         },
423         {
424                 .name = "SOCK_SEQPACKET MSG_TRUNC flag",
425                 .run_client = test_seqpacket_msg_trunc_client,
426                 .run_server = test_seqpacket_msg_trunc_server,
427         },
428         {},
429 };
430
431 static const char optstring[] = "";
432 static const struct option longopts[] = {
433         {
434                 .name = "control-host",
435                 .has_arg = required_argument,
436                 .val = 'H',
437         },
438         {
439                 .name = "control-port",
440                 .has_arg = required_argument,
441                 .val = 'P',
442         },
443         {
444                 .name = "mode",
445                 .has_arg = required_argument,
446                 .val = 'm',
447         },
448         {
449                 .name = "peer-cid",
450                 .has_arg = required_argument,
451                 .val = 'p',
452         },
453         {
454                 .name = "list",
455                 .has_arg = no_argument,
456                 .val = 'l',
457         },
458         {
459                 .name = "skip",
460                 .has_arg = required_argument,
461                 .val = 's',
462         },
463         {
464                 .name = "help",
465                 .has_arg = no_argument,
466                 .val = '?',
467         },
468         {},
469 };
470
471 static void usage(void)
472 {
473         fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
474                 "\n"
475                 "  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
476                 "  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
477                 "\n"
478                 "Run vsock.ko tests.  Must be launched in both guest\n"
479                 "and host.  One side must use --mode=client and\n"
480                 "the other side must use --mode=server.\n"
481                 "\n"
482                 "A TCP control socket connection is used to coordinate tests\n"
483                 "between the client and the server.  The server requires a\n"
484                 "listen address and the client requires an address to\n"
485                 "connect to.\n"
486                 "\n"
487                 "The CID of the other side must be given with --peer-cid=<cid>.\n"
488                 "\n"
489                 "Options:\n"
490                 "  --help                 This help message\n"
491                 "  --control-host <host>  Server IP address to connect to\n"
492                 "  --control-port <port>  Server port to listen on/connect to\n"
493                 "  --mode client|server   Server or client mode\n"
494                 "  --peer-cid <cid>       CID of the other side\n"
495                 "  --list                 List of tests that will be executed\n"
496                 "  --skip <test_id>       Test ID to skip;\n"
497                 "                         use multiple --skip options to skip more tests\n"
498                 );
499         exit(EXIT_FAILURE);
500 }
501
502 int main(int argc, char **argv)
503 {
504         const char *control_host = NULL;
505         const char *control_port = NULL;
506         struct test_opts opts = {
507                 .mode = TEST_MODE_UNSET,
508                 .peer_cid = VMADDR_CID_ANY,
509         };
510
511         init_signals();
512
513         for (;;) {
514                 int opt = getopt_long(argc, argv, optstring, longopts, NULL);
515
516                 if (opt == -1)
517                         break;
518
519                 switch (opt) {
520                 case 'H':
521                         control_host = optarg;
522                         break;
523                 case 'm':
524                         if (strcmp(optarg, "client") == 0)
525                                 opts.mode = TEST_MODE_CLIENT;
526                         else if (strcmp(optarg, "server") == 0)
527                                 opts.mode = TEST_MODE_SERVER;
528                         else {
529                                 fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
530                                 return EXIT_FAILURE;
531                         }
532                         break;
533                 case 'p':
534                         opts.peer_cid = parse_cid(optarg);
535                         break;
536                 case 'P':
537                         control_port = optarg;
538                         break;
539                 case 'l':
540                         list_tests(test_cases);
541                         break;
542                 case 's':
543                         skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
544                                   optarg);
545                         break;
546                 case '?':
547                 default:
548                         usage();
549                 }
550         }
551
552         if (!control_port)
553                 usage();
554         if (opts.mode == TEST_MODE_UNSET)
555                 usage();
556         if (opts.peer_cid == VMADDR_CID_ANY)
557                 usage();
558
559         if (!control_host) {
560                 if (opts.mode != TEST_MODE_SERVER)
561                         usage();
562                 control_host = "0.0.0.0";
563         }
564
565         control_init(control_host, control_port,
566                      opts.mode == TEST_MODE_SERVER);
567
568         run_tests(test_cases, &opts);
569
570         control_cleanup();
571         return EXIT_SUCCESS;
572 }