xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision bbb774d9)
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 #include <time.h>
20 #include <sys/mman.h>
21 
22 #include "timeout.h"
23 #include "control.h"
24 #include "util.h"
25 
26 static void test_stream_connection_reset(const struct test_opts *opts)
27 {
28 	union {
29 		struct sockaddr sa;
30 		struct sockaddr_vm svm;
31 	} addr = {
32 		.svm = {
33 			.svm_family = AF_VSOCK,
34 			.svm_port = 1234,
35 			.svm_cid = opts->peer_cid,
36 		},
37 	};
38 	int ret;
39 	int fd;
40 
41 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
42 
43 	timeout_begin(TIMEOUT);
44 	do {
45 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
46 		timeout_check("connect");
47 	} while (ret < 0 && errno == EINTR);
48 	timeout_end();
49 
50 	if (ret != -1) {
51 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
52 		exit(EXIT_FAILURE);
53 	}
54 	if (errno != ECONNRESET) {
55 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
56 		exit(EXIT_FAILURE);
57 	}
58 
59 	close(fd);
60 }
61 
62 static void test_stream_bind_only_client(const struct test_opts *opts)
63 {
64 	union {
65 		struct sockaddr sa;
66 		struct sockaddr_vm svm;
67 	} addr = {
68 		.svm = {
69 			.svm_family = AF_VSOCK,
70 			.svm_port = 1234,
71 			.svm_cid = opts->peer_cid,
72 		},
73 	};
74 	int ret;
75 	int fd;
76 
77 	/* Wait for the server to be ready */
78 	control_expectln("BIND");
79 
80 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
81 
82 	timeout_begin(TIMEOUT);
83 	do {
84 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
85 		timeout_check("connect");
86 	} while (ret < 0 && errno == EINTR);
87 	timeout_end();
88 
89 	if (ret != -1) {
90 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
91 		exit(EXIT_FAILURE);
92 	}
93 	if (errno != ECONNRESET) {
94 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
95 		exit(EXIT_FAILURE);
96 	}
97 
98 	/* Notify the server that the client has finished */
99 	control_writeln("DONE");
100 
101 	close(fd);
102 }
103 
104 static void test_stream_bind_only_server(const struct test_opts *opts)
105 {
106 	union {
107 		struct sockaddr sa;
108 		struct sockaddr_vm svm;
109 	} addr = {
110 		.svm = {
111 			.svm_family = AF_VSOCK,
112 			.svm_port = 1234,
113 			.svm_cid = VMADDR_CID_ANY,
114 		},
115 	};
116 	int fd;
117 
118 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
119 
120 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
121 		perror("bind");
122 		exit(EXIT_FAILURE);
123 	}
124 
125 	/* Notify the client that the server is ready */
126 	control_writeln("BIND");
127 
128 	/* Wait for the client to finish */
129 	control_expectln("DONE");
130 
131 	close(fd);
132 }
133 
134 static void test_stream_client_close_client(const struct test_opts *opts)
135 {
136 	int fd;
137 
138 	fd = vsock_stream_connect(opts->peer_cid, 1234);
139 	if (fd < 0) {
140 		perror("connect");
141 		exit(EXIT_FAILURE);
142 	}
143 
144 	send_byte(fd, 1, 0);
145 	close(fd);
146 }
147 
148 static void test_stream_client_close_server(const struct test_opts *opts)
149 {
150 	int fd;
151 
152 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
153 	if (fd < 0) {
154 		perror("accept");
155 		exit(EXIT_FAILURE);
156 	}
157 
158 	/* Wait for the remote to close the connection, before check
159 	 * -EPIPE error on send.
160 	 */
161 	vsock_wait_remote_close(fd);
162 
163 	send_byte(fd, -EPIPE, 0);
164 	recv_byte(fd, 1, 0);
165 	recv_byte(fd, 0, 0);
166 	close(fd);
167 }
168 
169 static void test_stream_server_close_client(const struct test_opts *opts)
170 {
171 	int fd;
172 
173 	fd = vsock_stream_connect(opts->peer_cid, 1234);
174 	if (fd < 0) {
175 		perror("connect");
176 		exit(EXIT_FAILURE);
177 	}
178 
179 	/* Wait for the remote to close the connection, before check
180 	 * -EPIPE error on send.
181 	 */
182 	vsock_wait_remote_close(fd);
183 
184 	send_byte(fd, -EPIPE, 0);
185 	recv_byte(fd, 1, 0);
186 	recv_byte(fd, 0, 0);
187 	close(fd);
188 }
189 
190 static void test_stream_server_close_server(const struct test_opts *opts)
191 {
192 	int fd;
193 
194 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
195 	if (fd < 0) {
196 		perror("accept");
197 		exit(EXIT_FAILURE);
198 	}
199 
200 	send_byte(fd, 1, 0);
201 	close(fd);
202 }
203 
204 /* With the standard socket sizes, VMCI is able to support about 100
205  * concurrent stream connections.
206  */
207 #define MULTICONN_NFDS 100
208 
209 static void test_stream_multiconn_client(const struct test_opts *opts)
210 {
211 	int fds[MULTICONN_NFDS];
212 	int i;
213 
214 	for (i = 0; i < MULTICONN_NFDS; i++) {
215 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
216 		if (fds[i] < 0) {
217 			perror("connect");
218 			exit(EXIT_FAILURE);
219 		}
220 	}
221 
222 	for (i = 0; i < MULTICONN_NFDS; i++) {
223 		if (i % 2)
224 			recv_byte(fds[i], 1, 0);
225 		else
226 			send_byte(fds[i], 1, 0);
227 	}
228 
229 	for (i = 0; i < MULTICONN_NFDS; i++)
230 		close(fds[i]);
231 }
232 
233 static void test_stream_multiconn_server(const struct test_opts *opts)
234 {
235 	int fds[MULTICONN_NFDS];
236 	int i;
237 
238 	for (i = 0; i < MULTICONN_NFDS; i++) {
239 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
240 		if (fds[i] < 0) {
241 			perror("accept");
242 			exit(EXIT_FAILURE);
243 		}
244 	}
245 
246 	for (i = 0; i < MULTICONN_NFDS; i++) {
247 		if (i % 2)
248 			send_byte(fds[i], 1, 0);
249 		else
250 			recv_byte(fds[i], 1, 0);
251 	}
252 
253 	for (i = 0; i < MULTICONN_NFDS; i++)
254 		close(fds[i]);
255 }
256 
257 static void test_stream_msg_peek_client(const struct test_opts *opts)
258 {
259 	int fd;
260 
261 	fd = vsock_stream_connect(opts->peer_cid, 1234);
262 	if (fd < 0) {
263 		perror("connect");
264 		exit(EXIT_FAILURE);
265 	}
266 
267 	send_byte(fd, 1, 0);
268 	close(fd);
269 }
270 
271 static void test_stream_msg_peek_server(const struct test_opts *opts)
272 {
273 	int fd;
274 
275 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
276 	if (fd < 0) {
277 		perror("accept");
278 		exit(EXIT_FAILURE);
279 	}
280 
281 	recv_byte(fd, 1, MSG_PEEK);
282 	recv_byte(fd, 1, 0);
283 	close(fd);
284 }
285 
286 #define MESSAGES_CNT 7
287 #define MSG_EOR_IDX (MESSAGES_CNT / 2)
288 static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
289 {
290 	int fd;
291 
292 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
293 	if (fd < 0) {
294 		perror("connect");
295 		exit(EXIT_FAILURE);
296 	}
297 
298 	/* Send several messages, one with MSG_EOR flag */
299 	for (int i = 0; i < MESSAGES_CNT; i++)
300 		send_byte(fd, 1, (i == MSG_EOR_IDX) ? MSG_EOR : 0);
301 
302 	control_writeln("SENDDONE");
303 	close(fd);
304 }
305 
306 static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
307 {
308 	int fd;
309 	char buf[16];
310 	struct msghdr msg = {0};
311 	struct iovec iov = {0};
312 
313 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
314 	if (fd < 0) {
315 		perror("accept");
316 		exit(EXIT_FAILURE);
317 	}
318 
319 	control_expectln("SENDDONE");
320 	iov.iov_base = buf;
321 	iov.iov_len = sizeof(buf);
322 	msg.msg_iov = &iov;
323 	msg.msg_iovlen = 1;
324 
325 	for (int i = 0; i < MESSAGES_CNT; i++) {
326 		if (recvmsg(fd, &msg, 0) != 1) {
327 			perror("message bound violated");
328 			exit(EXIT_FAILURE);
329 		}
330 
331 		if ((i == MSG_EOR_IDX) ^ !!(msg.msg_flags & MSG_EOR)) {
332 			perror("MSG_EOR");
333 			exit(EXIT_FAILURE);
334 		}
335 	}
336 
337 	close(fd);
338 }
339 
340 #define MESSAGE_TRUNC_SZ 32
341 static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
342 {
343 	int fd;
344 	char buf[MESSAGE_TRUNC_SZ];
345 
346 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
347 	if (fd < 0) {
348 		perror("connect");
349 		exit(EXIT_FAILURE);
350 	}
351 
352 	if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
353 		perror("send failed");
354 		exit(EXIT_FAILURE);
355 	}
356 
357 	control_writeln("SENDDONE");
358 	close(fd);
359 }
360 
361 static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
362 {
363 	int fd;
364 	char buf[MESSAGE_TRUNC_SZ / 2];
365 	struct msghdr msg = {0};
366 	struct iovec iov = {0};
367 
368 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
369 	if (fd < 0) {
370 		perror("accept");
371 		exit(EXIT_FAILURE);
372 	}
373 
374 	control_expectln("SENDDONE");
375 	iov.iov_base = buf;
376 	iov.iov_len = sizeof(buf);
377 	msg.msg_iov = &iov;
378 	msg.msg_iovlen = 1;
379 
380 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
381 
382 	if (ret != MESSAGE_TRUNC_SZ) {
383 		printf("%zi\n", ret);
384 		perror("MSG_TRUNC doesn't work");
385 		exit(EXIT_FAILURE);
386 	}
387 
388 	if (!(msg.msg_flags & MSG_TRUNC)) {
389 		fprintf(stderr, "MSG_TRUNC expected\n");
390 		exit(EXIT_FAILURE);
391 	}
392 
393 	close(fd);
394 }
395 
396 static time_t current_nsec(void)
397 {
398 	struct timespec ts;
399 
400 	if (clock_gettime(CLOCK_REALTIME, &ts)) {
401 		perror("clock_gettime(3) failed");
402 		exit(EXIT_FAILURE);
403 	}
404 
405 	return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
406 }
407 
408 #define RCVTIMEO_TIMEOUT_SEC 1
409 #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
410 
411 static void test_seqpacket_timeout_client(const struct test_opts *opts)
412 {
413 	int fd;
414 	struct timeval tv;
415 	char dummy;
416 	time_t read_enter_ns;
417 	time_t read_overhead_ns;
418 
419 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
420 	if (fd < 0) {
421 		perror("connect");
422 		exit(EXIT_FAILURE);
423 	}
424 
425 	tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
426 	tv.tv_usec = 0;
427 
428 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
429 		perror("setsockopt 'SO_RCVTIMEO'");
430 		exit(EXIT_FAILURE);
431 	}
432 
433 	read_enter_ns = current_nsec();
434 
435 	if (read(fd, &dummy, sizeof(dummy)) != -1) {
436 		fprintf(stderr,
437 			"expected 'dummy' read(2) failure\n");
438 		exit(EXIT_FAILURE);
439 	}
440 
441 	if (errno != EAGAIN) {
442 		perror("EAGAIN expected");
443 		exit(EXIT_FAILURE);
444 	}
445 
446 	read_overhead_ns = current_nsec() - read_enter_ns -
447 			1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
448 
449 	if (read_overhead_ns > READ_OVERHEAD_NSEC) {
450 		fprintf(stderr,
451 			"too much time in read(2), %lu > %i ns\n",
452 			read_overhead_ns, READ_OVERHEAD_NSEC);
453 		exit(EXIT_FAILURE);
454 	}
455 
456 	control_writeln("WAITDONE");
457 	close(fd);
458 }
459 
460 static void test_seqpacket_timeout_server(const struct test_opts *opts)
461 {
462 	int fd;
463 
464 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
465 	if (fd < 0) {
466 		perror("accept");
467 		exit(EXIT_FAILURE);
468 	}
469 
470 	control_expectln("WAITDONE");
471 	close(fd);
472 }
473 
474 #define BUF_PATTERN_1 'a'
475 #define BUF_PATTERN_2 'b'
476 
477 static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
478 {
479 	int fd;
480 	unsigned char *buf1;
481 	unsigned char *buf2;
482 	int buf_size = getpagesize() * 3;
483 
484 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
485 	if (fd < 0) {
486 		perror("connect");
487 		exit(EXIT_FAILURE);
488 	}
489 
490 	buf1 = malloc(buf_size);
491 	if (!buf1) {
492 		perror("'malloc()' for 'buf1'");
493 		exit(EXIT_FAILURE);
494 	}
495 
496 	buf2 = malloc(buf_size);
497 	if (!buf2) {
498 		perror("'malloc()' for 'buf2'");
499 		exit(EXIT_FAILURE);
500 	}
501 
502 	memset(buf1, BUF_PATTERN_1, buf_size);
503 	memset(buf2, BUF_PATTERN_2, buf_size);
504 
505 	if (send(fd, buf1, buf_size, 0) != buf_size) {
506 		perror("send failed");
507 		exit(EXIT_FAILURE);
508 	}
509 
510 	if (send(fd, buf2, buf_size, 0) != buf_size) {
511 		perror("send failed");
512 		exit(EXIT_FAILURE);
513 	}
514 
515 	close(fd);
516 }
517 
518 static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
519 {
520 	int fd;
521 	unsigned char *broken_buf;
522 	unsigned char *valid_buf;
523 	int page_size = getpagesize();
524 	int buf_size = page_size * 3;
525 	ssize_t res;
526 	int prot = PROT_READ | PROT_WRITE;
527 	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
528 	int i;
529 
530 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
531 	if (fd < 0) {
532 		perror("accept");
533 		exit(EXIT_FAILURE);
534 	}
535 
536 	/* Setup first buffer. */
537 	broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
538 	if (broken_buf == MAP_FAILED) {
539 		perror("mmap for 'broken_buf'");
540 		exit(EXIT_FAILURE);
541 	}
542 
543 	/* Unmap "hole" in buffer. */
544 	if (munmap(broken_buf + page_size, page_size)) {
545 		perror("'broken_buf' setup");
546 		exit(EXIT_FAILURE);
547 	}
548 
549 	valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
550 	if (valid_buf == MAP_FAILED) {
551 		perror("mmap for 'valid_buf'");
552 		exit(EXIT_FAILURE);
553 	}
554 
555 	/* Try to fill buffer with unmapped middle. */
556 	res = read(fd, broken_buf, buf_size);
557 	if (res != -1) {
558 		fprintf(stderr,
559 			"expected 'broken_buf' read(2) failure, got %zi\n",
560 			res);
561 		exit(EXIT_FAILURE);
562 	}
563 
564 	if (errno != ENOMEM) {
565 		perror("unexpected errno of 'broken_buf'");
566 		exit(EXIT_FAILURE);
567 	}
568 
569 	/* Try to fill valid buffer. */
570 	res = read(fd, valid_buf, buf_size);
571 	if (res < 0) {
572 		perror("unexpected 'valid_buf' read(2) failure");
573 		exit(EXIT_FAILURE);
574 	}
575 
576 	if (res != buf_size) {
577 		fprintf(stderr,
578 			"invalid 'valid_buf' read(2), expected %i, got %zi\n",
579 			buf_size, res);
580 		exit(EXIT_FAILURE);
581 	}
582 
583 	for (i = 0; i < buf_size; i++) {
584 		if (valid_buf[i] != BUF_PATTERN_2) {
585 			fprintf(stderr,
586 				"invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
587 				i, BUF_PATTERN_2, valid_buf[i]);
588 			exit(EXIT_FAILURE);
589 		}
590 	}
591 
592 	/* Unmap buffers. */
593 	munmap(broken_buf, page_size);
594 	munmap(broken_buf + page_size * 2, page_size);
595 	munmap(valid_buf, buf_size);
596 	close(fd);
597 }
598 
599 static struct test_case test_cases[] = {
600 	{
601 		.name = "SOCK_STREAM connection reset",
602 		.run_client = test_stream_connection_reset,
603 	},
604 	{
605 		.name = "SOCK_STREAM bind only",
606 		.run_client = test_stream_bind_only_client,
607 		.run_server = test_stream_bind_only_server,
608 	},
609 	{
610 		.name = "SOCK_STREAM client close",
611 		.run_client = test_stream_client_close_client,
612 		.run_server = test_stream_client_close_server,
613 	},
614 	{
615 		.name = "SOCK_STREAM server close",
616 		.run_client = test_stream_server_close_client,
617 		.run_server = test_stream_server_close_server,
618 	},
619 	{
620 		.name = "SOCK_STREAM multiple connections",
621 		.run_client = test_stream_multiconn_client,
622 		.run_server = test_stream_multiconn_server,
623 	},
624 	{
625 		.name = "SOCK_STREAM MSG_PEEK",
626 		.run_client = test_stream_msg_peek_client,
627 		.run_server = test_stream_msg_peek_server,
628 	},
629 	{
630 		.name = "SOCK_SEQPACKET msg bounds",
631 		.run_client = test_seqpacket_msg_bounds_client,
632 		.run_server = test_seqpacket_msg_bounds_server,
633 	},
634 	{
635 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
636 		.run_client = test_seqpacket_msg_trunc_client,
637 		.run_server = test_seqpacket_msg_trunc_server,
638 	},
639 	{
640 		.name = "SOCK_SEQPACKET timeout",
641 		.run_client = test_seqpacket_timeout_client,
642 		.run_server = test_seqpacket_timeout_server,
643 	},
644 	{
645 		.name = "SOCK_SEQPACKET invalid receive buffer",
646 		.run_client = test_seqpacket_invalid_rec_buffer_client,
647 		.run_server = test_seqpacket_invalid_rec_buffer_server,
648 	},
649 	{},
650 };
651 
652 static const char optstring[] = "";
653 static const struct option longopts[] = {
654 	{
655 		.name = "control-host",
656 		.has_arg = required_argument,
657 		.val = 'H',
658 	},
659 	{
660 		.name = "control-port",
661 		.has_arg = required_argument,
662 		.val = 'P',
663 	},
664 	{
665 		.name = "mode",
666 		.has_arg = required_argument,
667 		.val = 'm',
668 	},
669 	{
670 		.name = "peer-cid",
671 		.has_arg = required_argument,
672 		.val = 'p',
673 	},
674 	{
675 		.name = "list",
676 		.has_arg = no_argument,
677 		.val = 'l',
678 	},
679 	{
680 		.name = "skip",
681 		.has_arg = required_argument,
682 		.val = 's',
683 	},
684 	{
685 		.name = "help",
686 		.has_arg = no_argument,
687 		.val = '?',
688 	},
689 	{},
690 };
691 
692 static void usage(void)
693 {
694 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
695 		"\n"
696 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
697 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
698 		"\n"
699 		"Run vsock.ko tests.  Must be launched in both guest\n"
700 		"and host.  One side must use --mode=client and\n"
701 		"the other side must use --mode=server.\n"
702 		"\n"
703 		"A TCP control socket connection is used to coordinate tests\n"
704 		"between the client and the server.  The server requires a\n"
705 		"listen address and the client requires an address to\n"
706 		"connect to.\n"
707 		"\n"
708 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
709 		"\n"
710 		"Options:\n"
711 		"  --help                 This help message\n"
712 		"  --control-host <host>  Server IP address to connect to\n"
713 		"  --control-port <port>  Server port to listen on/connect to\n"
714 		"  --mode client|server   Server or client mode\n"
715 		"  --peer-cid <cid>       CID of the other side\n"
716 		"  --list                 List of tests that will be executed\n"
717 		"  --skip <test_id>       Test ID to skip;\n"
718 		"                         use multiple --skip options to skip more tests\n"
719 		);
720 	exit(EXIT_FAILURE);
721 }
722 
723 int main(int argc, char **argv)
724 {
725 	const char *control_host = NULL;
726 	const char *control_port = NULL;
727 	struct test_opts opts = {
728 		.mode = TEST_MODE_UNSET,
729 		.peer_cid = VMADDR_CID_ANY,
730 	};
731 
732 	init_signals();
733 
734 	for (;;) {
735 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
736 
737 		if (opt == -1)
738 			break;
739 
740 		switch (opt) {
741 		case 'H':
742 			control_host = optarg;
743 			break;
744 		case 'm':
745 			if (strcmp(optarg, "client") == 0)
746 				opts.mode = TEST_MODE_CLIENT;
747 			else if (strcmp(optarg, "server") == 0)
748 				opts.mode = TEST_MODE_SERVER;
749 			else {
750 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
751 				return EXIT_FAILURE;
752 			}
753 			break;
754 		case 'p':
755 			opts.peer_cid = parse_cid(optarg);
756 			break;
757 		case 'P':
758 			control_port = optarg;
759 			break;
760 		case 'l':
761 			list_tests(test_cases);
762 			break;
763 		case 's':
764 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
765 				  optarg);
766 			break;
767 		case '?':
768 		default:
769 			usage();
770 		}
771 	}
772 
773 	if (!control_port)
774 		usage();
775 	if (opts.mode == TEST_MODE_UNSET)
776 		usage();
777 	if (opts.peer_cid == VMADDR_CID_ANY)
778 		usage();
779 
780 	if (!control_host) {
781 		if (opts.mode != TEST_MODE_SERVER)
782 			usage();
783 		control_host = "0.0.0.0";
784 	}
785 
786 	control_init(control_host, control_port,
787 		     opts.mode == TEST_MODE_SERVER);
788 
789 	run_tests(test_cases, &opts);
790 
791 	control_cleanup();
792 	return EXIT_SUCCESS;
793 }
794