Merge tag 'devicetree-fixes-for-5.13-2' of git://git.kernel.org/pub/scm/linux/kernel...
[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
18 #include "timeout.h"
19 #include "control.h"
20 #include "util.h"
21
22 static void test_stream_connection_reset(const struct test_opts *opts)
23 {
24         union {
25                 struct sockaddr sa;
26                 struct sockaddr_vm svm;
27         } addr = {
28                 .svm = {
29                         .svm_family = AF_VSOCK,
30                         .svm_port = 1234,
31                         .svm_cid = opts->peer_cid,
32                 },
33         };
34         int ret;
35         int fd;
36
37         fd = socket(AF_VSOCK, SOCK_STREAM, 0);
38
39         timeout_begin(TIMEOUT);
40         do {
41                 ret = connect(fd, &addr.sa, sizeof(addr.svm));
42                 timeout_check("connect");
43         } while (ret < 0 && errno == EINTR);
44         timeout_end();
45
46         if (ret != -1) {
47                 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
48                 exit(EXIT_FAILURE);
49         }
50         if (errno != ECONNRESET) {
51                 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
52                 exit(EXIT_FAILURE);
53         }
54
55         close(fd);
56 }
57
58 static void test_stream_bind_only_client(const struct test_opts *opts)
59 {
60         union {
61                 struct sockaddr sa;
62                 struct sockaddr_vm svm;
63         } addr = {
64                 .svm = {
65                         .svm_family = AF_VSOCK,
66                         .svm_port = 1234,
67                         .svm_cid = opts->peer_cid,
68                 },
69         };
70         int ret;
71         int fd;
72
73         /* Wait for the server to be ready */
74         control_expectln("BIND");
75
76         fd = socket(AF_VSOCK, SOCK_STREAM, 0);
77
78         timeout_begin(TIMEOUT);
79         do {
80                 ret = connect(fd, &addr.sa, sizeof(addr.svm));
81                 timeout_check("connect");
82         } while (ret < 0 && errno == EINTR);
83         timeout_end();
84
85         if (ret != -1) {
86                 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
87                 exit(EXIT_FAILURE);
88         }
89         if (errno != ECONNRESET) {
90                 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
91                 exit(EXIT_FAILURE);
92         }
93
94         /* Notify the server that the client has finished */
95         control_writeln("DONE");
96
97         close(fd);
98 }
99
100 static void test_stream_bind_only_server(const struct test_opts *opts)
101 {
102         union {
103                 struct sockaddr sa;
104                 struct sockaddr_vm svm;
105         } addr = {
106                 .svm = {
107                         .svm_family = AF_VSOCK,
108                         .svm_port = 1234,
109                         .svm_cid = VMADDR_CID_ANY,
110                 },
111         };
112         int fd;
113
114         fd = socket(AF_VSOCK, SOCK_STREAM, 0);
115
116         if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
117                 perror("bind");
118                 exit(EXIT_FAILURE);
119         }
120
121         /* Notify the client that the server is ready */
122         control_writeln("BIND");
123
124         /* Wait for the client to finish */
125         control_expectln("DONE");
126
127         close(fd);
128 }
129
130 static void test_stream_client_close_client(const struct test_opts *opts)
131 {
132         int fd;
133
134         fd = vsock_stream_connect(opts->peer_cid, 1234);
135         if (fd < 0) {
136                 perror("connect");
137                 exit(EXIT_FAILURE);
138         }
139
140         send_byte(fd, 1, 0);
141         close(fd);
142 }
143
144 static void test_stream_client_close_server(const struct test_opts *opts)
145 {
146         int fd;
147
148         fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
149         if (fd < 0) {
150                 perror("accept");
151                 exit(EXIT_FAILURE);
152         }
153
154         /* Wait for the remote to close the connection, before check
155          * -EPIPE error on send.
156          */
157         vsock_wait_remote_close(fd);
158
159         send_byte(fd, -EPIPE, 0);
160         recv_byte(fd, 1, 0);
161         recv_byte(fd, 0, 0);
162         close(fd);
163 }
164
165 static void test_stream_server_close_client(const struct test_opts *opts)
166 {
167         int fd;
168
169         fd = vsock_stream_connect(opts->peer_cid, 1234);
170         if (fd < 0) {
171                 perror("connect");
172                 exit(EXIT_FAILURE);
173         }
174
175         /* Wait for the remote to close the connection, before check
176          * -EPIPE error on send.
177          */
178         vsock_wait_remote_close(fd);
179
180         send_byte(fd, -EPIPE, 0);
181         recv_byte(fd, 1, 0);
182         recv_byte(fd, 0, 0);
183         close(fd);
184 }
185
186 static void test_stream_server_close_server(const struct test_opts *opts)
187 {
188         int fd;
189
190         fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
191         if (fd < 0) {
192                 perror("accept");
193                 exit(EXIT_FAILURE);
194         }
195
196         send_byte(fd, 1, 0);
197         close(fd);
198 }
199
200 /* With the standard socket sizes, VMCI is able to support about 100
201  * concurrent stream connections.
202  */
203 #define MULTICONN_NFDS 100
204
205 static void test_stream_multiconn_client(const struct test_opts *opts)
206 {
207         int fds[MULTICONN_NFDS];
208         int i;
209
210         for (i = 0; i < MULTICONN_NFDS; i++) {
211                 fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
212                 if (fds[i] < 0) {
213                         perror("connect");
214                         exit(EXIT_FAILURE);
215                 }
216         }
217
218         for (i = 0; i < MULTICONN_NFDS; i++) {
219                 if (i % 2)
220                         recv_byte(fds[i], 1, 0);
221                 else
222                         send_byte(fds[i], 1, 0);
223         }
224
225         for (i = 0; i < MULTICONN_NFDS; i++)
226                 close(fds[i]);
227 }
228
229 static void test_stream_multiconn_server(const struct test_opts *opts)
230 {
231         int fds[MULTICONN_NFDS];
232         int i;
233
234         for (i = 0; i < MULTICONN_NFDS; i++) {
235                 fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
236                 if (fds[i] < 0) {
237                         perror("accept");
238                         exit(EXIT_FAILURE);
239                 }
240         }
241
242         for (i = 0; i < MULTICONN_NFDS; i++) {
243                 if (i % 2)
244                         send_byte(fds[i], 1, 0);
245                 else
246                         recv_byte(fds[i], 1, 0);
247         }
248
249         for (i = 0; i < MULTICONN_NFDS; i++)
250                 close(fds[i]);
251 }
252
253 static void test_stream_msg_peek_client(const struct test_opts *opts)
254 {
255         int fd;
256
257         fd = vsock_stream_connect(opts->peer_cid, 1234);
258         if (fd < 0) {
259                 perror("connect");
260                 exit(EXIT_FAILURE);
261         }
262
263         send_byte(fd, 1, 0);
264         close(fd);
265 }
266
267 static void test_stream_msg_peek_server(const struct test_opts *opts)
268 {
269         int fd;
270
271         fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
272         if (fd < 0) {
273                 perror("accept");
274                 exit(EXIT_FAILURE);
275         }
276
277         recv_byte(fd, 1, MSG_PEEK);
278         recv_byte(fd, 1, 0);
279         close(fd);
280 }
281
282 static struct test_case test_cases[] = {
283         {
284                 .name = "SOCK_STREAM connection reset",
285                 .run_client = test_stream_connection_reset,
286         },
287         {
288                 .name = "SOCK_STREAM bind only",
289                 .run_client = test_stream_bind_only_client,
290                 .run_server = test_stream_bind_only_server,
291         },
292         {
293                 .name = "SOCK_STREAM client close",
294                 .run_client = test_stream_client_close_client,
295                 .run_server = test_stream_client_close_server,
296         },
297         {
298                 .name = "SOCK_STREAM server close",
299                 .run_client = test_stream_server_close_client,
300                 .run_server = test_stream_server_close_server,
301         },
302         {
303                 .name = "SOCK_STREAM multiple connections",
304                 .run_client = test_stream_multiconn_client,
305                 .run_server = test_stream_multiconn_server,
306         },
307         {
308                 .name = "SOCK_STREAM MSG_PEEK",
309                 .run_client = test_stream_msg_peek_client,
310                 .run_server = test_stream_msg_peek_server,
311         },
312         {},
313 };
314
315 static const char optstring[] = "";
316 static const struct option longopts[] = {
317         {
318                 .name = "control-host",
319                 .has_arg = required_argument,
320                 .val = 'H',
321         },
322         {
323                 .name = "control-port",
324                 .has_arg = required_argument,
325                 .val = 'P',
326         },
327         {
328                 .name = "mode",
329                 .has_arg = required_argument,
330                 .val = 'm',
331         },
332         {
333                 .name = "peer-cid",
334                 .has_arg = required_argument,
335                 .val = 'p',
336         },
337         {
338                 .name = "list",
339                 .has_arg = no_argument,
340                 .val = 'l',
341         },
342         {
343                 .name = "skip",
344                 .has_arg = required_argument,
345                 .val = 's',
346         },
347         {
348                 .name = "help",
349                 .has_arg = no_argument,
350                 .val = '?',
351         },
352         {},
353 };
354
355 static void usage(void)
356 {
357         fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
358                 "\n"
359                 "  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
360                 "  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
361                 "\n"
362                 "Run vsock.ko tests.  Must be launched in both guest\n"
363                 "and host.  One side must use --mode=client and\n"
364                 "the other side must use --mode=server.\n"
365                 "\n"
366                 "A TCP control socket connection is used to coordinate tests\n"
367                 "between the client and the server.  The server requires a\n"
368                 "listen address and the client requires an address to\n"
369                 "connect to.\n"
370                 "\n"
371                 "The CID of the other side must be given with --peer-cid=<cid>.\n"
372                 "\n"
373                 "Options:\n"
374                 "  --help                 This help message\n"
375                 "  --control-host <host>  Server IP address to connect to\n"
376                 "  --control-port <port>  Server port to listen on/connect to\n"
377                 "  --mode client|server   Server or client mode\n"
378                 "  --peer-cid <cid>       CID of the other side\n"
379                 "  --list                 List of tests that will be executed\n"
380                 "  --skip <test_id>       Test ID to skip;\n"
381                 "                         use multiple --skip options to skip more tests\n"
382                 );
383         exit(EXIT_FAILURE);
384 }
385
386 int main(int argc, char **argv)
387 {
388         const char *control_host = NULL;
389         const char *control_port = NULL;
390         struct test_opts opts = {
391                 .mode = TEST_MODE_UNSET,
392                 .peer_cid = VMADDR_CID_ANY,
393         };
394
395         init_signals();
396
397         for (;;) {
398                 int opt = getopt_long(argc, argv, optstring, longopts, NULL);
399
400                 if (opt == -1)
401                         break;
402
403                 switch (opt) {
404                 case 'H':
405                         control_host = optarg;
406                         break;
407                 case 'm':
408                         if (strcmp(optarg, "client") == 0)
409                                 opts.mode = TEST_MODE_CLIENT;
410                         else if (strcmp(optarg, "server") == 0)
411                                 opts.mode = TEST_MODE_SERVER;
412                         else {
413                                 fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
414                                 return EXIT_FAILURE;
415                         }
416                         break;
417                 case 'p':
418                         opts.peer_cid = parse_cid(optarg);
419                         break;
420                 case 'P':
421                         control_port = optarg;
422                         break;
423                 case 'l':
424                         list_tests(test_cases);
425                         break;
426                 case 's':
427                         skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
428                                   optarg);
429                         break;
430                 case '?':
431                 default:
432                         usage();
433                 }
434         }
435
436         if (!control_port)
437                 usage();
438         if (opts.mode == TEST_MODE_UNSET)
439                 usage();
440         if (opts.peer_cid == VMADDR_CID_ANY)
441                 usage();
442
443         if (!control_host) {
444                 if (opts.mode != TEST_MODE_SERVER)
445                         usage();
446                 control_host = "0.0.0.0";
447         }
448
449         control_init(control_host, control_port,
450                      opts.mode == TEST_MODE_SERVER);
451
452         run_tests(test_cases, &opts);
453
454         control_cleanup();
455         return EXIT_SUCCESS;
456 }