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