xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision d6269a93)
1cdbcc18dSStefan Hajnoczi // SPDX-License-Identifier: GPL-2.0-only
2cdbcc18dSStefan Hajnoczi /*
3cdbcc18dSStefan Hajnoczi  * vsock_test - vsock.ko test suite
4cdbcc18dSStefan Hajnoczi  *
5cdbcc18dSStefan Hajnoczi  * Copyright (C) 2017 Red Hat, Inc.
6cdbcc18dSStefan Hajnoczi  *
7cdbcc18dSStefan Hajnoczi  * Author: Stefan Hajnoczi <stefanha@redhat.com>
8cdbcc18dSStefan Hajnoczi  */
9cdbcc18dSStefan Hajnoczi 
10cdbcc18dSStefan Hajnoczi #include <getopt.h>
11cdbcc18dSStefan Hajnoczi #include <stdio.h>
12cdbcc18dSStefan Hajnoczi #include <stdlib.h>
13cdbcc18dSStefan Hajnoczi #include <string.h>
14cdbcc18dSStefan Hajnoczi #include <errno.h>
15cdbcc18dSStefan Hajnoczi #include <unistd.h>
165a2b2425SStefano Garzarella #include <linux/kernel.h>
17cdbcc18dSStefan Hajnoczi 
18cdbcc18dSStefan Hajnoczi #include "timeout.h"
19cdbcc18dSStefan Hajnoczi #include "control.h"
20cdbcc18dSStefan Hajnoczi #include "util.h"
21cdbcc18dSStefan Hajnoczi 
22cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts)
23cdbcc18dSStefan Hajnoczi {
24cdbcc18dSStefan Hajnoczi 	union {
25cdbcc18dSStefan Hajnoczi 		struct sockaddr sa;
26cdbcc18dSStefan Hajnoczi 		struct sockaddr_vm svm;
27cdbcc18dSStefan Hajnoczi 	} addr = {
28cdbcc18dSStefan Hajnoczi 		.svm = {
29cdbcc18dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
30cdbcc18dSStefan Hajnoczi 			.svm_port = 1234,
31cdbcc18dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
32cdbcc18dSStefan Hajnoczi 		},
33cdbcc18dSStefan Hajnoczi 	};
34cdbcc18dSStefan Hajnoczi 	int ret;
35cdbcc18dSStefan Hajnoczi 	int fd;
36cdbcc18dSStefan Hajnoczi 
37cdbcc18dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
38cdbcc18dSStefan Hajnoczi 
39cdbcc18dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
40cdbcc18dSStefan Hajnoczi 	do {
41cdbcc18dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
42cdbcc18dSStefan Hajnoczi 		timeout_check("connect");
43cdbcc18dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
44cdbcc18dSStefan Hajnoczi 	timeout_end();
45cdbcc18dSStefan Hajnoczi 
46cdbcc18dSStefan Hajnoczi 	if (ret != -1) {
47cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
48cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
49cdbcc18dSStefan Hajnoczi 	}
50cdbcc18dSStefan Hajnoczi 	if (errno != ECONNRESET) {
51cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
52cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
53cdbcc18dSStefan Hajnoczi 	}
54cdbcc18dSStefan Hajnoczi 
55cdbcc18dSStefan Hajnoczi 	close(fd);
56cdbcc18dSStefan Hajnoczi }
57cdbcc18dSStefan Hajnoczi 
58cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts)
59cdbcc18dSStefan Hajnoczi {
60cdbcc18dSStefan Hajnoczi 	int fd;
61cdbcc18dSStefan Hajnoczi 
62cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
63cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
64cdbcc18dSStefan Hajnoczi 		perror("connect");
65cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
66cdbcc18dSStefan Hajnoczi 	}
67cdbcc18dSStefan Hajnoczi 
68cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
69cdbcc18dSStefan Hajnoczi 	close(fd);
70cdbcc18dSStefan Hajnoczi }
71cdbcc18dSStefan Hajnoczi 
72cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts)
73cdbcc18dSStefan Hajnoczi {
74cdbcc18dSStefan Hajnoczi 	int fd;
75cdbcc18dSStefan Hajnoczi 
76cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
77cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
78cdbcc18dSStefan Hajnoczi 		perror("accept");
79cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
80cdbcc18dSStefan Hajnoczi 	}
81cdbcc18dSStefan Hajnoczi 
82770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
83770ce007SStefano Garzarella 	 * -EPIPE error on send.
84770ce007SStefano Garzarella 	 */
85770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
86cdbcc18dSStefan Hajnoczi 
87cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
88cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
89cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
90cdbcc18dSStefan Hajnoczi 	close(fd);
91cdbcc18dSStefan Hajnoczi }
92cdbcc18dSStefan Hajnoczi 
93cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts)
94cdbcc18dSStefan Hajnoczi {
95cdbcc18dSStefan Hajnoczi 	int fd;
96cdbcc18dSStefan Hajnoczi 
97cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
98cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
99cdbcc18dSStefan Hajnoczi 		perror("connect");
100cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
101cdbcc18dSStefan Hajnoczi 	}
102cdbcc18dSStefan Hajnoczi 
103770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
104770ce007SStefano Garzarella 	 * -EPIPE error on send.
105770ce007SStefano Garzarella 	 */
106770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
107cdbcc18dSStefan Hajnoczi 
108cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
109cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
110cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
111cdbcc18dSStefan Hajnoczi 	close(fd);
112cdbcc18dSStefan Hajnoczi }
113cdbcc18dSStefan Hajnoczi 
114cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts)
115cdbcc18dSStefan Hajnoczi {
116cdbcc18dSStefan Hajnoczi 	int fd;
117cdbcc18dSStefan Hajnoczi 
118cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
119cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
120cdbcc18dSStefan Hajnoczi 		perror("accept");
121cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
122cdbcc18dSStefan Hajnoczi 	}
123cdbcc18dSStefan Hajnoczi 
124cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
125cdbcc18dSStefan Hajnoczi 	close(fd);
126cdbcc18dSStefan Hajnoczi }
127cdbcc18dSStefan Hajnoczi 
128cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100
129cdbcc18dSStefan Hajnoczi  * concurrent stream connections.
130cdbcc18dSStefan Hajnoczi  */
131cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100
132cdbcc18dSStefan Hajnoczi 
133cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts)
134cdbcc18dSStefan Hajnoczi {
135cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
136cdbcc18dSStefan Hajnoczi 	int i;
137cdbcc18dSStefan Hajnoczi 
138cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
139cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
140cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
141cdbcc18dSStefan Hajnoczi 			perror("connect");
142cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
143cdbcc18dSStefan Hajnoczi 		}
144cdbcc18dSStefan Hajnoczi 	}
145cdbcc18dSStefan Hajnoczi 
146cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
147cdbcc18dSStefan Hajnoczi 		if (i % 2)
148cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
149cdbcc18dSStefan Hajnoczi 		else
150cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
151cdbcc18dSStefan Hajnoczi 	}
152cdbcc18dSStefan Hajnoczi 
153cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
154cdbcc18dSStefan Hajnoczi 		close(fds[i]);
155cdbcc18dSStefan Hajnoczi }
156cdbcc18dSStefan Hajnoczi 
157cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts)
158cdbcc18dSStefan Hajnoczi {
159cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
160cdbcc18dSStefan Hajnoczi 	int i;
161cdbcc18dSStefan Hajnoczi 
162cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
163cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
164cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
165cdbcc18dSStefan Hajnoczi 			perror("accept");
166cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
167cdbcc18dSStefan Hajnoczi 		}
168cdbcc18dSStefan Hajnoczi 	}
169cdbcc18dSStefan Hajnoczi 
170cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
171cdbcc18dSStefan Hajnoczi 		if (i % 2)
172cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
173cdbcc18dSStefan Hajnoczi 		else
174cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
175cdbcc18dSStefan Hajnoczi 	}
176cdbcc18dSStefan Hajnoczi 
177cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
178cdbcc18dSStefan Hajnoczi 		close(fds[i]);
179cdbcc18dSStefan Hajnoczi }
180cdbcc18dSStefan Hajnoczi 
181d6269a93SStefano Garzarella static void test_stream_msg_peek_client(const struct test_opts *opts)
182d6269a93SStefano Garzarella {
183d6269a93SStefano Garzarella 	int fd;
184d6269a93SStefano Garzarella 
185d6269a93SStefano Garzarella 	fd = vsock_stream_connect(opts->peer_cid, 1234);
186d6269a93SStefano Garzarella 	if (fd < 0) {
187d6269a93SStefano Garzarella 		perror("connect");
188d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
189d6269a93SStefano Garzarella 	}
190d6269a93SStefano Garzarella 
191d6269a93SStefano Garzarella 	send_byte(fd, 1, 0);
192d6269a93SStefano Garzarella 	close(fd);
193d6269a93SStefano Garzarella }
194d6269a93SStefano Garzarella 
195d6269a93SStefano Garzarella static void test_stream_msg_peek_server(const struct test_opts *opts)
196d6269a93SStefano Garzarella {
197d6269a93SStefano Garzarella 	int fd;
198d6269a93SStefano Garzarella 
199d6269a93SStefano Garzarella 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
200d6269a93SStefano Garzarella 	if (fd < 0) {
201d6269a93SStefano Garzarella 		perror("accept");
202d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
203d6269a93SStefano Garzarella 	}
204d6269a93SStefano Garzarella 
205d6269a93SStefano Garzarella 	recv_byte(fd, 1, MSG_PEEK);
206d6269a93SStefano Garzarella 	recv_byte(fd, 1, 0);
207d6269a93SStefano Garzarella 	close(fd);
208d6269a93SStefano Garzarella }
209d6269a93SStefano Garzarella 
210cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
211cdbcc18dSStefan Hajnoczi 	{
212cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
213cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
214cdbcc18dSStefan Hajnoczi 	},
215cdbcc18dSStefan Hajnoczi 	{
216cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
217cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
218cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
219cdbcc18dSStefan Hajnoczi 	},
220cdbcc18dSStefan Hajnoczi 	{
221cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
222cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
223cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
224cdbcc18dSStefan Hajnoczi 	},
225cdbcc18dSStefan Hajnoczi 	{
226cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
227cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
228cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
229cdbcc18dSStefan Hajnoczi 	},
230d6269a93SStefano Garzarella 	{
231d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
232d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
233d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
234d6269a93SStefano Garzarella 	},
235cdbcc18dSStefan Hajnoczi 	{},
236cdbcc18dSStefan Hajnoczi };
237cdbcc18dSStefan Hajnoczi 
238cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
239cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
240cdbcc18dSStefan Hajnoczi 	{
241cdbcc18dSStefan Hajnoczi 		.name = "control-host",
242cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
243cdbcc18dSStefan Hajnoczi 		.val = 'H',
244cdbcc18dSStefan Hajnoczi 	},
245cdbcc18dSStefan Hajnoczi 	{
246cdbcc18dSStefan Hajnoczi 		.name = "control-port",
247cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
248cdbcc18dSStefan Hajnoczi 		.val = 'P',
249cdbcc18dSStefan Hajnoczi 	},
250cdbcc18dSStefan Hajnoczi 	{
251cdbcc18dSStefan Hajnoczi 		.name = "mode",
252cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
253cdbcc18dSStefan Hajnoczi 		.val = 'm',
254cdbcc18dSStefan Hajnoczi 	},
255cdbcc18dSStefan Hajnoczi 	{
256cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
257cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
258cdbcc18dSStefan Hajnoczi 		.val = 'p',
259cdbcc18dSStefan Hajnoczi 	},
260cdbcc18dSStefan Hajnoczi 	{
2615a2b2425SStefano Garzarella 		.name = "list",
2625a2b2425SStefano Garzarella 		.has_arg = no_argument,
2635a2b2425SStefano Garzarella 		.val = 'l',
2645a2b2425SStefano Garzarella 	},
2655a2b2425SStefano Garzarella 	{
2665a2b2425SStefano Garzarella 		.name = "skip",
2675a2b2425SStefano Garzarella 		.has_arg = required_argument,
2685a2b2425SStefano Garzarella 		.val = 's',
2695a2b2425SStefano Garzarella 	},
2705a2b2425SStefano Garzarella 	{
271cdbcc18dSStefan Hajnoczi 		.name = "help",
272cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
273cdbcc18dSStefan Hajnoczi 		.val = '?',
274cdbcc18dSStefan Hajnoczi 	},
275cdbcc18dSStefan Hajnoczi 	{},
276cdbcc18dSStefan Hajnoczi };
277cdbcc18dSStefan Hajnoczi 
278cdbcc18dSStefan Hajnoczi static void usage(void)
279cdbcc18dSStefan Hajnoczi {
2805a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
281cdbcc18dSStefan Hajnoczi 		"\n"
282cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
283cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
284cdbcc18dSStefan Hajnoczi 		"\n"
285cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
286cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
287cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
288cdbcc18dSStefan Hajnoczi 		"\n"
289cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
290cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
291cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
292cdbcc18dSStefan Hajnoczi 		"connect to.\n"
293cdbcc18dSStefan Hajnoczi 		"\n"
2948d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
2958d00b93fSStefano Garzarella 		"\n"
2968d00b93fSStefano Garzarella 		"Options:\n"
2978d00b93fSStefano Garzarella 		"  --help                 This help message\n"
2988d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
2998d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
3008d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
3018d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
3028d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
3038d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
3048d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
3058d00b93fSStefano Garzarella 		);
306cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
307cdbcc18dSStefan Hajnoczi }
308cdbcc18dSStefan Hajnoczi 
309cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
310cdbcc18dSStefan Hajnoczi {
311cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
312cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
313cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
314cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
315cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
316cdbcc18dSStefan Hajnoczi 	};
317cdbcc18dSStefan Hajnoczi 
318cdbcc18dSStefan Hajnoczi 	init_signals();
319cdbcc18dSStefan Hajnoczi 
320cdbcc18dSStefan Hajnoczi 	for (;;) {
321cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
322cdbcc18dSStefan Hajnoczi 
323cdbcc18dSStefan Hajnoczi 		if (opt == -1)
324cdbcc18dSStefan Hajnoczi 			break;
325cdbcc18dSStefan Hajnoczi 
326cdbcc18dSStefan Hajnoczi 		switch (opt) {
327cdbcc18dSStefan Hajnoczi 		case 'H':
328cdbcc18dSStefan Hajnoczi 			control_host = optarg;
329cdbcc18dSStefan Hajnoczi 			break;
330cdbcc18dSStefan Hajnoczi 		case 'm':
331cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
332cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
333cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
334cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
335cdbcc18dSStefan Hajnoczi 			else {
336cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
337cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
338cdbcc18dSStefan Hajnoczi 			}
339cdbcc18dSStefan Hajnoczi 			break;
340cdbcc18dSStefan Hajnoczi 		case 'p':
341cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
342cdbcc18dSStefan Hajnoczi 			break;
343cdbcc18dSStefan Hajnoczi 		case 'P':
344cdbcc18dSStefan Hajnoczi 			control_port = optarg;
345cdbcc18dSStefan Hajnoczi 			break;
3465a2b2425SStefano Garzarella 		case 'l':
3475a2b2425SStefano Garzarella 			list_tests(test_cases);
3485a2b2425SStefano Garzarella 			break;
3495a2b2425SStefano Garzarella 		case 's':
3505a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
3515a2b2425SStefano Garzarella 				  optarg);
3525a2b2425SStefano Garzarella 			break;
353cdbcc18dSStefan Hajnoczi 		case '?':
354cdbcc18dSStefan Hajnoczi 		default:
355cdbcc18dSStefan Hajnoczi 			usage();
356cdbcc18dSStefan Hajnoczi 		}
357cdbcc18dSStefan Hajnoczi 	}
358cdbcc18dSStefan Hajnoczi 
359cdbcc18dSStefan Hajnoczi 	if (!control_port)
360cdbcc18dSStefan Hajnoczi 		usage();
361cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
362cdbcc18dSStefan Hajnoczi 		usage();
363cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
364cdbcc18dSStefan Hajnoczi 		usage();
365cdbcc18dSStefan Hajnoczi 
366cdbcc18dSStefan Hajnoczi 	if (!control_host) {
367cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
368cdbcc18dSStefan Hajnoczi 			usage();
369cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
370cdbcc18dSStefan Hajnoczi 	}
371cdbcc18dSStefan Hajnoczi 
372cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
373cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
374cdbcc18dSStefan Hajnoczi 
375cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
376cdbcc18dSStefan Hajnoczi 
377cdbcc18dSStefan Hajnoczi 	control_cleanup();
378cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
379cdbcc18dSStefan Hajnoczi }
380