1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * vsock_test - vsock.ko test suite 4 * 5 * Copyright (C) 2017 Red Hat, Inc. 6 * 7 * Author: Stefan Hajnoczi <stefanha@redhat.com> 8 */ 9 10 #include <getopt.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <errno.h> 15 #include <unistd.h> 16 #include <linux/kernel.h> 17 #include <sys/types.h> 18 #include <sys/socket.h> 19 20 #include "timeout.h" 21 #include "control.h" 22 #include "util.h" 23 24 static void test_stream_connection_reset(const struct test_opts *opts) 25 { 26 union { 27 struct sockaddr sa; 28 struct sockaddr_vm svm; 29 } addr = { 30 .svm = { 31 .svm_family = AF_VSOCK, 32 .svm_port = 1234, 33 .svm_cid = opts->peer_cid, 34 }, 35 }; 36 int ret; 37 int fd; 38 39 fd = socket(AF_VSOCK, SOCK_STREAM, 0); 40 41 timeout_begin(TIMEOUT); 42 do { 43 ret = connect(fd, &addr.sa, sizeof(addr.svm)); 44 timeout_check("connect"); 45 } while (ret < 0 && errno == EINTR); 46 timeout_end(); 47 48 if (ret != -1) { 49 fprintf(stderr, "expected connect(2) failure, got %d\n", ret); 50 exit(EXIT_FAILURE); 51 } 52 if (errno != ECONNRESET) { 53 fprintf(stderr, "unexpected connect(2) errno %d\n", errno); 54 exit(EXIT_FAILURE); 55 } 56 57 close(fd); 58 } 59 60 static void test_stream_bind_only_client(const struct test_opts *opts) 61 { 62 union { 63 struct sockaddr sa; 64 struct sockaddr_vm svm; 65 } addr = { 66 .svm = { 67 .svm_family = AF_VSOCK, 68 .svm_port = 1234, 69 .svm_cid = opts->peer_cid, 70 }, 71 }; 72 int ret; 73 int fd; 74 75 /* Wait for the server to be ready */ 76 control_expectln("BIND"); 77 78 fd = socket(AF_VSOCK, SOCK_STREAM, 0); 79 80 timeout_begin(TIMEOUT); 81 do { 82 ret = connect(fd, &addr.sa, sizeof(addr.svm)); 83 timeout_check("connect"); 84 } while (ret < 0 && errno == EINTR); 85 timeout_end(); 86 87 if (ret != -1) { 88 fprintf(stderr, "expected connect(2) failure, got %d\n", ret); 89 exit(EXIT_FAILURE); 90 } 91 if (errno != ECONNRESET) { 92 fprintf(stderr, "unexpected connect(2) errno %d\n", errno); 93 exit(EXIT_FAILURE); 94 } 95 96 /* Notify the server that the client has finished */ 97 control_writeln("DONE"); 98 99 close(fd); 100 } 101 102 static void test_stream_bind_only_server(const struct test_opts *opts) 103 { 104 union { 105 struct sockaddr sa; 106 struct sockaddr_vm svm; 107 } addr = { 108 .svm = { 109 .svm_family = AF_VSOCK, 110 .svm_port = 1234, 111 .svm_cid = VMADDR_CID_ANY, 112 }, 113 }; 114 int fd; 115 116 fd = socket(AF_VSOCK, SOCK_STREAM, 0); 117 118 if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { 119 perror("bind"); 120 exit(EXIT_FAILURE); 121 } 122 123 /* Notify the client that the server is ready */ 124 control_writeln("BIND"); 125 126 /* Wait for the client to finish */ 127 control_expectln("DONE"); 128 129 close(fd); 130 } 131 132 static void test_stream_client_close_client(const struct test_opts *opts) 133 { 134 int fd; 135 136 fd = vsock_stream_connect(opts->peer_cid, 1234); 137 if (fd < 0) { 138 perror("connect"); 139 exit(EXIT_FAILURE); 140 } 141 142 send_byte(fd, 1, 0); 143 close(fd); 144 } 145 146 static void test_stream_client_close_server(const struct test_opts *opts) 147 { 148 int fd; 149 150 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 151 if (fd < 0) { 152 perror("accept"); 153 exit(EXIT_FAILURE); 154 } 155 156 /* Wait for the remote to close the connection, before check 157 * -EPIPE error on send. 158 */ 159 vsock_wait_remote_close(fd); 160 161 send_byte(fd, -EPIPE, 0); 162 recv_byte(fd, 1, 0); 163 recv_byte(fd, 0, 0); 164 close(fd); 165 } 166 167 static void test_stream_server_close_client(const struct test_opts *opts) 168 { 169 int fd; 170 171 fd = vsock_stream_connect(opts->peer_cid, 1234); 172 if (fd < 0) { 173 perror("connect"); 174 exit(EXIT_FAILURE); 175 } 176 177 /* Wait for the remote to close the connection, before check 178 * -EPIPE error on send. 179 */ 180 vsock_wait_remote_close(fd); 181 182 send_byte(fd, -EPIPE, 0); 183 recv_byte(fd, 1, 0); 184 recv_byte(fd, 0, 0); 185 close(fd); 186 } 187 188 static void test_stream_server_close_server(const struct test_opts *opts) 189 { 190 int fd; 191 192 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 193 if (fd < 0) { 194 perror("accept"); 195 exit(EXIT_FAILURE); 196 } 197 198 send_byte(fd, 1, 0); 199 close(fd); 200 } 201 202 /* With the standard socket sizes, VMCI is able to support about 100 203 * concurrent stream connections. 204 */ 205 #define MULTICONN_NFDS 100 206 207 static void test_stream_multiconn_client(const struct test_opts *opts) 208 { 209 int fds[MULTICONN_NFDS]; 210 int i; 211 212 for (i = 0; i < MULTICONN_NFDS; i++) { 213 fds[i] = vsock_stream_connect(opts->peer_cid, 1234); 214 if (fds[i] < 0) { 215 perror("connect"); 216 exit(EXIT_FAILURE); 217 } 218 } 219 220 for (i = 0; i < MULTICONN_NFDS; i++) { 221 if (i % 2) 222 recv_byte(fds[i], 1, 0); 223 else 224 send_byte(fds[i], 1, 0); 225 } 226 227 for (i = 0; i < MULTICONN_NFDS; i++) 228 close(fds[i]); 229 } 230 231 static void test_stream_multiconn_server(const struct test_opts *opts) 232 { 233 int fds[MULTICONN_NFDS]; 234 int i; 235 236 for (i = 0; i < MULTICONN_NFDS; i++) { 237 fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 238 if (fds[i] < 0) { 239 perror("accept"); 240 exit(EXIT_FAILURE); 241 } 242 } 243 244 for (i = 0; i < MULTICONN_NFDS; i++) { 245 if (i % 2) 246 send_byte(fds[i], 1, 0); 247 else 248 recv_byte(fds[i], 1, 0); 249 } 250 251 for (i = 0; i < MULTICONN_NFDS; i++) 252 close(fds[i]); 253 } 254 255 static void test_stream_msg_peek_client(const struct test_opts *opts) 256 { 257 int fd; 258 259 fd = vsock_stream_connect(opts->peer_cid, 1234); 260 if (fd < 0) { 261 perror("connect"); 262 exit(EXIT_FAILURE); 263 } 264 265 send_byte(fd, 1, 0); 266 close(fd); 267 } 268 269 static void test_stream_msg_peek_server(const struct test_opts *opts) 270 { 271 int fd; 272 273 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 274 if (fd < 0) { 275 perror("accept"); 276 exit(EXIT_FAILURE); 277 } 278 279 recv_byte(fd, 1, MSG_PEEK); 280 recv_byte(fd, 1, 0); 281 close(fd); 282 } 283 284 #define MESSAGES_CNT 7 285 static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) 286 { 287 int fd; 288 289 fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 290 if (fd < 0) { 291 perror("connect"); 292 exit(EXIT_FAILURE); 293 } 294 295 /* Send several messages, one with MSG_EOR flag */ 296 for (int i = 0; i < MESSAGES_CNT; i++) 297 send_byte(fd, 1, 0); 298 299 control_writeln("SENDDONE"); 300 close(fd); 301 } 302 303 static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) 304 { 305 int fd; 306 char buf[16]; 307 struct msghdr msg = {0}; 308 struct iovec iov = {0}; 309 310 fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 311 if (fd < 0) { 312 perror("accept"); 313 exit(EXIT_FAILURE); 314 } 315 316 control_expectln("SENDDONE"); 317 iov.iov_base = buf; 318 iov.iov_len = sizeof(buf); 319 msg.msg_iov = &iov; 320 msg.msg_iovlen = 1; 321 322 for (int i = 0; i < MESSAGES_CNT; i++) { 323 if (recvmsg(fd, &msg, 0) != 1) { 324 perror("message bound violated"); 325 exit(EXIT_FAILURE); 326 } 327 } 328 329 close(fd); 330 } 331 332 #define MESSAGE_TRUNC_SZ 32 333 static void test_seqpacket_msg_trunc_client(const struct test_opts *opts) 334 { 335 int fd; 336 char buf[MESSAGE_TRUNC_SZ]; 337 338 fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 339 if (fd < 0) { 340 perror("connect"); 341 exit(EXIT_FAILURE); 342 } 343 344 if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) { 345 perror("send failed"); 346 exit(EXIT_FAILURE); 347 } 348 349 control_writeln("SENDDONE"); 350 close(fd); 351 } 352 353 static void test_seqpacket_msg_trunc_server(const struct test_opts *opts) 354 { 355 int fd; 356 char buf[MESSAGE_TRUNC_SZ / 2]; 357 struct msghdr msg = {0}; 358 struct iovec iov = {0}; 359 360 fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 361 if (fd < 0) { 362 perror("accept"); 363 exit(EXIT_FAILURE); 364 } 365 366 control_expectln("SENDDONE"); 367 iov.iov_base = buf; 368 iov.iov_len = sizeof(buf); 369 msg.msg_iov = &iov; 370 msg.msg_iovlen = 1; 371 372 ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC); 373 374 if (ret != MESSAGE_TRUNC_SZ) { 375 printf("%zi\n", ret); 376 perror("MSG_TRUNC doesn't work"); 377 exit(EXIT_FAILURE); 378 } 379 380 if (!(msg.msg_flags & MSG_TRUNC)) { 381 fprintf(stderr, "MSG_TRUNC expected\n"); 382 exit(EXIT_FAILURE); 383 } 384 385 close(fd); 386 } 387 388 static struct test_case test_cases[] = { 389 { 390 .name = "SOCK_STREAM connection reset", 391 .run_client = test_stream_connection_reset, 392 }, 393 { 394 .name = "SOCK_STREAM bind only", 395 .run_client = test_stream_bind_only_client, 396 .run_server = test_stream_bind_only_server, 397 }, 398 { 399 .name = "SOCK_STREAM client close", 400 .run_client = test_stream_client_close_client, 401 .run_server = test_stream_client_close_server, 402 }, 403 { 404 .name = "SOCK_STREAM server close", 405 .run_client = test_stream_server_close_client, 406 .run_server = test_stream_server_close_server, 407 }, 408 { 409 .name = "SOCK_STREAM multiple connections", 410 .run_client = test_stream_multiconn_client, 411 .run_server = test_stream_multiconn_server, 412 }, 413 { 414 .name = "SOCK_STREAM MSG_PEEK", 415 .run_client = test_stream_msg_peek_client, 416 .run_server = test_stream_msg_peek_server, 417 }, 418 { 419 .name = "SOCK_SEQPACKET msg bounds", 420 .run_client = test_seqpacket_msg_bounds_client, 421 .run_server = test_seqpacket_msg_bounds_server, 422 }, 423 { 424 .name = "SOCK_SEQPACKET MSG_TRUNC flag", 425 .run_client = test_seqpacket_msg_trunc_client, 426 .run_server = test_seqpacket_msg_trunc_server, 427 }, 428 {}, 429 }; 430 431 static const char optstring[] = ""; 432 static const struct option longopts[] = { 433 { 434 .name = "control-host", 435 .has_arg = required_argument, 436 .val = 'H', 437 }, 438 { 439 .name = "control-port", 440 .has_arg = required_argument, 441 .val = 'P', 442 }, 443 { 444 .name = "mode", 445 .has_arg = required_argument, 446 .val = 'm', 447 }, 448 { 449 .name = "peer-cid", 450 .has_arg = required_argument, 451 .val = 'p', 452 }, 453 { 454 .name = "list", 455 .has_arg = no_argument, 456 .val = 'l', 457 }, 458 { 459 .name = "skip", 460 .has_arg = required_argument, 461 .val = 's', 462 }, 463 { 464 .name = "help", 465 .has_arg = no_argument, 466 .val = '?', 467 }, 468 {}, 469 }; 470 471 static void usage(void) 472 { 473 fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n" 474 "\n" 475 " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n" 476 " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" 477 "\n" 478 "Run vsock.ko tests. Must be launched in both guest\n" 479 "and host. One side must use --mode=client and\n" 480 "the other side must use --mode=server.\n" 481 "\n" 482 "A TCP control socket connection is used to coordinate tests\n" 483 "between the client and the server. The server requires a\n" 484 "listen address and the client requires an address to\n" 485 "connect to.\n" 486 "\n" 487 "The CID of the other side must be given with --peer-cid=<cid>.\n" 488 "\n" 489 "Options:\n" 490 " --help This help message\n" 491 " --control-host <host> Server IP address to connect to\n" 492 " --control-port <port> Server port to listen on/connect to\n" 493 " --mode client|server Server or client mode\n" 494 " --peer-cid <cid> CID of the other side\n" 495 " --list List of tests that will be executed\n" 496 " --skip <test_id> Test ID to skip;\n" 497 " use multiple --skip options to skip more tests\n" 498 ); 499 exit(EXIT_FAILURE); 500 } 501 502 int main(int argc, char **argv) 503 { 504 const char *control_host = NULL; 505 const char *control_port = NULL; 506 struct test_opts opts = { 507 .mode = TEST_MODE_UNSET, 508 .peer_cid = VMADDR_CID_ANY, 509 }; 510 511 init_signals(); 512 513 for (;;) { 514 int opt = getopt_long(argc, argv, optstring, longopts, NULL); 515 516 if (opt == -1) 517 break; 518 519 switch (opt) { 520 case 'H': 521 control_host = optarg; 522 break; 523 case 'm': 524 if (strcmp(optarg, "client") == 0) 525 opts.mode = TEST_MODE_CLIENT; 526 else if (strcmp(optarg, "server") == 0) 527 opts.mode = TEST_MODE_SERVER; 528 else { 529 fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); 530 return EXIT_FAILURE; 531 } 532 break; 533 case 'p': 534 opts.peer_cid = parse_cid(optarg); 535 break; 536 case 'P': 537 control_port = optarg; 538 break; 539 case 'l': 540 list_tests(test_cases); 541 break; 542 case 's': 543 skip_test(test_cases, ARRAY_SIZE(test_cases) - 1, 544 optarg); 545 break; 546 case '?': 547 default: 548 usage(); 549 } 550 } 551 552 if (!control_port) 553 usage(); 554 if (opts.mode == TEST_MODE_UNSET) 555 usage(); 556 if (opts.peer_cid == VMADDR_CID_ANY) 557 usage(); 558 559 if (!control_host) { 560 if (opts.mode != TEST_MODE_SERVER) 561 usage(); 562 control_host = "0.0.0.0"; 563 } 564 565 control_init(control_host, control_port, 566 opts.mode == TEST_MODE_SERVER); 567 568 run_tests(test_cases, &opts); 569 570 control_cleanup(); 571 return EXIT_SUCCESS; 572 } 573