treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / tools / testing / vsock / vsock_test.c
blob1d8b93f1af3154bb7f7be991161481146f854a07
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * vsock_test - vsock.ko test suite
5 * Copyright (C) 2017 Red Hat, Inc.
7 * Author: Stefan Hajnoczi <stefanha@redhat.com>
8 */
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>
18 #include "timeout.h"
19 #include "control.h"
20 #include "util.h"
22 static void test_stream_connection_reset(const struct test_opts *opts)
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,
34 int ret;
35 int fd;
37 fd = socket(AF_VSOCK, SOCK_STREAM, 0);
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();
46 if (ret != -1) {
47 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
48 exit(EXIT_FAILURE);
50 if (errno != ECONNRESET) {
51 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
52 exit(EXIT_FAILURE);
55 close(fd);
58 static void test_stream_client_close_client(const struct test_opts *opts)
60 int fd;
62 fd = vsock_stream_connect(opts->peer_cid, 1234);
63 if (fd < 0) {
64 perror("connect");
65 exit(EXIT_FAILURE);
68 send_byte(fd, 1, 0);
69 close(fd);
72 static void test_stream_client_close_server(const struct test_opts *opts)
74 int fd;
76 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
77 if (fd < 0) {
78 perror("accept");
79 exit(EXIT_FAILURE);
82 /* Wait for the remote to close the connection, before check
83 * -EPIPE error on send.
85 vsock_wait_remote_close(fd);
87 send_byte(fd, -EPIPE, 0);
88 recv_byte(fd, 1, 0);
89 recv_byte(fd, 0, 0);
90 close(fd);
93 static void test_stream_server_close_client(const struct test_opts *opts)
95 int fd;
97 fd = vsock_stream_connect(opts->peer_cid, 1234);
98 if (fd < 0) {
99 perror("connect");
100 exit(EXIT_FAILURE);
103 /* Wait for the remote to close the connection, before check
104 * -EPIPE error on send.
106 vsock_wait_remote_close(fd);
108 send_byte(fd, -EPIPE, 0);
109 recv_byte(fd, 1, 0);
110 recv_byte(fd, 0, 0);
111 close(fd);
114 static void test_stream_server_close_server(const struct test_opts *opts)
116 int fd;
118 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
119 if (fd < 0) {
120 perror("accept");
121 exit(EXIT_FAILURE);
124 send_byte(fd, 1, 0);
125 close(fd);
128 /* With the standard socket sizes, VMCI is able to support about 100
129 * concurrent stream connections.
131 #define MULTICONN_NFDS 100
133 static void test_stream_multiconn_client(const struct test_opts *opts)
135 int fds[MULTICONN_NFDS];
136 int i;
138 for (i = 0; i < MULTICONN_NFDS; i++) {
139 fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
140 if (fds[i] < 0) {
141 perror("connect");
142 exit(EXIT_FAILURE);
146 for (i = 0; i < MULTICONN_NFDS; i++) {
147 if (i % 2)
148 recv_byte(fds[i], 1, 0);
149 else
150 send_byte(fds[i], 1, 0);
153 for (i = 0; i < MULTICONN_NFDS; i++)
154 close(fds[i]);
157 static void test_stream_multiconn_server(const struct test_opts *opts)
159 int fds[MULTICONN_NFDS];
160 int i;
162 for (i = 0; i < MULTICONN_NFDS; i++) {
163 fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
164 if (fds[i] < 0) {
165 perror("accept");
166 exit(EXIT_FAILURE);
170 for (i = 0; i < MULTICONN_NFDS; i++) {
171 if (i % 2)
172 send_byte(fds[i], 1, 0);
173 else
174 recv_byte(fds[i], 1, 0);
177 for (i = 0; i < MULTICONN_NFDS; i++)
178 close(fds[i]);
181 static void test_stream_msg_peek_client(const struct test_opts *opts)
183 int fd;
185 fd = vsock_stream_connect(opts->peer_cid, 1234);
186 if (fd < 0) {
187 perror("connect");
188 exit(EXIT_FAILURE);
191 send_byte(fd, 1, 0);
192 close(fd);
195 static void test_stream_msg_peek_server(const struct test_opts *opts)
197 int fd;
199 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
200 if (fd < 0) {
201 perror("accept");
202 exit(EXIT_FAILURE);
205 recv_byte(fd, 1, MSG_PEEK);
206 recv_byte(fd, 1, 0);
207 close(fd);
210 static struct test_case test_cases[] = {
212 .name = "SOCK_STREAM connection reset",
213 .run_client = test_stream_connection_reset,
216 .name = "SOCK_STREAM client close",
217 .run_client = test_stream_client_close_client,
218 .run_server = test_stream_client_close_server,
221 .name = "SOCK_STREAM server close",
222 .run_client = test_stream_server_close_client,
223 .run_server = test_stream_server_close_server,
226 .name = "SOCK_STREAM multiple connections",
227 .run_client = test_stream_multiconn_client,
228 .run_server = test_stream_multiconn_server,
231 .name = "SOCK_STREAM MSG_PEEK",
232 .run_client = test_stream_msg_peek_client,
233 .run_server = test_stream_msg_peek_server,
238 static const char optstring[] = "";
239 static const struct option longopts[] = {
241 .name = "control-host",
242 .has_arg = required_argument,
243 .val = 'H',
246 .name = "control-port",
247 .has_arg = required_argument,
248 .val = 'P',
251 .name = "mode",
252 .has_arg = required_argument,
253 .val = 'm',
256 .name = "peer-cid",
257 .has_arg = required_argument,
258 .val = 'p',
261 .name = "list",
262 .has_arg = no_argument,
263 .val = 'l',
266 .name = "skip",
267 .has_arg = required_argument,
268 .val = 's',
271 .name = "help",
272 .has_arg = no_argument,
273 .val = '?',
278 static void usage(void)
280 fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
281 "\n"
282 " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
283 " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
284 "\n"
285 "Run vsock.ko tests. Must be launched in both guest\n"
286 "and host. One side must use --mode=client and\n"
287 "the other side must use --mode=server.\n"
288 "\n"
289 "A TCP control socket connection is used to coordinate tests\n"
290 "between the client and the server. The server requires a\n"
291 "listen address and the client requires an address to\n"
292 "connect to.\n"
293 "\n"
294 "The CID of the other side must be given with --peer-cid=<cid>.\n"
295 "\n"
296 "Options:\n"
297 " --help This help message\n"
298 " --control-host <host> Server IP address to connect to\n"
299 " --control-port <port> Server port to listen on/connect to\n"
300 " --mode client|server Server or client mode\n"
301 " --peer-cid <cid> CID of the other side\n"
302 " --list List of tests that will be executed\n"
303 " --skip <test_id> Test ID to skip;\n"
304 " use multiple --skip options to skip more tests\n"
306 exit(EXIT_FAILURE);
309 int main(int argc, char **argv)
311 const char *control_host = NULL;
312 const char *control_port = NULL;
313 struct test_opts opts = {
314 .mode = TEST_MODE_UNSET,
315 .peer_cid = VMADDR_CID_ANY,
318 init_signals();
320 for (;;) {
321 int opt = getopt_long(argc, argv, optstring, longopts, NULL);
323 if (opt == -1)
324 break;
326 switch (opt) {
327 case 'H':
328 control_host = optarg;
329 break;
330 case 'm':
331 if (strcmp(optarg, "client") == 0)
332 opts.mode = TEST_MODE_CLIENT;
333 else if (strcmp(optarg, "server") == 0)
334 opts.mode = TEST_MODE_SERVER;
335 else {
336 fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
337 return EXIT_FAILURE;
339 break;
340 case 'p':
341 opts.peer_cid = parse_cid(optarg);
342 break;
343 case 'P':
344 control_port = optarg;
345 break;
346 case 'l':
347 list_tests(test_cases);
348 break;
349 case 's':
350 skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
351 optarg);
352 break;
353 case '?':
354 default:
355 usage();
359 if (!control_port)
360 usage();
361 if (opts.mode == TEST_MODE_UNSET)
362 usage();
363 if (opts.peer_cid == VMADDR_CID_ANY)
364 usage();
366 if (!control_host) {
367 if (opts.mode != TEST_MODE_SERVER)
368 usage();
369 control_host = "0.0.0.0";
372 control_init(control_host, control_port,
373 opts.mode == TEST_MODE_SERVER);
375 run_tests(test_cases, &opts);
377 control_cleanup();
378 return EXIT_SUCCESS;