Linux Audio

Check our new training course

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