xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision 41b792d7)
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>
17*41b792d7SArseny Krasnov #include <sys/types.h>
18*41b792d7SArseny Krasnov #include <sys/socket.h>
19cdbcc18dSStefan Hajnoczi 
20cdbcc18dSStefan Hajnoczi #include "timeout.h"
21cdbcc18dSStefan Hajnoczi #include "control.h"
22cdbcc18dSStefan Hajnoczi #include "util.h"
23cdbcc18dSStefan Hajnoczi 
24cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts)
25cdbcc18dSStefan Hajnoczi {
26cdbcc18dSStefan Hajnoczi 	union {
27cdbcc18dSStefan Hajnoczi 		struct sockaddr sa;
28cdbcc18dSStefan Hajnoczi 		struct sockaddr_vm svm;
29cdbcc18dSStefan Hajnoczi 	} addr = {
30cdbcc18dSStefan Hajnoczi 		.svm = {
31cdbcc18dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
32cdbcc18dSStefan Hajnoczi 			.svm_port = 1234,
33cdbcc18dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
34cdbcc18dSStefan Hajnoczi 		},
35cdbcc18dSStefan Hajnoczi 	};
36cdbcc18dSStefan Hajnoczi 	int ret;
37cdbcc18dSStefan Hajnoczi 	int fd;
38cdbcc18dSStefan Hajnoczi 
39cdbcc18dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
40cdbcc18dSStefan Hajnoczi 
41cdbcc18dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
42cdbcc18dSStefan Hajnoczi 	do {
43cdbcc18dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
44cdbcc18dSStefan Hajnoczi 		timeout_check("connect");
45cdbcc18dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
46cdbcc18dSStefan Hajnoczi 	timeout_end();
47cdbcc18dSStefan Hajnoczi 
48cdbcc18dSStefan Hajnoczi 	if (ret != -1) {
49cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
50cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
51cdbcc18dSStefan Hajnoczi 	}
52cdbcc18dSStefan Hajnoczi 	if (errno != ECONNRESET) {
53cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
54cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
55cdbcc18dSStefan Hajnoczi 	}
56cdbcc18dSStefan Hajnoczi 
57cdbcc18dSStefan Hajnoczi 	close(fd);
58cdbcc18dSStefan Hajnoczi }
59cdbcc18dSStefan Hajnoczi 
609de9f7d1SSebastien Boeuf static void test_stream_bind_only_client(const struct test_opts *opts)
619de9f7d1SSebastien Boeuf {
629de9f7d1SSebastien Boeuf 	union {
639de9f7d1SSebastien Boeuf 		struct sockaddr sa;
649de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
659de9f7d1SSebastien Boeuf 	} addr = {
669de9f7d1SSebastien Boeuf 		.svm = {
679de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
689de9f7d1SSebastien Boeuf 			.svm_port = 1234,
699de9f7d1SSebastien Boeuf 			.svm_cid = opts->peer_cid,
709de9f7d1SSebastien Boeuf 		},
719de9f7d1SSebastien Boeuf 	};
729de9f7d1SSebastien Boeuf 	int ret;
739de9f7d1SSebastien Boeuf 	int fd;
749de9f7d1SSebastien Boeuf 
759de9f7d1SSebastien Boeuf 	/* Wait for the server to be ready */
769de9f7d1SSebastien Boeuf 	control_expectln("BIND");
779de9f7d1SSebastien Boeuf 
789de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
799de9f7d1SSebastien Boeuf 
809de9f7d1SSebastien Boeuf 	timeout_begin(TIMEOUT);
819de9f7d1SSebastien Boeuf 	do {
829de9f7d1SSebastien Boeuf 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
839de9f7d1SSebastien Boeuf 		timeout_check("connect");
849de9f7d1SSebastien Boeuf 	} while (ret < 0 && errno == EINTR);
859de9f7d1SSebastien Boeuf 	timeout_end();
869de9f7d1SSebastien Boeuf 
879de9f7d1SSebastien Boeuf 	if (ret != -1) {
889de9f7d1SSebastien Boeuf 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
899de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
909de9f7d1SSebastien Boeuf 	}
919de9f7d1SSebastien Boeuf 	if (errno != ECONNRESET) {
929de9f7d1SSebastien Boeuf 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
939de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
949de9f7d1SSebastien Boeuf 	}
959de9f7d1SSebastien Boeuf 
969de9f7d1SSebastien Boeuf 	/* Notify the server that the client has finished */
979de9f7d1SSebastien Boeuf 	control_writeln("DONE");
989de9f7d1SSebastien Boeuf 
999de9f7d1SSebastien Boeuf 	close(fd);
1009de9f7d1SSebastien Boeuf }
1019de9f7d1SSebastien Boeuf 
1029de9f7d1SSebastien Boeuf static void test_stream_bind_only_server(const struct test_opts *opts)
1039de9f7d1SSebastien Boeuf {
1049de9f7d1SSebastien Boeuf 	union {
1059de9f7d1SSebastien Boeuf 		struct sockaddr sa;
1069de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
1079de9f7d1SSebastien Boeuf 	} addr = {
1089de9f7d1SSebastien Boeuf 		.svm = {
1099de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
1109de9f7d1SSebastien Boeuf 			.svm_port = 1234,
1119de9f7d1SSebastien Boeuf 			.svm_cid = VMADDR_CID_ANY,
1129de9f7d1SSebastien Boeuf 		},
1139de9f7d1SSebastien Boeuf 	};
1149de9f7d1SSebastien Boeuf 	int fd;
1159de9f7d1SSebastien Boeuf 
1169de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1179de9f7d1SSebastien Boeuf 
1189de9f7d1SSebastien Boeuf 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1199de9f7d1SSebastien Boeuf 		perror("bind");
1209de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
1219de9f7d1SSebastien Boeuf 	}
1229de9f7d1SSebastien Boeuf 
1239de9f7d1SSebastien Boeuf 	/* Notify the client that the server is ready */
1249de9f7d1SSebastien Boeuf 	control_writeln("BIND");
1259de9f7d1SSebastien Boeuf 
1269de9f7d1SSebastien Boeuf 	/* Wait for the client to finish */
1279de9f7d1SSebastien Boeuf 	control_expectln("DONE");
1289de9f7d1SSebastien Boeuf 
1299de9f7d1SSebastien Boeuf 	close(fd);
1309de9f7d1SSebastien Boeuf }
1319de9f7d1SSebastien Boeuf 
132cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts)
133cdbcc18dSStefan Hajnoczi {
134cdbcc18dSStefan Hajnoczi 	int fd;
135cdbcc18dSStefan Hajnoczi 
136cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
137cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
138cdbcc18dSStefan Hajnoczi 		perror("connect");
139cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
140cdbcc18dSStefan Hajnoczi 	}
141cdbcc18dSStefan Hajnoczi 
142cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
143cdbcc18dSStefan Hajnoczi 	close(fd);
144cdbcc18dSStefan Hajnoczi }
145cdbcc18dSStefan Hajnoczi 
146cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts)
147cdbcc18dSStefan Hajnoczi {
148cdbcc18dSStefan Hajnoczi 	int fd;
149cdbcc18dSStefan Hajnoczi 
150cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
151cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
152cdbcc18dSStefan Hajnoczi 		perror("accept");
153cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
154cdbcc18dSStefan Hajnoczi 	}
155cdbcc18dSStefan Hajnoczi 
156770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
157770ce007SStefano Garzarella 	 * -EPIPE error on send.
158770ce007SStefano Garzarella 	 */
159770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
160cdbcc18dSStefan Hajnoczi 
161cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
162cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
163cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
164cdbcc18dSStefan Hajnoczi 	close(fd);
165cdbcc18dSStefan Hajnoczi }
166cdbcc18dSStefan Hajnoczi 
167cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts)
168cdbcc18dSStefan Hajnoczi {
169cdbcc18dSStefan Hajnoczi 	int fd;
170cdbcc18dSStefan Hajnoczi 
171cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
172cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
173cdbcc18dSStefan Hajnoczi 		perror("connect");
174cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
175cdbcc18dSStefan Hajnoczi 	}
176cdbcc18dSStefan Hajnoczi 
177770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
178770ce007SStefano Garzarella 	 * -EPIPE error on send.
179770ce007SStefano Garzarella 	 */
180770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
181cdbcc18dSStefan Hajnoczi 
182cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
183cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
184cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
185cdbcc18dSStefan Hajnoczi 	close(fd);
186cdbcc18dSStefan Hajnoczi }
187cdbcc18dSStefan Hajnoczi 
188cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts)
189cdbcc18dSStefan Hajnoczi {
190cdbcc18dSStefan Hajnoczi 	int fd;
191cdbcc18dSStefan Hajnoczi 
192cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
193cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
194cdbcc18dSStefan Hajnoczi 		perror("accept");
195cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
196cdbcc18dSStefan Hajnoczi 	}
197cdbcc18dSStefan Hajnoczi 
198cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
199cdbcc18dSStefan Hajnoczi 	close(fd);
200cdbcc18dSStefan Hajnoczi }
201cdbcc18dSStefan Hajnoczi 
202cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100
203cdbcc18dSStefan Hajnoczi  * concurrent stream connections.
204cdbcc18dSStefan Hajnoczi  */
205cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100
206cdbcc18dSStefan Hajnoczi 
207cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts)
208cdbcc18dSStefan Hajnoczi {
209cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
210cdbcc18dSStefan Hajnoczi 	int i;
211cdbcc18dSStefan Hajnoczi 
212cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
213cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
214cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
215cdbcc18dSStefan Hajnoczi 			perror("connect");
216cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
217cdbcc18dSStefan Hajnoczi 		}
218cdbcc18dSStefan Hajnoczi 	}
219cdbcc18dSStefan Hajnoczi 
220cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
221cdbcc18dSStefan Hajnoczi 		if (i % 2)
222cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
223cdbcc18dSStefan Hajnoczi 		else
224cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
225cdbcc18dSStefan Hajnoczi 	}
226cdbcc18dSStefan Hajnoczi 
227cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
228cdbcc18dSStefan Hajnoczi 		close(fds[i]);
229cdbcc18dSStefan Hajnoczi }
230cdbcc18dSStefan Hajnoczi 
231cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts)
232cdbcc18dSStefan Hajnoczi {
233cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
234cdbcc18dSStefan Hajnoczi 	int i;
235cdbcc18dSStefan Hajnoczi 
236cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
237cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
238cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
239cdbcc18dSStefan Hajnoczi 			perror("accept");
240cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
241cdbcc18dSStefan Hajnoczi 		}
242cdbcc18dSStefan Hajnoczi 	}
243cdbcc18dSStefan Hajnoczi 
244cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
245cdbcc18dSStefan Hajnoczi 		if (i % 2)
246cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
247cdbcc18dSStefan Hajnoczi 		else
248cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
249cdbcc18dSStefan Hajnoczi 	}
250cdbcc18dSStefan Hajnoczi 
251cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
252cdbcc18dSStefan Hajnoczi 		close(fds[i]);
253cdbcc18dSStefan Hajnoczi }
254cdbcc18dSStefan Hajnoczi 
255d6269a93SStefano Garzarella static void test_stream_msg_peek_client(const struct test_opts *opts)
256d6269a93SStefano Garzarella {
257d6269a93SStefano Garzarella 	int fd;
258d6269a93SStefano Garzarella 
259d6269a93SStefano Garzarella 	fd = vsock_stream_connect(opts->peer_cid, 1234);
260d6269a93SStefano Garzarella 	if (fd < 0) {
261d6269a93SStefano Garzarella 		perror("connect");
262d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
263d6269a93SStefano Garzarella 	}
264d6269a93SStefano Garzarella 
265d6269a93SStefano Garzarella 	send_byte(fd, 1, 0);
266d6269a93SStefano Garzarella 	close(fd);
267d6269a93SStefano Garzarella }
268d6269a93SStefano Garzarella 
269d6269a93SStefano Garzarella static void test_stream_msg_peek_server(const struct test_opts *opts)
270d6269a93SStefano Garzarella {
271d6269a93SStefano Garzarella 	int fd;
272d6269a93SStefano Garzarella 
273d6269a93SStefano Garzarella 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
274d6269a93SStefano Garzarella 	if (fd < 0) {
275d6269a93SStefano Garzarella 		perror("accept");
276d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
277d6269a93SStefano Garzarella 	}
278d6269a93SStefano Garzarella 
279d6269a93SStefano Garzarella 	recv_byte(fd, 1, MSG_PEEK);
280d6269a93SStefano Garzarella 	recv_byte(fd, 1, 0);
281d6269a93SStefano Garzarella 	close(fd);
282d6269a93SStefano Garzarella }
283d6269a93SStefano Garzarella 
284*41b792d7SArseny Krasnov #define MESSAGES_CNT 7
285*41b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
286*41b792d7SArseny Krasnov {
287*41b792d7SArseny Krasnov 	int fd;
288*41b792d7SArseny Krasnov 
289*41b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
290*41b792d7SArseny Krasnov 	if (fd < 0) {
291*41b792d7SArseny Krasnov 		perror("connect");
292*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
293*41b792d7SArseny Krasnov 	}
294*41b792d7SArseny Krasnov 
295*41b792d7SArseny Krasnov 	/* Send several messages, one with MSG_EOR flag */
296*41b792d7SArseny Krasnov 	for (int i = 0; i < MESSAGES_CNT; i++)
297*41b792d7SArseny Krasnov 		send_byte(fd, 1, 0);
298*41b792d7SArseny Krasnov 
299*41b792d7SArseny Krasnov 	control_writeln("SENDDONE");
300*41b792d7SArseny Krasnov 	close(fd);
301*41b792d7SArseny Krasnov }
302*41b792d7SArseny Krasnov 
303*41b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
304*41b792d7SArseny Krasnov {
305*41b792d7SArseny Krasnov 	int fd;
306*41b792d7SArseny Krasnov 	char buf[16];
307*41b792d7SArseny Krasnov 	struct msghdr msg = {0};
308*41b792d7SArseny Krasnov 	struct iovec iov = {0};
309*41b792d7SArseny Krasnov 
310*41b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
311*41b792d7SArseny Krasnov 	if (fd < 0) {
312*41b792d7SArseny Krasnov 		perror("accept");
313*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
314*41b792d7SArseny Krasnov 	}
315*41b792d7SArseny Krasnov 
316*41b792d7SArseny Krasnov 	control_expectln("SENDDONE");
317*41b792d7SArseny Krasnov 	iov.iov_base = buf;
318*41b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
319*41b792d7SArseny Krasnov 	msg.msg_iov = &iov;
320*41b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
321*41b792d7SArseny Krasnov 
322*41b792d7SArseny Krasnov 	for (int i = 0; i < MESSAGES_CNT; i++) {
323*41b792d7SArseny Krasnov 		if (recvmsg(fd, &msg, 0) != 1) {
324*41b792d7SArseny Krasnov 			perror("message bound violated");
325*41b792d7SArseny Krasnov 			exit(EXIT_FAILURE);
326*41b792d7SArseny Krasnov 		}
327*41b792d7SArseny Krasnov 	}
328*41b792d7SArseny Krasnov 
329*41b792d7SArseny Krasnov 	close(fd);
330*41b792d7SArseny Krasnov }
331*41b792d7SArseny Krasnov 
332*41b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32
333*41b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
334*41b792d7SArseny Krasnov {
335*41b792d7SArseny Krasnov 	int fd;
336*41b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ];
337*41b792d7SArseny Krasnov 
338*41b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
339*41b792d7SArseny Krasnov 	if (fd < 0) {
340*41b792d7SArseny Krasnov 		perror("connect");
341*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
342*41b792d7SArseny Krasnov 	}
343*41b792d7SArseny Krasnov 
344*41b792d7SArseny Krasnov 	if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
345*41b792d7SArseny Krasnov 		perror("send failed");
346*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
347*41b792d7SArseny Krasnov 	}
348*41b792d7SArseny Krasnov 
349*41b792d7SArseny Krasnov 	control_writeln("SENDDONE");
350*41b792d7SArseny Krasnov 	close(fd);
351*41b792d7SArseny Krasnov }
352*41b792d7SArseny Krasnov 
353*41b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
354*41b792d7SArseny Krasnov {
355*41b792d7SArseny Krasnov 	int fd;
356*41b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ / 2];
357*41b792d7SArseny Krasnov 	struct msghdr msg = {0};
358*41b792d7SArseny Krasnov 	struct iovec iov = {0};
359*41b792d7SArseny Krasnov 
360*41b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
361*41b792d7SArseny Krasnov 	if (fd < 0) {
362*41b792d7SArseny Krasnov 		perror("accept");
363*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
364*41b792d7SArseny Krasnov 	}
365*41b792d7SArseny Krasnov 
366*41b792d7SArseny Krasnov 	control_expectln("SENDDONE");
367*41b792d7SArseny Krasnov 	iov.iov_base = buf;
368*41b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
369*41b792d7SArseny Krasnov 	msg.msg_iov = &iov;
370*41b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
371*41b792d7SArseny Krasnov 
372*41b792d7SArseny Krasnov 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
373*41b792d7SArseny Krasnov 
374*41b792d7SArseny Krasnov 	if (ret != MESSAGE_TRUNC_SZ) {
375*41b792d7SArseny Krasnov 		printf("%zi\n", ret);
376*41b792d7SArseny Krasnov 		perror("MSG_TRUNC doesn't work");
377*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
378*41b792d7SArseny Krasnov 	}
379*41b792d7SArseny Krasnov 
380*41b792d7SArseny Krasnov 	if (!(msg.msg_flags & MSG_TRUNC)) {
381*41b792d7SArseny Krasnov 		fprintf(stderr, "MSG_TRUNC expected\n");
382*41b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
383*41b792d7SArseny Krasnov 	}
384*41b792d7SArseny Krasnov 
385*41b792d7SArseny Krasnov 	close(fd);
386*41b792d7SArseny Krasnov }
387*41b792d7SArseny Krasnov 
388cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
389cdbcc18dSStefan Hajnoczi 	{
390cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
391cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
392cdbcc18dSStefan Hajnoczi 	},
393cdbcc18dSStefan Hajnoczi 	{
3949de9f7d1SSebastien Boeuf 		.name = "SOCK_STREAM bind only",
3959de9f7d1SSebastien Boeuf 		.run_client = test_stream_bind_only_client,
3969de9f7d1SSebastien Boeuf 		.run_server = test_stream_bind_only_server,
3979de9f7d1SSebastien Boeuf 	},
3989de9f7d1SSebastien Boeuf 	{
399cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
400cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
401cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
402cdbcc18dSStefan Hajnoczi 	},
403cdbcc18dSStefan Hajnoczi 	{
404cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
405cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
406cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
407cdbcc18dSStefan Hajnoczi 	},
408cdbcc18dSStefan Hajnoczi 	{
409cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
410cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
411cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
412cdbcc18dSStefan Hajnoczi 	},
413d6269a93SStefano Garzarella 	{
414d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
415d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
416d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
417d6269a93SStefano Garzarella 	},
418*41b792d7SArseny Krasnov 	{
419*41b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET msg bounds",
420*41b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_bounds_client,
421*41b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_bounds_server,
422*41b792d7SArseny Krasnov 	},
423*41b792d7SArseny Krasnov 	{
424*41b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
425*41b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_trunc_client,
426*41b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_trunc_server,
427*41b792d7SArseny Krasnov 	},
428cdbcc18dSStefan Hajnoczi 	{},
429cdbcc18dSStefan Hajnoczi };
430cdbcc18dSStefan Hajnoczi 
431cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
432cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
433cdbcc18dSStefan Hajnoczi 	{
434cdbcc18dSStefan Hajnoczi 		.name = "control-host",
435cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
436cdbcc18dSStefan Hajnoczi 		.val = 'H',
437cdbcc18dSStefan Hajnoczi 	},
438cdbcc18dSStefan Hajnoczi 	{
439cdbcc18dSStefan Hajnoczi 		.name = "control-port",
440cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
441cdbcc18dSStefan Hajnoczi 		.val = 'P',
442cdbcc18dSStefan Hajnoczi 	},
443cdbcc18dSStefan Hajnoczi 	{
444cdbcc18dSStefan Hajnoczi 		.name = "mode",
445cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
446cdbcc18dSStefan Hajnoczi 		.val = 'm',
447cdbcc18dSStefan Hajnoczi 	},
448cdbcc18dSStefan Hajnoczi 	{
449cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
450cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
451cdbcc18dSStefan Hajnoczi 		.val = 'p',
452cdbcc18dSStefan Hajnoczi 	},
453cdbcc18dSStefan Hajnoczi 	{
4545a2b2425SStefano Garzarella 		.name = "list",
4555a2b2425SStefano Garzarella 		.has_arg = no_argument,
4565a2b2425SStefano Garzarella 		.val = 'l',
4575a2b2425SStefano Garzarella 	},
4585a2b2425SStefano Garzarella 	{
4595a2b2425SStefano Garzarella 		.name = "skip",
4605a2b2425SStefano Garzarella 		.has_arg = required_argument,
4615a2b2425SStefano Garzarella 		.val = 's',
4625a2b2425SStefano Garzarella 	},
4635a2b2425SStefano Garzarella 	{
464cdbcc18dSStefan Hajnoczi 		.name = "help",
465cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
466cdbcc18dSStefan Hajnoczi 		.val = '?',
467cdbcc18dSStefan Hajnoczi 	},
468cdbcc18dSStefan Hajnoczi 	{},
469cdbcc18dSStefan Hajnoczi };
470cdbcc18dSStefan Hajnoczi 
471cdbcc18dSStefan Hajnoczi static void usage(void)
472cdbcc18dSStefan Hajnoczi {
4735a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
474cdbcc18dSStefan Hajnoczi 		"\n"
475cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
476cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
477cdbcc18dSStefan Hajnoczi 		"\n"
478cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
479cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
480cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
481cdbcc18dSStefan Hajnoczi 		"\n"
482cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
483cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
484cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
485cdbcc18dSStefan Hajnoczi 		"connect to.\n"
486cdbcc18dSStefan Hajnoczi 		"\n"
4878d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
4888d00b93fSStefano Garzarella 		"\n"
4898d00b93fSStefano Garzarella 		"Options:\n"
4908d00b93fSStefano Garzarella 		"  --help                 This help message\n"
4918d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
4928d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
4938d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
4948d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
4958d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
4968d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
4978d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
4988d00b93fSStefano Garzarella 		);
499cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
500cdbcc18dSStefan Hajnoczi }
501cdbcc18dSStefan Hajnoczi 
502cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
503cdbcc18dSStefan Hajnoczi {
504cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
505cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
506cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
507cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
508cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
509cdbcc18dSStefan Hajnoczi 	};
510cdbcc18dSStefan Hajnoczi 
511cdbcc18dSStefan Hajnoczi 	init_signals();
512cdbcc18dSStefan Hajnoczi 
513cdbcc18dSStefan Hajnoczi 	for (;;) {
514cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
515cdbcc18dSStefan Hajnoczi 
516cdbcc18dSStefan Hajnoczi 		if (opt == -1)
517cdbcc18dSStefan Hajnoczi 			break;
518cdbcc18dSStefan Hajnoczi 
519cdbcc18dSStefan Hajnoczi 		switch (opt) {
520cdbcc18dSStefan Hajnoczi 		case 'H':
521cdbcc18dSStefan Hajnoczi 			control_host = optarg;
522cdbcc18dSStefan Hajnoczi 			break;
523cdbcc18dSStefan Hajnoczi 		case 'm':
524cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
525cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
526cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
527cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
528cdbcc18dSStefan Hajnoczi 			else {
529cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
530cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
531cdbcc18dSStefan Hajnoczi 			}
532cdbcc18dSStefan Hajnoczi 			break;
533cdbcc18dSStefan Hajnoczi 		case 'p':
534cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
535cdbcc18dSStefan Hajnoczi 			break;
536cdbcc18dSStefan Hajnoczi 		case 'P':
537cdbcc18dSStefan Hajnoczi 			control_port = optarg;
538cdbcc18dSStefan Hajnoczi 			break;
5395a2b2425SStefano Garzarella 		case 'l':
5405a2b2425SStefano Garzarella 			list_tests(test_cases);
5415a2b2425SStefano Garzarella 			break;
5425a2b2425SStefano Garzarella 		case 's':
5435a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
5445a2b2425SStefano Garzarella 				  optarg);
5455a2b2425SStefano Garzarella 			break;
546cdbcc18dSStefan Hajnoczi 		case '?':
547cdbcc18dSStefan Hajnoczi 		default:
548cdbcc18dSStefan Hajnoczi 			usage();
549cdbcc18dSStefan Hajnoczi 		}
550cdbcc18dSStefan Hajnoczi 	}
551cdbcc18dSStefan Hajnoczi 
552cdbcc18dSStefan Hajnoczi 	if (!control_port)
553cdbcc18dSStefan Hajnoczi 		usage();
554cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
555cdbcc18dSStefan Hajnoczi 		usage();
556cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
557cdbcc18dSStefan Hajnoczi 		usage();
558cdbcc18dSStefan Hajnoczi 
559cdbcc18dSStefan Hajnoczi 	if (!control_host) {
560cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
561cdbcc18dSStefan Hajnoczi 			usage();
562cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
563cdbcc18dSStefan Hajnoczi 	}
564cdbcc18dSStefan Hajnoczi 
565cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
566cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
567cdbcc18dSStefan Hajnoczi 
568cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
569cdbcc18dSStefan Hajnoczi 
570cdbcc18dSStefan Hajnoczi 	control_cleanup();
571cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
572cdbcc18dSStefan Hajnoczi }
573