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