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