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/socket.h>
170b025033SStefan Hajnoczi #include <sys/stat.h>
180b025033SStefan Hajnoczi #include <sys/types.h>
190b025033SStefan Hajnoczi #include <linux/list.h>
200b025033SStefan Hajnoczi #include <linux/net.h>
210b025033SStefan Hajnoczi #include <linux/netlink.h>
2243985468SStefan Hajnoczi #include <linux/vm_sockets.h>
230b025033SStefan Hajnoczi #include <linux/sock_diag.h>
2443985468SStefan Hajnoczi #include <linux/vm_sockets_diag.h>
250b025033SStefan Hajnoczi #include <netinet/tcp.h>
260b025033SStefan Hajnoczi 
270b025033SStefan Hajnoczi #include "timeout.h"
280b025033SStefan Hajnoczi #include "control.h"
29df7e0e0dSStefan Hajnoczi #include "util.h"
300b025033SStefan Hajnoczi 
310b025033SStefan Hajnoczi /* Per-socket status */
320b025033SStefan Hajnoczi struct vsock_stat {
330b025033SStefan Hajnoczi 	struct list_head list;
340b025033SStefan Hajnoczi 	struct vsock_diag_msg msg;
350b025033SStefan Hajnoczi };
360b025033SStefan Hajnoczi 
370b025033SStefan Hajnoczi static const char *sock_type_str(int type)
380b025033SStefan Hajnoczi {
390b025033SStefan Hajnoczi 	switch (type) {
400b025033SStefan Hajnoczi 	case SOCK_DGRAM:
410b025033SStefan Hajnoczi 		return "DGRAM";
420b025033SStefan Hajnoczi 	case SOCK_STREAM:
430b025033SStefan Hajnoczi 		return "STREAM";
440b025033SStefan Hajnoczi 	default:
450b025033SStefan Hajnoczi 		return "INVALID TYPE";
460b025033SStefan Hajnoczi 	}
470b025033SStefan Hajnoczi }
480b025033SStefan Hajnoczi 
490b025033SStefan Hajnoczi static const char *sock_state_str(int state)
500b025033SStefan Hajnoczi {
510b025033SStefan Hajnoczi 	switch (state) {
520b025033SStefan Hajnoczi 	case TCP_CLOSE:
530b025033SStefan Hajnoczi 		return "UNCONNECTED";
540b025033SStefan Hajnoczi 	case TCP_SYN_SENT:
550b025033SStefan Hajnoczi 		return "CONNECTING";
560b025033SStefan Hajnoczi 	case TCP_ESTABLISHED:
570b025033SStefan Hajnoczi 		return "CONNECTED";
580b025033SStefan Hajnoczi 	case TCP_CLOSING:
590b025033SStefan Hajnoczi 		return "DISCONNECTING";
600b025033SStefan Hajnoczi 	case TCP_LISTEN:
610b025033SStefan Hajnoczi 		return "LISTEN";
620b025033SStefan Hajnoczi 	default:
630b025033SStefan Hajnoczi 		return "INVALID STATE";
640b025033SStefan Hajnoczi 	}
650b025033SStefan Hajnoczi }
660b025033SStefan Hajnoczi 
670b025033SStefan Hajnoczi static const char *sock_shutdown_str(int shutdown)
680b025033SStefan Hajnoczi {
690b025033SStefan Hajnoczi 	switch (shutdown) {
700b025033SStefan Hajnoczi 	case 1:
710b025033SStefan Hajnoczi 		return "RCV_SHUTDOWN";
720b025033SStefan Hajnoczi 	case 2:
730b025033SStefan Hajnoczi 		return "SEND_SHUTDOWN";
740b025033SStefan Hajnoczi 	case 3:
750b025033SStefan Hajnoczi 		return "RCV_SHUTDOWN | SEND_SHUTDOWN";
760b025033SStefan Hajnoczi 	default:
770b025033SStefan Hajnoczi 		return "0";
780b025033SStefan Hajnoczi 	}
790b025033SStefan Hajnoczi }
800b025033SStefan Hajnoczi 
810b025033SStefan Hajnoczi static void print_vsock_addr(FILE *fp, unsigned int cid, unsigned int port)
820b025033SStefan Hajnoczi {
830b025033SStefan Hajnoczi 	if (cid == VMADDR_CID_ANY)
840b025033SStefan Hajnoczi 		fprintf(fp, "*:");
850b025033SStefan Hajnoczi 	else
860b025033SStefan Hajnoczi 		fprintf(fp, "%u:", cid);
870b025033SStefan Hajnoczi 
880b025033SStefan Hajnoczi 	if (port == VMADDR_PORT_ANY)
890b025033SStefan Hajnoczi 		fprintf(fp, "*");
900b025033SStefan Hajnoczi 	else
910b025033SStefan Hajnoczi 		fprintf(fp, "%u", port);
920b025033SStefan Hajnoczi }
930b025033SStefan Hajnoczi 
940b025033SStefan Hajnoczi static void print_vsock_stat(FILE *fp, struct vsock_stat *st)
950b025033SStefan Hajnoczi {
960b025033SStefan Hajnoczi 	print_vsock_addr(fp, st->msg.vdiag_src_cid, st->msg.vdiag_src_port);
970b025033SStefan Hajnoczi 	fprintf(fp, " ");
980b025033SStefan Hajnoczi 	print_vsock_addr(fp, st->msg.vdiag_dst_cid, st->msg.vdiag_dst_port);
990b025033SStefan Hajnoczi 	fprintf(fp, " %s %s %s %u\n",
1000b025033SStefan Hajnoczi 		sock_type_str(st->msg.vdiag_type),
1010b025033SStefan Hajnoczi 		sock_state_str(st->msg.vdiag_state),
1020b025033SStefan Hajnoczi 		sock_shutdown_str(st->msg.vdiag_shutdown),
1030b025033SStefan Hajnoczi 		st->msg.vdiag_ino);
1040b025033SStefan Hajnoczi }
1050b025033SStefan Hajnoczi 
1060b025033SStefan Hajnoczi static void print_vsock_stats(FILE *fp, struct list_head *head)
1070b025033SStefan Hajnoczi {
1080b025033SStefan Hajnoczi 	struct vsock_stat *st;
1090b025033SStefan Hajnoczi 
1100b025033SStefan Hajnoczi 	list_for_each_entry(st, head, list)
1110b025033SStefan Hajnoczi 		print_vsock_stat(fp, st);
1120b025033SStefan Hajnoczi }
1130b025033SStefan Hajnoczi 
1140b025033SStefan Hajnoczi static struct vsock_stat *find_vsock_stat(struct list_head *head, int fd)
1150b025033SStefan Hajnoczi {
1160b025033SStefan Hajnoczi 	struct vsock_stat *st;
1170b025033SStefan Hajnoczi 	struct stat stat;
1180b025033SStefan Hajnoczi 
1190b025033SStefan Hajnoczi 	if (fstat(fd, &stat) < 0) {
1200b025033SStefan Hajnoczi 		perror("fstat");
1210b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
1220b025033SStefan Hajnoczi 	}
1230b025033SStefan Hajnoczi 
1240b025033SStefan Hajnoczi 	list_for_each_entry(st, head, list)
1250b025033SStefan Hajnoczi 		if (st->msg.vdiag_ino == stat.st_ino)
1260b025033SStefan Hajnoczi 			return st;
1270b025033SStefan Hajnoczi 
1280b025033SStefan Hajnoczi 	fprintf(stderr, "cannot find fd %d\n", fd);
1290b025033SStefan Hajnoczi 	exit(EXIT_FAILURE);
1300b025033SStefan Hajnoczi }
1310b025033SStefan Hajnoczi 
1320b025033SStefan Hajnoczi static void check_no_sockets(struct list_head *head)
1330b025033SStefan Hajnoczi {
1340b025033SStefan Hajnoczi 	if (!list_empty(head)) {
1350b025033SStefan Hajnoczi 		fprintf(stderr, "expected no sockets\n");
1360b025033SStefan Hajnoczi 		print_vsock_stats(stderr, head);
1370b025033SStefan Hajnoczi 		exit(1);
1380b025033SStefan Hajnoczi 	}
1390b025033SStefan Hajnoczi }
1400b025033SStefan Hajnoczi 
1410b025033SStefan Hajnoczi static void check_num_sockets(struct list_head *head, int expected)
1420b025033SStefan Hajnoczi {
1430b025033SStefan Hajnoczi 	struct list_head *node;
1440b025033SStefan Hajnoczi 	int n = 0;
1450b025033SStefan Hajnoczi 
1460b025033SStefan Hajnoczi 	list_for_each(node, head)
1470b025033SStefan Hajnoczi 		n++;
1480b025033SStefan Hajnoczi 
1490b025033SStefan Hajnoczi 	if (n != expected) {
1500b025033SStefan Hajnoczi 		fprintf(stderr, "expected %d sockets, found %d\n",
1510b025033SStefan Hajnoczi 			expected, n);
1520b025033SStefan Hajnoczi 		print_vsock_stats(stderr, head);
1530b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
1540b025033SStefan Hajnoczi 	}
1550b025033SStefan Hajnoczi }
1560b025033SStefan Hajnoczi 
1570b025033SStefan Hajnoczi static void check_socket_state(struct vsock_stat *st, __u8 state)
1580b025033SStefan Hajnoczi {
1590b025033SStefan Hajnoczi 	if (st->msg.vdiag_state != state) {
1600b025033SStefan Hajnoczi 		fprintf(stderr, "expected socket state %#x, got %#x\n",
1610b025033SStefan Hajnoczi 			state, st->msg.vdiag_state);
1620b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
1630b025033SStefan Hajnoczi 	}
1640b025033SStefan Hajnoczi }
1650b025033SStefan Hajnoczi 
1660b025033SStefan Hajnoczi static void send_req(int fd)
1670b025033SStefan Hajnoczi {
1680b025033SStefan Hajnoczi 	struct sockaddr_nl nladdr = {
1690b025033SStefan Hajnoczi 		.nl_family = AF_NETLINK,
1700b025033SStefan Hajnoczi 	};
1710b025033SStefan Hajnoczi 	struct {
1720b025033SStefan Hajnoczi 		struct nlmsghdr nlh;
1730b025033SStefan Hajnoczi 		struct vsock_diag_req vreq;
1740b025033SStefan Hajnoczi 	} req = {
1750b025033SStefan Hajnoczi 		.nlh = {
1760b025033SStefan Hajnoczi 			.nlmsg_len = sizeof(req),
1770b025033SStefan Hajnoczi 			.nlmsg_type = SOCK_DIAG_BY_FAMILY,
1780b025033SStefan Hajnoczi 			.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
1790b025033SStefan Hajnoczi 		},
1800b025033SStefan Hajnoczi 		.vreq = {
1810b025033SStefan Hajnoczi 			.sdiag_family = AF_VSOCK,
1820b025033SStefan Hajnoczi 			.vdiag_states = ~(__u32)0,
1830b025033SStefan Hajnoczi 		},
1840b025033SStefan Hajnoczi 	};
1850b025033SStefan Hajnoczi 	struct iovec iov = {
1860b025033SStefan Hajnoczi 		.iov_base = &req,
1870b025033SStefan Hajnoczi 		.iov_len = sizeof(req),
1880b025033SStefan Hajnoczi 	};
1890b025033SStefan Hajnoczi 	struct msghdr msg = {
1900b025033SStefan Hajnoczi 		.msg_name = &nladdr,
1910b025033SStefan Hajnoczi 		.msg_namelen = sizeof(nladdr),
1920b025033SStefan Hajnoczi 		.msg_iov = &iov,
1930b025033SStefan Hajnoczi 		.msg_iovlen = 1,
1940b025033SStefan Hajnoczi 	};
1950b025033SStefan Hajnoczi 
1960b025033SStefan Hajnoczi 	for (;;) {
1970b025033SStefan Hajnoczi 		if (sendmsg(fd, &msg, 0) < 0) {
1980b025033SStefan Hajnoczi 			if (errno == EINTR)
1990b025033SStefan Hajnoczi 				continue;
2000b025033SStefan Hajnoczi 
2010b025033SStefan Hajnoczi 			perror("sendmsg");
2020b025033SStefan Hajnoczi 			exit(EXIT_FAILURE);
2030b025033SStefan Hajnoczi 		}
2040b025033SStefan Hajnoczi 
2050b025033SStefan Hajnoczi 		return;
2060b025033SStefan Hajnoczi 	}
2070b025033SStefan Hajnoczi }
2080b025033SStefan Hajnoczi 
2090b025033SStefan Hajnoczi static ssize_t recv_resp(int fd, void *buf, size_t len)
2100b025033SStefan Hajnoczi {
2110b025033SStefan Hajnoczi 	struct sockaddr_nl nladdr = {
2120b025033SStefan Hajnoczi 		.nl_family = AF_NETLINK,
2130b025033SStefan Hajnoczi 	};
2140b025033SStefan Hajnoczi 	struct iovec iov = {
2150b025033SStefan Hajnoczi 		.iov_base = buf,
2160b025033SStefan Hajnoczi 		.iov_len = len,
2170b025033SStefan Hajnoczi 	};
2180b025033SStefan Hajnoczi 	struct msghdr msg = {
2190b025033SStefan Hajnoczi 		.msg_name = &nladdr,
2200b025033SStefan Hajnoczi 		.msg_namelen = sizeof(nladdr),
2210b025033SStefan Hajnoczi 		.msg_iov = &iov,
2220b025033SStefan Hajnoczi 		.msg_iovlen = 1,
2230b025033SStefan Hajnoczi 	};
2240b025033SStefan Hajnoczi 	ssize_t ret;
2250b025033SStefan Hajnoczi 
2260b025033SStefan Hajnoczi 	do {
2270b025033SStefan Hajnoczi 		ret = recvmsg(fd, &msg, 0);
2280b025033SStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
2290b025033SStefan Hajnoczi 
2300b025033SStefan Hajnoczi 	if (ret < 0) {
2310b025033SStefan Hajnoczi 		perror("recvmsg");
2320b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
2330b025033SStefan Hajnoczi 	}
2340b025033SStefan Hajnoczi 
2350b025033SStefan Hajnoczi 	return ret;
2360b025033SStefan Hajnoczi }
2370b025033SStefan Hajnoczi 
2380b025033SStefan Hajnoczi static void add_vsock_stat(struct list_head *sockets,
2390b025033SStefan Hajnoczi 			   const struct vsock_diag_msg *resp)
2400b025033SStefan Hajnoczi {
2410b025033SStefan Hajnoczi 	struct vsock_stat *st;
2420b025033SStefan Hajnoczi 
2430b025033SStefan Hajnoczi 	st = malloc(sizeof(*st));
2440b025033SStefan Hajnoczi 	if (!st) {
2450b025033SStefan Hajnoczi 		perror("malloc");
2460b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
2470b025033SStefan Hajnoczi 	}
2480b025033SStefan Hajnoczi 
2490b025033SStefan Hajnoczi 	st->msg = *resp;
2500b025033SStefan Hajnoczi 	list_add_tail(&st->list, sockets);
2510b025033SStefan Hajnoczi }
2520b025033SStefan Hajnoczi 
2530b025033SStefan Hajnoczi /*
2540b025033SStefan Hajnoczi  * Read vsock stats into a list.
2550b025033SStefan Hajnoczi  */
2560b025033SStefan Hajnoczi static void read_vsock_stat(struct list_head *sockets)
2570b025033SStefan Hajnoczi {
2580b025033SStefan Hajnoczi 	long buf[8192 / sizeof(long)];
2590b025033SStefan Hajnoczi 	int fd;
2600b025033SStefan Hajnoczi 
2610b025033SStefan Hajnoczi 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
2620b025033SStefan Hajnoczi 	if (fd < 0) {
2630b025033SStefan Hajnoczi 		perror("socket");
2640b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
2650b025033SStefan Hajnoczi 	}
2660b025033SStefan Hajnoczi 
2670b025033SStefan Hajnoczi 	send_req(fd);
2680b025033SStefan Hajnoczi 
2690b025033SStefan Hajnoczi 	for (;;) {
2700b025033SStefan Hajnoczi 		const struct nlmsghdr *h;
2710b025033SStefan Hajnoczi 		ssize_t ret;
2720b025033SStefan Hajnoczi 
2730b025033SStefan Hajnoczi 		ret = recv_resp(fd, buf, sizeof(buf));
2740b025033SStefan Hajnoczi 		if (ret == 0)
2750b025033SStefan Hajnoczi 			goto done;
2760b025033SStefan Hajnoczi 		if (ret < sizeof(*h)) {
2770b025033SStefan Hajnoczi 			fprintf(stderr, "short read of %zd bytes\n", ret);
2780b025033SStefan Hajnoczi 			exit(EXIT_FAILURE);
2790b025033SStefan Hajnoczi 		}
2800b025033SStefan Hajnoczi 
2810b025033SStefan Hajnoczi 		h = (struct nlmsghdr *)buf;
2820b025033SStefan Hajnoczi 
2830b025033SStefan Hajnoczi 		while (NLMSG_OK(h, ret)) {
2840b025033SStefan Hajnoczi 			if (h->nlmsg_type == NLMSG_DONE)
2850b025033SStefan Hajnoczi 				goto done;
2860b025033SStefan Hajnoczi 
2870b025033SStefan Hajnoczi 			if (h->nlmsg_type == NLMSG_ERROR) {
2880b025033SStefan Hajnoczi 				const struct nlmsgerr *err = NLMSG_DATA(h);
2890b025033SStefan Hajnoczi 
2900b025033SStefan Hajnoczi 				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
2910b025033SStefan Hajnoczi 					fprintf(stderr, "NLMSG_ERROR\n");
2920b025033SStefan Hajnoczi 				else {
2930b025033SStefan Hajnoczi 					errno = -err->error;
2940b025033SStefan Hajnoczi 					perror("NLMSG_ERROR");
2950b025033SStefan Hajnoczi 				}
2960b025033SStefan Hajnoczi 
2970b025033SStefan Hajnoczi 				exit(EXIT_FAILURE);
2980b025033SStefan Hajnoczi 			}
2990b025033SStefan Hajnoczi 
3000b025033SStefan Hajnoczi 			if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
3010b025033SStefan Hajnoczi 				fprintf(stderr, "unexpected nlmsg_type %#x\n",
3020b025033SStefan Hajnoczi 					h->nlmsg_type);
3030b025033SStefan Hajnoczi 				exit(EXIT_FAILURE);
3040b025033SStefan Hajnoczi 			}
3050b025033SStefan Hajnoczi 			if (h->nlmsg_len <
3060b025033SStefan Hajnoczi 			    NLMSG_LENGTH(sizeof(struct vsock_diag_msg))) {
3070b025033SStefan Hajnoczi 				fprintf(stderr, "short vsock_diag_msg\n");
3080b025033SStefan Hajnoczi 				exit(EXIT_FAILURE);
3090b025033SStefan Hajnoczi 			}
3100b025033SStefan Hajnoczi 
3110b025033SStefan Hajnoczi 			add_vsock_stat(sockets, NLMSG_DATA(h));
3120b025033SStefan Hajnoczi 
3130b025033SStefan Hajnoczi 			h = NLMSG_NEXT(h, ret);
3140b025033SStefan Hajnoczi 		}
3150b025033SStefan Hajnoczi 	}
3160b025033SStefan Hajnoczi 
3170b025033SStefan Hajnoczi done:
3180b025033SStefan Hajnoczi 	close(fd);
3190b025033SStefan Hajnoczi }
3200b025033SStefan Hajnoczi 
3210b025033SStefan Hajnoczi static void free_sock_stat(struct list_head *sockets)
3220b025033SStefan Hajnoczi {
3230b025033SStefan Hajnoczi 	struct vsock_stat *st;
3240b025033SStefan Hajnoczi 	struct vsock_stat *next;
3250b025033SStefan Hajnoczi 
3260b025033SStefan Hajnoczi 	list_for_each_entry_safe(st, next, sockets, list)
3270b025033SStefan Hajnoczi 		free(st);
3280b025033SStefan Hajnoczi }
3290b025033SStefan Hajnoczi 
330df7e0e0dSStefan Hajnoczi static void test_no_sockets(const struct test_opts *opts)
3310b025033SStefan Hajnoczi {
3320b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
3330b025033SStefan Hajnoczi 
3340b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
3350b025033SStefan Hajnoczi 
3360b025033SStefan Hajnoczi 	check_no_sockets(&sockets);
3370b025033SStefan Hajnoczi 
3380b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
3390b025033SStefan Hajnoczi }
3400b025033SStefan Hajnoczi 
341df7e0e0dSStefan Hajnoczi static void test_listen_socket_server(const struct test_opts *opts)
3420b025033SStefan Hajnoczi {
3430b025033SStefan Hajnoczi 	union {
3440b025033SStefan Hajnoczi 		struct sockaddr sa;
3450b025033SStefan Hajnoczi 		struct sockaddr_vm svm;
3460b025033SStefan Hajnoczi 	} addr = {
3470b025033SStefan Hajnoczi 		.svm = {
3480b025033SStefan Hajnoczi 			.svm_family = AF_VSOCK,
3490b025033SStefan Hajnoczi 			.svm_port = 1234,
3500b025033SStefan Hajnoczi 			.svm_cid = VMADDR_CID_ANY,
3510b025033SStefan Hajnoczi 		},
3520b025033SStefan Hajnoczi 	};
3530b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
3540b025033SStefan Hajnoczi 	struct vsock_stat *st;
3550b025033SStefan Hajnoczi 	int fd;
3560b025033SStefan Hajnoczi 
3570b025033SStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
3580b025033SStefan Hajnoczi 
3590b025033SStefan Hajnoczi 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
3600b025033SStefan Hajnoczi 		perror("bind");
3610b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
3620b025033SStefan Hajnoczi 	}
3630b025033SStefan Hajnoczi 
3640b025033SStefan Hajnoczi 	if (listen(fd, 1) < 0) {
3650b025033SStefan Hajnoczi 		perror("listen");
3660b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
3670b025033SStefan Hajnoczi 	}
3680b025033SStefan Hajnoczi 
3690b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
3700b025033SStefan Hajnoczi 
3710b025033SStefan Hajnoczi 	check_num_sockets(&sockets, 1);
3720b025033SStefan Hajnoczi 	st = find_vsock_stat(&sockets, fd);
3730b025033SStefan Hajnoczi 	check_socket_state(st, TCP_LISTEN);
3740b025033SStefan Hajnoczi 
3750b025033SStefan Hajnoczi 	close(fd);
3760b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
3770b025033SStefan Hajnoczi }
3780b025033SStefan Hajnoczi 
379df7e0e0dSStefan Hajnoczi static void test_connect_client(const struct test_opts *opts)
3800b025033SStefan Hajnoczi {
3810b025033SStefan Hajnoczi 	union {
3820b025033SStefan Hajnoczi 		struct sockaddr sa;
3830b025033SStefan Hajnoczi 		struct sockaddr_vm svm;
3840b025033SStefan Hajnoczi 	} addr = {
3850b025033SStefan Hajnoczi 		.svm = {
3860b025033SStefan Hajnoczi 			.svm_family = AF_VSOCK,
3870b025033SStefan Hajnoczi 			.svm_port = 1234,
388df7e0e0dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
3890b025033SStefan Hajnoczi 		},
3900b025033SStefan Hajnoczi 	};
3910b025033SStefan Hajnoczi 	int fd;
3920b025033SStefan Hajnoczi 	int ret;
3930b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
3940b025033SStefan Hajnoczi 	struct vsock_stat *st;
3950b025033SStefan Hajnoczi 
3960b025033SStefan Hajnoczi 	control_expectln("LISTENING");
3970b025033SStefan Hajnoczi 
3980b025033SStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
3990b025033SStefan Hajnoczi 
4000b025033SStefan Hajnoczi 	timeout_begin(TIMEOUT);
4010b025033SStefan Hajnoczi 	do {
4020b025033SStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
4030b025033SStefan Hajnoczi 		timeout_check("connect");
4040b025033SStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
4050b025033SStefan Hajnoczi 	timeout_end();
4060b025033SStefan Hajnoczi 
4070b025033SStefan Hajnoczi 	if (ret < 0) {
4080b025033SStefan Hajnoczi 		perror("connect");
4090b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4100b025033SStefan Hajnoczi 	}
4110b025033SStefan Hajnoczi 
4120b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
4130b025033SStefan Hajnoczi 
4140b025033SStefan Hajnoczi 	check_num_sockets(&sockets, 1);
4150b025033SStefan Hajnoczi 	st = find_vsock_stat(&sockets, fd);
4160b025033SStefan Hajnoczi 	check_socket_state(st, TCP_ESTABLISHED);
4170b025033SStefan Hajnoczi 
4180b025033SStefan Hajnoczi 	control_expectln("DONE");
4190b025033SStefan Hajnoczi 	control_writeln("DONE");
4200b025033SStefan Hajnoczi 
4210b025033SStefan Hajnoczi 	close(fd);
4220b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
4230b025033SStefan Hajnoczi }
4240b025033SStefan Hajnoczi 
425df7e0e0dSStefan Hajnoczi static void test_connect_server(const struct test_opts *opts)
4260b025033SStefan Hajnoczi {
4270b025033SStefan Hajnoczi 	union {
4280b025033SStefan Hajnoczi 		struct sockaddr sa;
4290b025033SStefan Hajnoczi 		struct sockaddr_vm svm;
4300b025033SStefan Hajnoczi 	} addr = {
4310b025033SStefan Hajnoczi 		.svm = {
4320b025033SStefan Hajnoczi 			.svm_family = AF_VSOCK,
4330b025033SStefan Hajnoczi 			.svm_port = 1234,
4340b025033SStefan Hajnoczi 			.svm_cid = VMADDR_CID_ANY,
4350b025033SStefan Hajnoczi 		},
4360b025033SStefan Hajnoczi 	};
4370b025033SStefan Hajnoczi 	union {
4380b025033SStefan Hajnoczi 		struct sockaddr sa;
4390b025033SStefan Hajnoczi 		struct sockaddr_vm svm;
4400b025033SStefan Hajnoczi 	} clientaddr;
4410b025033SStefan Hajnoczi 	socklen_t clientaddr_len = sizeof(clientaddr.svm);
4420b025033SStefan Hajnoczi 	LIST_HEAD(sockets);
4430b025033SStefan Hajnoczi 	struct vsock_stat *st;
4440b025033SStefan Hajnoczi 	int fd;
4450b025033SStefan Hajnoczi 	int client_fd;
4460b025033SStefan Hajnoczi 
4470b025033SStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
4480b025033SStefan Hajnoczi 
4490b025033SStefan Hajnoczi 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
4500b025033SStefan Hajnoczi 		perror("bind");
4510b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4520b025033SStefan Hajnoczi 	}
4530b025033SStefan Hajnoczi 
4540b025033SStefan Hajnoczi 	if (listen(fd, 1) < 0) {
4550b025033SStefan Hajnoczi 		perror("listen");
4560b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4570b025033SStefan Hajnoczi 	}
4580b025033SStefan Hajnoczi 
4590b025033SStefan Hajnoczi 	control_writeln("LISTENING");
4600b025033SStefan Hajnoczi 
4610b025033SStefan Hajnoczi 	timeout_begin(TIMEOUT);
4620b025033SStefan Hajnoczi 	do {
4630b025033SStefan Hajnoczi 		client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
4640b025033SStefan Hajnoczi 		timeout_check("accept");
4650b025033SStefan Hajnoczi 	} while (client_fd < 0 && errno == EINTR);
4660b025033SStefan Hajnoczi 	timeout_end();
4670b025033SStefan Hajnoczi 
4680b025033SStefan Hajnoczi 	if (client_fd < 0) {
4690b025033SStefan Hajnoczi 		perror("accept");
4700b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4710b025033SStefan Hajnoczi 	}
4720b025033SStefan Hajnoczi 	if (clientaddr.sa.sa_family != AF_VSOCK) {
4730b025033SStefan Hajnoczi 		fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n",
4740b025033SStefan Hajnoczi 			clientaddr.sa.sa_family);
4750b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4760b025033SStefan Hajnoczi 	}
477df7e0e0dSStefan Hajnoczi 	if (clientaddr.svm.svm_cid != opts->peer_cid) {
4780b025033SStefan Hajnoczi 		fprintf(stderr, "expected peer CID %u from accept(2), got %u\n",
479df7e0e0dSStefan Hajnoczi 			opts->peer_cid, clientaddr.svm.svm_cid);
4800b025033SStefan Hajnoczi 		exit(EXIT_FAILURE);
4810b025033SStefan Hajnoczi 	}
4820b025033SStefan Hajnoczi 
4830b025033SStefan Hajnoczi 	read_vsock_stat(&sockets);
4840b025033SStefan Hajnoczi 
4850b025033SStefan Hajnoczi 	check_num_sockets(&sockets, 2);
4860b025033SStefan Hajnoczi 	find_vsock_stat(&sockets, fd);
4870b025033SStefan Hajnoczi 	st = find_vsock_stat(&sockets, client_fd);
4880b025033SStefan Hajnoczi 	check_socket_state(st, TCP_ESTABLISHED);
4890b025033SStefan Hajnoczi 
4900b025033SStefan Hajnoczi 	control_writeln("DONE");
4910b025033SStefan Hajnoczi 	control_expectln("DONE");
4920b025033SStefan Hajnoczi 
4930b025033SStefan Hajnoczi 	close(client_fd);
4940b025033SStefan Hajnoczi 	close(fd);
4950b025033SStefan Hajnoczi 	free_sock_stat(&sockets);
4960b025033SStefan Hajnoczi }
4970b025033SStefan Hajnoczi 
498df7e0e0dSStefan Hajnoczi static struct test_case test_cases[] = {
4990b025033SStefan Hajnoczi 	{
5000b025033SStefan Hajnoczi 		.name = "No sockets",
5010b025033SStefan Hajnoczi 		.run_server = test_no_sockets,
5020b025033SStefan Hajnoczi 	},
5030b025033SStefan Hajnoczi 	{
5040b025033SStefan Hajnoczi 		.name = "Listen socket",
5050b025033SStefan Hajnoczi 		.run_server = test_listen_socket_server,
5060b025033SStefan Hajnoczi 	},
5070b025033SStefan Hajnoczi 	{
5080b025033SStefan Hajnoczi 		.name = "Connect",
5090b025033SStefan Hajnoczi 		.run_client = test_connect_client,
5100b025033SStefan Hajnoczi 		.run_server = test_connect_server,
5110b025033SStefan Hajnoczi 	},
5120b025033SStefan Hajnoczi 	{},
5130b025033SStefan Hajnoczi };
5140b025033SStefan Hajnoczi 
5150b025033SStefan Hajnoczi static const char optstring[] = "";
5160b025033SStefan Hajnoczi static const struct option longopts[] = {
5170b025033SStefan Hajnoczi 	{
5180b025033SStefan Hajnoczi 		.name = "control-host",
5190b025033SStefan Hajnoczi 		.has_arg = required_argument,
5200b025033SStefan Hajnoczi 		.val = 'H',
5210b025033SStefan Hajnoczi 	},
5220b025033SStefan Hajnoczi 	{
5230b025033SStefan Hajnoczi 		.name = "control-port",
5240b025033SStefan Hajnoczi 		.has_arg = required_argument,
5250b025033SStefan Hajnoczi 		.val = 'P',
5260b025033SStefan Hajnoczi 	},
5270b025033SStefan Hajnoczi 	{
5280b025033SStefan Hajnoczi 		.name = "mode",
5290b025033SStefan Hajnoczi 		.has_arg = required_argument,
5300b025033SStefan Hajnoczi 		.val = 'm',
5310b025033SStefan Hajnoczi 	},
5320b025033SStefan Hajnoczi 	{
5330b025033SStefan Hajnoczi 		.name = "peer-cid",
5340b025033SStefan Hajnoczi 		.has_arg = required_argument,
5350b025033SStefan Hajnoczi 		.val = 'p',
5360b025033SStefan Hajnoczi 	},
5370b025033SStefan Hajnoczi 	{
5380b025033SStefan Hajnoczi 		.name = "help",
5390b025033SStefan Hajnoczi 		.has_arg = no_argument,
5400b025033SStefan Hajnoczi 		.val = '?',
5410b025033SStefan Hajnoczi 	},
5420b025033SStefan Hajnoczi 	{},
5430b025033SStefan Hajnoczi };
5440b025033SStefan Hajnoczi 
5450b025033SStefan Hajnoczi static void usage(void)
5460b025033SStefan Hajnoczi {
5470b025033SStefan Hajnoczi 	fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid>\n"
5480b025033SStefan Hajnoczi 		"\n"
5490b025033SStefan Hajnoczi 		"  Server: vsock_diag_test --control-port=1234 --mode=server --peer-cid=3\n"
5500b025033SStefan Hajnoczi 		"  Client: vsock_diag_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
5510b025033SStefan Hajnoczi 		"\n"
5520b025033SStefan Hajnoczi 		"Run vsock_diag.ko tests.  Must be launched in both\n"
5530b025033SStefan Hajnoczi 		"guest and host.  One side must use --mode=client and\n"
5540b025033SStefan Hajnoczi 		"the other side must use --mode=server.\n"
5550b025033SStefan Hajnoczi 		"\n"
5560b025033SStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
5570b025033SStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
5580b025033SStefan Hajnoczi 		"listen address and the client requires an address to\n"
5590b025033SStefan Hajnoczi 		"connect to.\n"
5600b025033SStefan Hajnoczi 		"\n"
5610b025033SStefan Hajnoczi 		"The CID of the other side must be given with --peer-cid=<cid>.\n");
5620b025033SStefan Hajnoczi 	exit(EXIT_FAILURE);
5630b025033SStefan Hajnoczi }
5640b025033SStefan Hajnoczi 
5650b025033SStefan Hajnoczi int main(int argc, char **argv)
5660b025033SStefan Hajnoczi {
5670b025033SStefan Hajnoczi 	const char *control_host = NULL;
5680b025033SStefan Hajnoczi 	const char *control_port = NULL;
569df7e0e0dSStefan Hajnoczi 	struct test_opts opts = {
570df7e0e0dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
571df7e0e0dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
572df7e0e0dSStefan Hajnoczi 	};
5730b025033SStefan Hajnoczi 
5740b025033SStefan Hajnoczi 	init_signals();
5750b025033SStefan Hajnoczi 
5760b025033SStefan Hajnoczi 	for (;;) {
5770b025033SStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
5780b025033SStefan Hajnoczi 
5790b025033SStefan Hajnoczi 		if (opt == -1)
5800b025033SStefan Hajnoczi 			break;
5810b025033SStefan Hajnoczi 
5820b025033SStefan Hajnoczi 		switch (opt) {
5830b025033SStefan Hajnoczi 		case 'H':
5840b025033SStefan Hajnoczi 			control_host = optarg;
5850b025033SStefan Hajnoczi 			break;
5860b025033SStefan Hajnoczi 		case 'm':
5870b025033SStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
588df7e0e0dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
5890b025033SStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
590df7e0e0dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
5910b025033SStefan Hajnoczi 			else {
5920b025033SStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
5930b025033SStefan Hajnoczi 				return EXIT_FAILURE;
5940b025033SStefan Hajnoczi 			}
5950b025033SStefan Hajnoczi 			break;
5960b025033SStefan Hajnoczi 		case 'p':
597df7e0e0dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
5980b025033SStefan Hajnoczi 			break;
5990b025033SStefan Hajnoczi 		case 'P':
6000b025033SStefan Hajnoczi 			control_port = optarg;
6010b025033SStefan Hajnoczi 			break;
6020b025033SStefan Hajnoczi 		case '?':
6030b025033SStefan Hajnoczi 		default:
6040b025033SStefan Hajnoczi 			usage();
6050b025033SStefan Hajnoczi 		}
6060b025033SStefan Hajnoczi 	}
6070b025033SStefan Hajnoczi 
6080b025033SStefan Hajnoczi 	if (!control_port)
6090b025033SStefan Hajnoczi 		usage();
610df7e0e0dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
6110b025033SStefan Hajnoczi 		usage();
612df7e0e0dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
6130b025033SStefan Hajnoczi 		usage();
6140b025033SStefan Hajnoczi 
6150b025033SStefan Hajnoczi 	if (!control_host) {
616df7e0e0dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
6170b025033SStefan Hajnoczi 			usage();
6180b025033SStefan Hajnoczi 		control_host = "0.0.0.0";
6190b025033SStefan Hajnoczi 	}
6200b025033SStefan Hajnoczi 
621df7e0e0dSStefan Hajnoczi 	control_init(control_host, control_port,
622df7e0e0dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
6230b025033SStefan Hajnoczi 
624df7e0e0dSStefan Hajnoczi 	run_tests(test_cases, &opts);
6250b025033SStefan Hajnoczi 
6260b025033SStefan Hajnoczi 	control_cleanup();
6270b025033SStefan Hajnoczi 	return EXIT_SUCCESS;
6280b025033SStefan Hajnoczi }
629