1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20b025033SStefan Hajnoczi /*
30b025033SStefan Hajnoczi  * vsock_diag_test - vsock_diag.ko test suite
40b025033SStefan Hajnoczi  *
50b025033SStefan Hajnoczi  * Copyright (C) 2017 Red Hat, Inc.
60b025033SStefan Hajnoczi  *
70b025033SStefan Hajnoczi  * Author: Stefan Hajnoczi <stefanha@redhat.com>
80b025033SStefan Hajnoczi  */
90b025033SStefan Hajnoczi 
100b025033SStefan Hajnoczi #include <getopt.h>
110b025033SStefan Hajnoczi #include <stdio.h>
120b025033SStefan Hajnoczi #include <stdlib.h>
130b025033SStefan Hajnoczi #include <string.h>
140b025033SStefan Hajnoczi #include <errno.h>
150b025033SStefan Hajnoczi #include <unistd.h>
160b025033SStefan Hajnoczi #include <sys/stat.h>
170b025033SStefan Hajnoczi #include <sys/types.h>
180b025033SStefan Hajnoczi #include <linux/list.h>
190b025033SStefan Hajnoczi #include <linux/net.h>
200b025033SStefan Hajnoczi #include <linux/netlink.h>
210b025033SStefan Hajnoczi #include <linux/sock_diag.h>
2243985468SStefan Hajnoczi #include <linux/vm_sockets_diag.h>
230b025033SStefan Hajnoczi #include <netinet/tcp.h>
240b025033SStefan Hajnoczi 
250b025033SStefan Hajnoczi #include "timeout.h"
260b025033SStefan Hajnoczi #include "control.h"
27df7e0e0dSStefan Hajnoczi #include "util.h"
280b025033SStefan Hajnoczi 
290b025033SStefan Hajnoczi /* Per-socket status */
300b025033SStefan Hajnoczi struct vsock_stat {
310b025033SStefan Hajnoczi 	struct list_head list;
320b025033SStefan Hajnoczi 	struct vsock_diag_msg msg;
330b025033SStefan Hajnoczi };
340b025033SStefan Hajnoczi 
sock_type_str(int type)350b025033SStefan Hajnoczi static const char *sock_type_str(int type)
360b025033SStefan Hajnoczi {
370b025033SStefan Hajnoczi 	switch (type) {
380b025033SStefan Hajnoczi 	case SOCK_DGRAM:
390b025033SStefan Hajnoczi 		return "DGRAM";
400b025033SStefan Hajnoczi 	case SOCK_STREAM:
410b025033SStefan Hajnoczi 		return "STREAM";
420b025033SStefan Hajnoczi 	default:
430b025033SStefan Hajnoczi 		return "INVALID TYPE";
440b025033SStefan Hajnoczi 	}
450b025033SStefan Hajnoczi }
460b025033SStefan Hajnoczi 
sock_state_str(int state)470b025033SStefan Hajnoczi static const char *sock_state_str(int state)
480b025033SStefan Hajnoczi {
490b025033SStefan Hajnoczi 	switch (state) {
500b025033SStefan Hajnoczi 	case TCP_CLOSE:
510b025033SStefan Hajnoczi 		return "UNCONNECTED";
520b025033SStefan Hajnoczi 	case TCP_SYN_SENT:
530b025033SStefan Hajnoczi 		return "CONNECTING";
540b025033SStefan Hajnoczi 	case TCP_ESTABLISHED:
550b025033SStefan Hajnoczi 		return "CONNECTED";
560b025033SStefan Hajnoczi 	case TCP_CLOSING:
570b025033SStefan Hajnoczi 		return "DISCONNECTING";
580b025033SStefan Hajnoczi 	case TCP_LISTEN:
590b025033SStefan Hajnoczi 		return "LISTEN";
600b025033SStefan Hajnoczi 	default:
610b025033SStefan Hajnoczi 		return "INVALID STATE";
620b025033SStefan Hajnoczi 	}
630b025033SStefan Hajnoczi }
640b025033SStefan Hajnoczi 
sock_shutdown_str(int shutdown)650b025033SStefan Hajnoczi static const char *sock_shutdown_str(int shutdown)
660b025033SStefan Hajnoczi {
670b025033SStefan Hajnoczi 	switch (shutdown) {
680b025033SStefan Hajnoczi 	case 1:
690b025033SStefan Hajnoczi 		return "RCV_SHUTDOWN";
700b025033SStefan Hajnoczi 	case 2:
710b025033SStefan Hajnoczi 		return "SEND_SHUTDOWN";
720b025033SStefan Hajnoczi 	case 3:
730b025033SStefan Hajnoczi 		return "RCV_SHUTDOWN | SEND_SHUTDOWN";
740b025033SStefan Hajnoczi 	default:
750b025033SStefan Hajnoczi 		return "0";
760b025033SStefan Hajnoczi 	}
770b025033SStefan Hajnoczi }
780b025033SStefan Hajnoczi 
print_vsock_addr(FILE * fp,unsigned int cid,unsigned int port)790b025033SStefan Hajnoczi static void print_vsock_addr(FILE *fp, unsigned int cid, unsigned int port)
800b025033SStefan Hajnoczi {
810b025033SStefan Hajnoczi 	if (cid == VMADDR_CID_ANY)
820b025033SStefan Hajnoczi 		fprintf(fp, "*:");
830b025033SStefan Hajnoczi 	else
840b025033SStefan Hajnoczi 		fprintf(fp, "%u:", cid);
850b025033SStefan Hajnoczi 
860b025033SStefan Hajnoczi 	if (port == VMADDR_PORT_ANY)
870b025033SStefan Hajnoczi 		fprintf(fp, "*");
880b025033SStefan Hajnoczi 	else
890b025033SStefan Hajnoczi 		fprintf(fp, "%u", port);
900b025033SStefan Hajnoczi }
910b025033SStefan Hajnoczi 
print_vsock_stat(FILE * fp,struct vsock_stat * st)920b025033SStefan Hajnoczi static void print_vsock_stat(FILE *fp, struct vsock_stat *st)
930b025033SStefan Hajnoczi {
940b025033SStefan Hajnoczi 	print_vsock_addr(fp, st->msg.vdiag_src_cid, st->msg.vdiag_src_port);
950b025033SStefan Hajnoczi 	fprintf(fp, " ");
960b025033SStefan Hajnoczi 	print_vsock_addr(fp, st->msg.vdiag_dst_cid, st->msg.vdiag_dst_port);
970b025033SStefan Hajnoczi 	fprintf(fp, " %s %s %s %u\n",
980b025033SStefan Hajnoczi 		sock_type_str(st->msg.vdiag_type),
990b025033SStefan Hajnoczi 		sock_state_str(st->msg.vdiag_state),
1000b025033SStefan Hajnoczi 		sock_shutdown_str(st->msg.vdiag_shutdown),
1010b025033SStefan Hajnoczi 		st->msg.vdiag_ino);
1020b025033SStefan Hajnoczi }
1030b025033SStefan Hajnoczi 
print_vsock_stats(FILE * fp,struct list_head * head)1040b025033SStefan Hajnoczi static void print_vsock_stats(FILE *fp, struct list_head *head)
1050b025033SStefan Hajnoczi {
1060b025033SStefan Hajnoczi 	struct vsock_stat *st;
1070b025033SStefan Hajnoczi 
1080b025033SStefan Hajnoczi 	list_for_each_entry(st, head, list)
1090b025033SStefan Hajnoczi 		print_vsock_stat(fp, st);
1100b025033SStefan Hajnoczi }
1110b025033SStefan Hajnoczi 
find_vsock_stat(struct list_head * head,int fd)1120b025033SStefan Hajnoczi static struct vsock_stat *find_vsock_stat(struct list_head *head, int fd)
1130b025033SStefan Hajnoczi {
1140b025033SStefan Hajnoczi 	struct vsock_stat *st;
1150b025033SStefan Hajnoczi 	struct stat stat;
1160b025033SStefan Hajnoczi 
1170b025033SStefan Hajnoczi 	if (fstat(fd, &stat) < 0) {
1180b025033SStefan Hajnoczi 		perror("fstat");
1190b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
1200b025033SStefan Hajnoczi 	}
1210b025033SStefan Hajnoczi 
1220b025033SStefan Hajnoczi 	list_for_each_entry(st, head, list)
1230b025033SStefan Hajnoczi 		if (st->msg.vdiag_ino == stat.st_ino)
1240b025033SStefan Hajnoczi 			return st;
1250b025033SStefan Hajnoczi 
1260b025033SStefan Hajnoczi 	fprintf(stderr, "cannot find fd %d\n", fd);
1270b025033SStefan Hajnoczi 	exit(EXIT_FAILURE);
1280b025033SStefan Hajnoczi }
1290b025033SStefan Hajnoczi 
check_no_sockets(struct list_head * head)1300b025033SStefan Hajnoczi static void check_no_sockets(struct list_head *head)
1310b025033SStefan Hajnoczi {
1320b025033SStefan Hajnoczi 	if (!list_empty(head)) {
1330b025033SStefan Hajnoczi 		fprintf(stderr, "expected no sockets\n");
1340b025033SStefan Hajnoczi 		print_vsock_stats(stderr, head);
1350b025033SStefan Hajnoczi 		exit(1);
1360b025033SStefan Hajnoczi 	}
1370b025033SStefan Hajnoczi }
1380b025033SStefan Hajnoczi 
check_num_sockets(struct list_head * head,int expected)1390b025033SStefan Hajnoczi static void check_num_sockets(struct list_head *head, int expected)
1400b025033SStefan Hajnoczi {
1410b025033SStefan Hajnoczi 	struct list_head *node;
1420b025033SStefan Hajnoczi 	int n = 0;
1430b025033SStefan Hajnoczi 
1440b025033SStefan Hajnoczi 	list_for_each(node, head)
1450b025033SStefan Hajnoczi 		n++;
1460b025033SStefan Hajnoczi 
1470b025033SStefan Hajnoczi 	if (n != expected) {
1480b025033SStefan Hajnoczi 		fprintf(stderr, "expected %d sockets, found %d\n",
1490b025033SStefan Hajnoczi 			expected, n);
1500b025033SStefan Hajnoczi 		print_vsock_stats(stderr, head);
1510b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
1520b025033SStefan Hajnoczi 	}
1530b025033SStefan Hajnoczi }
1540b025033SStefan Hajnoczi 
check_socket_state(struct vsock_stat * st,__u8 state)1550b025033SStefan Hajnoczi static void check_socket_state(struct vsock_stat *st, __u8 state)
1560b025033SStefan Hajnoczi {
1570b025033SStefan Hajnoczi 	if (st->msg.vdiag_state != state) {
1580b025033SStefan Hajnoczi 		fprintf(stderr, "expected socket state %#x, got %#x\n",
1590b025033SStefan Hajnoczi 			state, st->msg.vdiag_state);
1600b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
1610b025033SStefan Hajnoczi 	}
1620b025033SStefan Hajnoczi }
1630b025033SStefan Hajnoczi 
send_req(int fd)1640b025033SStefan Hajnoczi static void send_req(int fd)
1650b025033SStefan Hajnoczi {
1660b025033SStefan Hajnoczi 	struct sockaddr_nl nladdr = {
1670b025033SStefan Hajnoczi 		.nl_family = AF_NETLINK,
1680b025033SStefan Hajnoczi 	};
1690b025033SStefan Hajnoczi 	struct {
1700b025033SStefan Hajnoczi 		struct nlmsghdr nlh;
1710b025033SStefan Hajnoczi 		struct vsock_diag_req vreq;
1720b025033SStefan Hajnoczi 	} req = {
1730b025033SStefan Hajnoczi 		.nlh = {
1740b025033SStefan Hajnoczi 			.nlmsg_len = sizeof(req),
1750b025033SStefan Hajnoczi 			.nlmsg_type = SOCK_DIAG_BY_FAMILY,
1760b025033SStefan Hajnoczi 			.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
1770b025033SStefan Hajnoczi 		},
1780b025033SStefan Hajnoczi 		.vreq = {
1790b025033SStefan Hajnoczi 			.sdiag_family = AF_VSOCK,
1800b025033SStefan Hajnoczi 			.vdiag_states = ~(__u32)0,
1810b025033SStefan Hajnoczi 		},
1820b025033SStefan Hajnoczi 	};
1830b025033SStefan Hajnoczi 	struct iovec iov = {
1840b025033SStefan Hajnoczi 		.iov_base = &req,
1850b025033SStefan Hajnoczi 		.iov_len = sizeof(req),
1860b025033SStefan Hajnoczi 	};
1870b025033SStefan Hajnoczi 	struct msghdr msg = {
1880b025033SStefan Hajnoczi 		.msg_name = &nladdr,
1890b025033SStefan Hajnoczi 		.msg_namelen = sizeof(nladdr),
1900b025033SStefan Hajnoczi 		.msg_iov = &iov,
1910b025033SStefan Hajnoczi 		.msg_iovlen = 1,
1920b025033SStefan Hajnoczi 	};
1930b025033SStefan Hajnoczi 
1940b025033SStefan Hajnoczi 	for (;;) {
1950b025033SStefan Hajnoczi 		if (sendmsg(fd, &msg, 0) < 0) {
1960b025033SStefan Hajnoczi 			if (errno == EINTR)
1970b025033SStefan Hajnoczi 				continue;
1980b025033SStefan Hajnoczi 
1990b025033SStefan Hajnoczi 			perror("sendmsg");
2000b025033SStefan Hajnoczi 			exit(EXIT_FAILURE);
2010b025033SStefan Hajnoczi 		}
2020b025033SStefan Hajnoczi 
2030b025033SStefan Hajnoczi 		return;
2040b025033SStefan Hajnoczi 	}
2050b025033SStefan Hajnoczi }
2060b025033SStefan Hajnoczi 
recv_resp(int fd,void * buf,size_t len)2070b025033SStefan Hajnoczi static ssize_t recv_resp(int fd, void *buf, size_t len)
2080b025033SStefan Hajnoczi {
2090b025033SStefan Hajnoczi 	struct sockaddr_nl nladdr = {
2100b025033SStefan Hajnoczi 		.nl_family = AF_NETLINK,
2110b025033SStefan Hajnoczi 	};
2120b025033SStefan Hajnoczi 	struct iovec iov = {
2130b025033SStefan Hajnoczi 		.iov_base = buf,
2140b025033SStefan Hajnoczi 		.iov_len = len,
2150b025033SStefan Hajnoczi 	};
2160b025033SStefan Hajnoczi 	struct msghdr msg = {
2170b025033SStefan Hajnoczi 		.msg_name = &nladdr,
2180b025033SStefan Hajnoczi 		.msg_namelen = sizeof(nladdr),
2190b025033SStefan Hajnoczi 		.msg_iov = &iov,
2200b025033SStefan Hajnoczi 		.msg_iovlen = 1,
2210b025033SStefan Hajnoczi 	};
2220b025033SStefan Hajnoczi 	ssize_t ret;
2230b025033SStefan Hajnoczi 
2240b025033SStefan Hajnoczi 	do {
2250b025033SStefan Hajnoczi 		ret = recvmsg(fd, &msg, 0);
2260b025033SStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
2270b025033SStefan Hajnoczi 
2280b025033SStefan Hajnoczi 	if (ret < 0) {
2290b025033SStefan Hajnoczi 		perror("recvmsg");
2300b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
2310b025033SStefan Hajnoczi 	}
2320b025033SStefan Hajnoczi 
2330b025033SStefan Hajnoczi 	return ret;
2340b025033SStefan Hajnoczi }
2350b025033SStefan Hajnoczi 
add_vsock_stat(struct list_head * sockets,const struct vsock_diag_msg * resp)2360b025033SStefan Hajnoczi static void add_vsock_stat(struct list_head *sockets,
2370b025033SStefan Hajnoczi 			   const struct vsock_diag_msg *resp)
2380b025033SStefan Hajnoczi {
2390b025033SStefan Hajnoczi 	struct vsock_stat *st;
2400b025033SStefan Hajnoczi 
2410b025033SStefan Hajnoczi 	st = malloc(sizeof(*st));
2420b025033SStefan Hajnoczi 	if (!st) {
2430b025033SStefan Hajnoczi 		perror("malloc");
2440b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
2450b025033SStefan Hajnoczi 	}
2460b025033SStefan Hajnoczi 
2470b025033SStefan Hajnoczi 	st->msg = *resp;
2480b025033SStefan Hajnoczi 	list_add_tail(&st->list, sockets);
2490b025033SStefan Hajnoczi }
2500b025033SStefan Hajnoczi 
2510b025033SStefan Hajnoczi /*
2520b025033SStefan Hajnoczi  * Read vsock stats into a list.
2530b025033SStefan Hajnoczi  */
read_vsock_stat(struct list_head * sockets)2540b025033SStefan Hajnoczi static void read_vsock_stat(struct list_head *sockets)
2550b025033SStefan Hajnoczi {
2560b025033SStefan Hajnoczi 	long buf[8192 / sizeof(long)];
2570b025033SStefan Hajnoczi 	int fd;
2580b025033SStefan Hajnoczi 
2590b025033SStefan Hajnoczi 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
2600b025033SStefan Hajnoczi 	if (fd < 0) {
2610b025033SStefan Hajnoczi 		perror("socket");
2620b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
2630b025033SStefan Hajnoczi 	}
2640b025033SStefan Hajnoczi 
2650b025033SStefan Hajnoczi 	send_req(fd);
2660b025033SStefan Hajnoczi 
2670b025033SStefan Hajnoczi 	for (;;) {
2680b025033SStefan Hajnoczi 		const struct nlmsghdr *h;
2690b025033SStefan Hajnoczi 		ssize_t ret;
2700b025033SStefan Hajnoczi 
2710b025033SStefan Hajnoczi 		ret = recv_resp(fd, buf, sizeof(buf));
2720b025033SStefan Hajnoczi 		if (ret == 0)
2730b025033SStefan Hajnoczi 			goto done;
2740b025033SStefan Hajnoczi 		if (ret < sizeof(*h)) {
2750b025033SStefan Hajnoczi 			fprintf(stderr, "short read of %zd bytes\n", ret);
2760b025033SStefan Hajnoczi 			exit(EXIT_FAILURE);
2770b025033SStefan Hajnoczi 		}
2780b025033SStefan Hajnoczi 
2790b025033SStefan Hajnoczi 		h = (struct nlmsghdr *)buf;
2800b025033SStefan Hajnoczi 
2810b025033SStefan Hajnoczi 		while (NLMSG_OK(h, ret)) {
2820b025033SStefan Hajnoczi 			if (h->nlmsg_type == NLMSG_DONE)
2830b025033SStefan Hajnoczi 				goto done;
2840b025033SStefan Hajnoczi 
2850b025033SStefan Hajnoczi 			if (h->nlmsg_type == NLMSG_ERROR) {
2860b025033SStefan Hajnoczi 				const struct nlmsgerr *err = NLMSG_DATA(h);
2870b025033SStefan Hajnoczi 
2880b025033SStefan Hajnoczi 				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
2890b025033SStefan Hajnoczi 					fprintf(stderr, "NLMSG_ERROR\n");
2900b025033SStefan Hajnoczi 				else {
2910b025033SStefan Hajnoczi 					errno = -err->error;
2920b025033SStefan Hajnoczi 					perror("NLMSG_ERROR");
2930b025033SStefan Hajnoczi 				}
2940b025033SStefan Hajnoczi 
2950b025033SStefan Hajnoczi 				exit(EXIT_FAILURE);
2960b025033SStefan Hajnoczi 			}
2970b025033SStefan Hajnoczi 
2980b025033SStefan Hajnoczi 			if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
2990b025033SStefan Hajnoczi 				fprintf(stderr, "unexpected nlmsg_type %#x\n",
3000b025033SStefan Hajnoczi 					h->nlmsg_type);
3010b025033SStefan Hajnoczi 				exit(EXIT_FAILURE);
3020b025033SStefan Hajnoczi 			}
3030b025033SStefan Hajnoczi 			if (h->nlmsg_len <
3040b025033SStefan Hajnoczi 			    NLMSG_LENGTH(sizeof(struct vsock_diag_msg))) {
3050b025033SStefan Hajnoczi 				fprintf(stderr, "short vsock_diag_msg\n");
3060b025033SStefan Hajnoczi 				exit(EXIT_FAILURE);
3070b025033SStefan Hajnoczi 			}
3080b025033SStefan Hajnoczi 
3090b025033SStefan Hajnoczi 			add_vsock_stat(sockets, NLMSG_DATA(h));
3100b025033SStefan Hajnoczi 
3110b025033SStefan Hajnoczi 			h = NLMSG_NEXT(h, ret);
3120b025033SStefan Hajnoczi 		}
3130b025033SStefan Hajnoczi 	}
3140b025033SStefan Hajnoczi 
3150b025033SStefan Hajnoczi done:
3160b025033SStefan Hajnoczi 	close(fd);
3170b025033SStefan Hajnoczi }
3180b025033SStefan Hajnoczi 
free_sock_stat(struct list_head * sockets)3190b025033SStefan Hajnoczi static void free_sock_stat(struct list_head *sockets)
3200b025033SStefan Hajnoczi {
3210b025033SStefan Hajnoczi 	struct vsock_stat *st;
3220b025033SStefan Hajnoczi 	struct vsock_stat *next;
3230b025033SStefan Hajnoczi 
3240b025033SStefan Hajnoczi 	list_for_each_entry_safe(st, next, sockets, list)
3250b025033SStefan Hajnoczi 		free(st);
3260b025033SStefan Hajnoczi }
3270b025033SStefan Hajnoczi 
test_no_sockets(const struct test_opts * opts)328df7e0e0dSStefan Hajnoczi static void test_no_sockets(const struct test_opts *opts)
3290b025033SStefan Hajnoczi {
3300b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
3310b025033SStefan Hajnoczi 
3320b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
3330b025033SStefan Hajnoczi 
3340b025033SStefan Hajnoczi 	check_no_sockets(&sockets);
3350b025033SStefan Hajnoczi }
3360b025033SStefan Hajnoczi 
test_listen_socket_server(const struct test_opts * opts)337df7e0e0dSStefan Hajnoczi static void test_listen_socket_server(const struct test_opts *opts)
3380b025033SStefan Hajnoczi {
3390b025033SStefan Hajnoczi 	union {
3400b025033SStefan Hajnoczi 		struct sockaddr sa;
3410b025033SStefan Hajnoczi 		struct sockaddr_vm svm;
3420b025033SStefan Hajnoczi 	} addr = {
3430b025033SStefan Hajnoczi 		.svm = {
3440b025033SStefan Hajnoczi 			.svm_family = AF_VSOCK,
3450b025033SStefan Hajnoczi 			.svm_port = 1234,
3460b025033SStefan Hajnoczi 			.svm_cid = VMADDR_CID_ANY,
3470b025033SStefan Hajnoczi 		},
3480b025033SStefan Hajnoczi 	};
3490b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
3500b025033SStefan Hajnoczi 	struct vsock_stat *st;
3510b025033SStefan Hajnoczi 	int fd;
3520b025033SStefan Hajnoczi 
3530b025033SStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
3540b025033SStefan Hajnoczi 
3550b025033SStefan Hajnoczi 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
3560b025033SStefan Hajnoczi 		perror("bind");
3570b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
3580b025033SStefan Hajnoczi 	}
3590b025033SStefan Hajnoczi 
3600b025033SStefan Hajnoczi 	if (listen(fd, 1) < 0) {
3610b025033SStefan Hajnoczi 		perror("listen");
3620b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
3630b025033SStefan Hajnoczi 	}
3640b025033SStefan Hajnoczi 
3650b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
3660b025033SStefan Hajnoczi 
3670b025033SStefan Hajnoczi 	check_num_sockets(&sockets, 1);
3680b025033SStefan Hajnoczi 	st = find_vsock_stat(&sockets, fd);
3690b025033SStefan Hajnoczi 	check_socket_state(st, TCP_LISTEN);
3700b025033SStefan Hajnoczi 
3710b025033SStefan Hajnoczi 	close(fd);
3720b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
3730b025033SStefan Hajnoczi }
3740b025033SStefan Hajnoczi 
test_connect_client(const struct test_opts * opts)375df7e0e0dSStefan Hajnoczi static void test_connect_client(const struct test_opts *opts)
3760b025033SStefan Hajnoczi {
3770b025033SStefan Hajnoczi 	int fd;
3780b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
3790b025033SStefan Hajnoczi 	struct vsock_stat *st;
3800b025033SStefan Hajnoczi 
3819bb8a29dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
3829bb8a29dSStefan Hajnoczi 	if (fd < 0) {
3830b025033SStefan Hajnoczi 		perror("connect");
3840b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
3850b025033SStefan Hajnoczi 	}
3860b025033SStefan Hajnoczi 
3870b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
3880b025033SStefan Hajnoczi 
3890b025033SStefan Hajnoczi 	check_num_sockets(&sockets, 1);
3900b025033SStefan Hajnoczi 	st = find_vsock_stat(&sockets, fd);
3910b025033SStefan Hajnoczi 	check_socket_state(st, TCP_ESTABLISHED);
3920b025033SStefan Hajnoczi 
3930b025033SStefan Hajnoczi 	control_expectln("DONE");
3940b025033SStefan Hajnoczi 	control_writeln("DONE");
3950b025033SStefan Hajnoczi 
3960b025033SStefan Hajnoczi 	close(fd);
3970b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
3980b025033SStefan Hajnoczi }
3990b025033SStefan Hajnoczi 
test_connect_server(const struct test_opts * opts)400df7e0e0dSStefan Hajnoczi static void test_connect_server(const struct test_opts *opts)
4010b025033SStefan Hajnoczi {
4020b025033SStefan Hajnoczi 	struct vsock_stat *st;
4039bb8a29dSStefan Hajnoczi 	LIST_HEAD(sockets);
4040b025033SStefan Hajnoczi 	int client_fd;
4050b025033SStefan Hajnoczi 
4069bb8a29dSStefan Hajnoczi 	client_fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
4070b025033SStefan Hajnoczi 	if (client_fd < 0) {
4080b025033SStefan Hajnoczi 		perror("accept");
4090b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4100b025033SStefan Hajnoczi 	}
4110b025033SStefan Hajnoczi 
4120b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
4130b025033SStefan Hajnoczi 
4149bb8a29dSStefan Hajnoczi 	check_num_sockets(&sockets, 1);
4150b025033SStefan Hajnoczi 	st = find_vsock_stat(&sockets, client_fd);
4160b025033SStefan Hajnoczi 	check_socket_state(st, TCP_ESTABLISHED);
4170b025033SStefan Hajnoczi 
4180b025033SStefan Hajnoczi 	control_writeln("DONE");
4190b025033SStefan Hajnoczi 	control_expectln("DONE");
4200b025033SStefan Hajnoczi 
4210b025033SStefan Hajnoczi 	close(client_fd);
4220b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
4230b025033SStefan Hajnoczi }
4240b025033SStefan Hajnoczi 
425df7e0e0dSStefan Hajnoczi static struct test_case test_cases[] = {
4260b025033SStefan Hajnoczi 	{
4270b025033SStefan Hajnoczi 		.name = "No sockets",
4280b025033SStefan Hajnoczi 		.run_server = test_no_sockets,
4290b025033SStefan Hajnoczi 	},
4300b025033SStefan Hajnoczi 	{
4310b025033SStefan Hajnoczi 		.name = "Listen socket",
4320b025033SStefan Hajnoczi 		.run_server = test_listen_socket_server,
4330b025033SStefan Hajnoczi 	},
4340b025033SStefan Hajnoczi 	{
4350b025033SStefan Hajnoczi 		.name = "Connect",
4360b025033SStefan Hajnoczi 		.run_client = test_connect_client,
4370b025033SStefan Hajnoczi 		.run_server = test_connect_server,
4380b025033SStefan Hajnoczi 	},
4390b025033SStefan Hajnoczi 	{},
4400b025033SStefan Hajnoczi };
4410b025033SStefan Hajnoczi 
4420b025033SStefan Hajnoczi static const char optstring[] = "";
4430b025033SStefan Hajnoczi static const struct option longopts[] = {
4440b025033SStefan Hajnoczi 	{
4450b025033SStefan Hajnoczi 		.name = "control-host",
4460b025033SStefan Hajnoczi 		.has_arg = required_argument,
4470b025033SStefan Hajnoczi 		.val = 'H',
4480b025033SStefan Hajnoczi 	},
4490b025033SStefan Hajnoczi 	{
4500b025033SStefan Hajnoczi 		.name = "control-port",
4510b025033SStefan Hajnoczi 		.has_arg = required_argument,
4520b025033SStefan Hajnoczi 		.val = 'P',
4530b025033SStefan Hajnoczi 	},
4540b025033SStefan Hajnoczi 	{
4550b025033SStefan Hajnoczi 		.name = "mode",
4560b025033SStefan Hajnoczi 		.has_arg = required_argument,
4570b025033SStefan Hajnoczi 		.val = 'm',
4580b025033SStefan Hajnoczi 	},
4590b025033SStefan Hajnoczi 	{
4600b025033SStefan Hajnoczi 		.name = "peer-cid",
4610b025033SStefan Hajnoczi 		.has_arg = required_argument,
4620b025033SStefan Hajnoczi 		.val = 'p',
4630b025033SStefan Hajnoczi 	},
4640b025033SStefan Hajnoczi 	{
4655a2b2425SStefano Garzarella 		.name = "list",
4665a2b2425SStefano Garzarella 		.has_arg = no_argument,
4675a2b2425SStefano Garzarella 		.val = 'l',
4685a2b2425SStefano Garzarella 	},
4695a2b2425SStefano Garzarella 	{
4705a2b2425SStefano Garzarella 		.name = "skip",
4715a2b2425SStefano Garzarella 		.has_arg = required_argument,
4725a2b2425SStefano Garzarella 		.val = 's',
4735a2b2425SStefano Garzarella 	},
4745a2b2425SStefano Garzarella 	{
4750b025033SStefan Hajnoczi 		.name = "help",
4760b025033SStefan Hajnoczi 		.has_arg = no_argument,
4770b025033SStefan Hajnoczi 		.val = '?',
4780b025033SStefan Hajnoczi 	},
4790b025033SStefan Hajnoczi 	{},
4800b025033SStefan Hajnoczi };
4810b025033SStefan Hajnoczi 
usage(void)4820b025033SStefan Hajnoczi static void usage(void)
4830b025033SStefan Hajnoczi {
4845a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
4850b025033SStefan Hajnoczi 		"\n"
4860b025033SStefan Hajnoczi 		"  Server: vsock_diag_test --control-port=1234 --mode=server --peer-cid=3\n"
4870b025033SStefan Hajnoczi 		"  Client: vsock_diag_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
4880b025033SStefan Hajnoczi 		"\n"
4890b025033SStefan Hajnoczi 		"Run vsock_diag.ko tests.  Must be launched in both\n"
4900b025033SStefan Hajnoczi 		"guest and host.  One side must use --mode=client and\n"
4910b025033SStefan Hajnoczi 		"the other side must use --mode=server.\n"
4920b025033SStefan Hajnoczi 		"\n"
4930b025033SStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
4940b025033SStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
4950b025033SStefan Hajnoczi 		"listen address and the client requires an address to\n"
4960b025033SStefan Hajnoczi 		"connect to.\n"
4970b025033SStefan Hajnoczi 		"\n"
4988d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
4998d00b93fSStefano Garzarella 		"\n"
5008d00b93fSStefano Garzarella 		"Options:\n"
5018d00b93fSStefano Garzarella 		"  --help                 This help message\n"
5028d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
5038d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
5048d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
5058d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
5068d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
5078d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
5088d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
5098d00b93fSStefano Garzarella 		);
5100b025033SStefan Hajnoczi 	exit(EXIT_FAILURE);
5110b025033SStefan Hajnoczi }
5120b025033SStefan Hajnoczi 
main(int argc,char ** argv)5130b025033SStefan Hajnoczi int main(int argc, char **argv)
5140b025033SStefan Hajnoczi {
5150b025033SStefan Hajnoczi 	const char *control_host = NULL;
5160b025033SStefan Hajnoczi 	const char *control_port = NULL;
517df7e0e0dSStefan Hajnoczi 	struct test_opts opts = {
518df7e0e0dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
519df7e0e0dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
520df7e0e0dSStefan Hajnoczi 	};
5210b025033SStefan Hajnoczi 
5220b025033SStefan Hajnoczi 	init_signals();
5230b025033SStefan Hajnoczi 
5240b025033SStefan Hajnoczi 	for (;;) {
5250b025033SStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
5260b025033SStefan Hajnoczi 
5270b025033SStefan Hajnoczi 		if (opt == -1)
5280b025033SStefan Hajnoczi 			break;
5290b025033SStefan Hajnoczi 
5300b025033SStefan Hajnoczi 		switch (opt) {
5310b025033SStefan Hajnoczi 		case 'H':
5320b025033SStefan Hajnoczi 			control_host = optarg;
5330b025033SStefan Hajnoczi 			break;
5340b025033SStefan Hajnoczi 		case 'm':
5350b025033SStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
536df7e0e0dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
5370b025033SStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
538df7e0e0dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
5390b025033SStefan Hajnoczi 			else {
5400b025033SStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
5410b025033SStefan Hajnoczi 				return EXIT_FAILURE;
5420b025033SStefan Hajnoczi 			}
5430b025033SStefan Hajnoczi 			break;
5440b025033SStefan Hajnoczi 		case 'p':
545df7e0e0dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
5460b025033SStefan Hajnoczi 			break;
5470b025033SStefan Hajnoczi 		case 'P':
5480b025033SStefan Hajnoczi 			control_port = optarg;
5490b025033SStefan Hajnoczi 			break;
5505a2b2425SStefano Garzarella 		case 'l':
5515a2b2425SStefano Garzarella 			list_tests(test_cases);
5525a2b2425SStefano Garzarella 			break;
5535a2b2425SStefano Garzarella 		case 's':
5545a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
5555a2b2425SStefano Garzarella 				  optarg);
5565a2b2425SStefano Garzarella 			break;
5570b025033SStefan Hajnoczi 		case '?':
5580b025033SStefan Hajnoczi 		default:
5590b025033SStefan Hajnoczi 			usage();
5600b025033SStefan Hajnoczi 		}
5610b025033SStefan Hajnoczi 	}
5620b025033SStefan Hajnoczi 
5630b025033SStefan Hajnoczi 	if (!control_port)
5640b025033SStefan Hajnoczi 		usage();
565df7e0e0dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
5660b025033SStefan Hajnoczi 		usage();
567df7e0e0dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
5680b025033SStefan Hajnoczi 		usage();
5690b025033SStefan Hajnoczi 
5700b025033SStefan Hajnoczi 	if (!control_host) {
571df7e0e0dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
5720b025033SStefan Hajnoczi 			usage();
5730b025033SStefan Hajnoczi 		control_host = "0.0.0.0";
5740b025033SStefan Hajnoczi 	}
5750b025033SStefan Hajnoczi 
576df7e0e0dSStefan Hajnoczi 	control_init(control_host, control_port,
577df7e0e0dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
5780b025033SStefan Hajnoczi 
579df7e0e0dSStefan Hajnoczi 	run_tests(test_cases, &opts);
5800b025033SStefan Hajnoczi 
5810b025033SStefan Hajnoczi 	control_cleanup();
5820b025033SStefan Hajnoczi 	return EXIT_SUCCESS;
5830b025033SStefan Hajnoczi }
584