| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * vsock_diag_test - vsock_diag.ko test suite |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2017 Red Hat, Inc. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Stefan Hajnoczi <stefanha@redhat.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or |
|---|
| 9 | | - * modify it under the terms of the GNU General Public License |
|---|
| 10 | | - * as published by the Free Software Foundation; version 2 |
|---|
| 11 | | - * of the License. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 14 | 10 | #include <getopt.h> |
|---|
| 15 | 11 | #include <stdio.h> |
|---|
| 16 | | -#include <stdbool.h> |
|---|
| 17 | 12 | #include <stdlib.h> |
|---|
| 18 | 13 | #include <string.h> |
|---|
| 19 | 14 | #include <errno.h> |
|---|
| 20 | 15 | #include <unistd.h> |
|---|
| 21 | | -#include <signal.h> |
|---|
| 22 | | -#include <sys/socket.h> |
|---|
| 23 | 16 | #include <sys/stat.h> |
|---|
| 24 | 17 | #include <sys/types.h> |
|---|
| 25 | 18 | #include <linux/list.h> |
|---|
| 26 | 19 | #include <linux/net.h> |
|---|
| 27 | 20 | #include <linux/netlink.h> |
|---|
| 28 | 21 | #include <linux/sock_diag.h> |
|---|
| 22 | +#include <linux/vm_sockets_diag.h> |
|---|
| 29 | 23 | #include <netinet/tcp.h> |
|---|
| 30 | | - |
|---|
| 31 | | -#include "../../../include/uapi/linux/vm_sockets.h" |
|---|
| 32 | | -#include "../../../include/uapi/linux/vm_sockets_diag.h" |
|---|
| 33 | 24 | |
|---|
| 34 | 25 | #include "timeout.h" |
|---|
| 35 | 26 | #include "control.h" |
|---|
| 36 | | - |
|---|
| 37 | | -enum test_mode { |
|---|
| 38 | | - TEST_MODE_UNSET, |
|---|
| 39 | | - TEST_MODE_CLIENT, |
|---|
| 40 | | - TEST_MODE_SERVER |
|---|
| 41 | | -}; |
|---|
| 27 | +#include "util.h" |
|---|
| 42 | 28 | |
|---|
| 43 | 29 | /* Per-socket status */ |
|---|
| 44 | 30 | struct vsock_stat { |
|---|
| .. | .. |
|---|
| 339 | 325 | free(st); |
|---|
| 340 | 326 | } |
|---|
| 341 | 327 | |
|---|
| 342 | | -static void test_no_sockets(unsigned int peer_cid) |
|---|
| 328 | +static void test_no_sockets(const struct test_opts *opts) |
|---|
| 343 | 329 | { |
|---|
| 344 | 330 | LIST_HEAD(sockets); |
|---|
| 345 | 331 | |
|---|
| .. | .. |
|---|
| 350 | 336 | free_sock_stat(&sockets); |
|---|
| 351 | 337 | } |
|---|
| 352 | 338 | |
|---|
| 353 | | -static void test_listen_socket_server(unsigned int peer_cid) |
|---|
| 339 | +static void test_listen_socket_server(const struct test_opts *opts) |
|---|
| 354 | 340 | { |
|---|
| 355 | 341 | union { |
|---|
| 356 | 342 | struct sockaddr sa; |
|---|
| .. | .. |
|---|
| 388 | 374 | free_sock_stat(&sockets); |
|---|
| 389 | 375 | } |
|---|
| 390 | 376 | |
|---|
| 391 | | -static void test_connect_client(unsigned int peer_cid) |
|---|
| 377 | +static void test_connect_client(const struct test_opts *opts) |
|---|
| 392 | 378 | { |
|---|
| 393 | | - union { |
|---|
| 394 | | - struct sockaddr sa; |
|---|
| 395 | | - struct sockaddr_vm svm; |
|---|
| 396 | | - } addr = { |
|---|
| 397 | | - .svm = { |
|---|
| 398 | | - .svm_family = AF_VSOCK, |
|---|
| 399 | | - .svm_port = 1234, |
|---|
| 400 | | - .svm_cid = peer_cid, |
|---|
| 401 | | - }, |
|---|
| 402 | | - }; |
|---|
| 403 | 379 | int fd; |
|---|
| 404 | | - int ret; |
|---|
| 405 | 380 | LIST_HEAD(sockets); |
|---|
| 406 | 381 | struct vsock_stat *st; |
|---|
| 407 | 382 | |
|---|
| 408 | | - control_expectln("LISTENING"); |
|---|
| 409 | | - |
|---|
| 410 | | - fd = socket(AF_VSOCK, SOCK_STREAM, 0); |
|---|
| 411 | | - |
|---|
| 412 | | - timeout_begin(TIMEOUT); |
|---|
| 413 | | - do { |
|---|
| 414 | | - ret = connect(fd, &addr.sa, sizeof(addr.svm)); |
|---|
| 415 | | - timeout_check("connect"); |
|---|
| 416 | | - } while (ret < 0 && errno == EINTR); |
|---|
| 417 | | - timeout_end(); |
|---|
| 418 | | - |
|---|
| 419 | | - if (ret < 0) { |
|---|
| 383 | + fd = vsock_stream_connect(opts->peer_cid, 1234); |
|---|
| 384 | + if (fd < 0) { |
|---|
| 420 | 385 | perror("connect"); |
|---|
| 421 | 386 | exit(EXIT_FAILURE); |
|---|
| 422 | 387 | } |
|---|
| .. | .. |
|---|
| 434 | 399 | free_sock_stat(&sockets); |
|---|
| 435 | 400 | } |
|---|
| 436 | 401 | |
|---|
| 437 | | -static void test_connect_server(unsigned int peer_cid) |
|---|
| 402 | +static void test_connect_server(const struct test_opts *opts) |
|---|
| 438 | 403 | { |
|---|
| 439 | | - union { |
|---|
| 440 | | - struct sockaddr sa; |
|---|
| 441 | | - struct sockaddr_vm svm; |
|---|
| 442 | | - } addr = { |
|---|
| 443 | | - .svm = { |
|---|
| 444 | | - .svm_family = AF_VSOCK, |
|---|
| 445 | | - .svm_port = 1234, |
|---|
| 446 | | - .svm_cid = VMADDR_CID_ANY, |
|---|
| 447 | | - }, |
|---|
| 448 | | - }; |
|---|
| 449 | | - union { |
|---|
| 450 | | - struct sockaddr sa; |
|---|
| 451 | | - struct sockaddr_vm svm; |
|---|
| 452 | | - } clientaddr; |
|---|
| 453 | | - socklen_t clientaddr_len = sizeof(clientaddr.svm); |
|---|
| 454 | | - LIST_HEAD(sockets); |
|---|
| 455 | 404 | struct vsock_stat *st; |
|---|
| 456 | | - int fd; |
|---|
| 405 | + LIST_HEAD(sockets); |
|---|
| 457 | 406 | int client_fd; |
|---|
| 458 | 407 | |
|---|
| 459 | | - fd = socket(AF_VSOCK, SOCK_STREAM, 0); |
|---|
| 460 | | - |
|---|
| 461 | | - if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { |
|---|
| 462 | | - perror("bind"); |
|---|
| 463 | | - exit(EXIT_FAILURE); |
|---|
| 464 | | - } |
|---|
| 465 | | - |
|---|
| 466 | | - if (listen(fd, 1) < 0) { |
|---|
| 467 | | - perror("listen"); |
|---|
| 468 | | - exit(EXIT_FAILURE); |
|---|
| 469 | | - } |
|---|
| 470 | | - |
|---|
| 471 | | - control_writeln("LISTENING"); |
|---|
| 472 | | - |
|---|
| 473 | | - timeout_begin(TIMEOUT); |
|---|
| 474 | | - do { |
|---|
| 475 | | - client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); |
|---|
| 476 | | - timeout_check("accept"); |
|---|
| 477 | | - } while (client_fd < 0 && errno == EINTR); |
|---|
| 478 | | - timeout_end(); |
|---|
| 479 | | - |
|---|
| 408 | + client_fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); |
|---|
| 480 | 409 | if (client_fd < 0) { |
|---|
| 481 | 410 | perror("accept"); |
|---|
| 482 | | - exit(EXIT_FAILURE); |
|---|
| 483 | | - } |
|---|
| 484 | | - if (clientaddr.sa.sa_family != AF_VSOCK) { |
|---|
| 485 | | - fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n", |
|---|
| 486 | | - clientaddr.sa.sa_family); |
|---|
| 487 | | - exit(EXIT_FAILURE); |
|---|
| 488 | | - } |
|---|
| 489 | | - if (clientaddr.svm.svm_cid != peer_cid) { |
|---|
| 490 | | - fprintf(stderr, "expected peer CID %u from accept(2), got %u\n", |
|---|
| 491 | | - peer_cid, clientaddr.svm.svm_cid); |
|---|
| 492 | 411 | exit(EXIT_FAILURE); |
|---|
| 493 | 412 | } |
|---|
| 494 | 413 | |
|---|
| 495 | 414 | read_vsock_stat(&sockets); |
|---|
| 496 | 415 | |
|---|
| 497 | | - check_num_sockets(&sockets, 2); |
|---|
| 498 | | - find_vsock_stat(&sockets, fd); |
|---|
| 416 | + check_num_sockets(&sockets, 1); |
|---|
| 499 | 417 | st = find_vsock_stat(&sockets, client_fd); |
|---|
| 500 | 418 | check_socket_state(st, TCP_ESTABLISHED); |
|---|
| 501 | 419 | |
|---|
| .. | .. |
|---|
| 503 | 421 | control_expectln("DONE"); |
|---|
| 504 | 422 | |
|---|
| 505 | 423 | close(client_fd); |
|---|
| 506 | | - close(fd); |
|---|
| 507 | 424 | free_sock_stat(&sockets); |
|---|
| 508 | 425 | } |
|---|
| 509 | 426 | |
|---|
| 510 | | -static struct { |
|---|
| 511 | | - const char *name; |
|---|
| 512 | | - void (*run_client)(unsigned int peer_cid); |
|---|
| 513 | | - void (*run_server)(unsigned int peer_cid); |
|---|
| 514 | | -} test_cases[] = { |
|---|
| 427 | +static struct test_case test_cases[] = { |
|---|
| 515 | 428 | { |
|---|
| 516 | 429 | .name = "No sockets", |
|---|
| 517 | 430 | .run_server = test_no_sockets, |
|---|
| .. | .. |
|---|
| 527 | 440 | }, |
|---|
| 528 | 441 | {}, |
|---|
| 529 | 442 | }; |
|---|
| 530 | | - |
|---|
| 531 | | -static void init_signals(void) |
|---|
| 532 | | -{ |
|---|
| 533 | | - struct sigaction act = { |
|---|
| 534 | | - .sa_handler = sigalrm, |
|---|
| 535 | | - }; |
|---|
| 536 | | - |
|---|
| 537 | | - sigaction(SIGALRM, &act, NULL); |
|---|
| 538 | | - signal(SIGPIPE, SIG_IGN); |
|---|
| 539 | | -} |
|---|
| 540 | | - |
|---|
| 541 | | -static unsigned int parse_cid(const char *str) |
|---|
| 542 | | -{ |
|---|
| 543 | | - char *endptr = NULL; |
|---|
| 544 | | - unsigned long int n; |
|---|
| 545 | | - |
|---|
| 546 | | - errno = 0; |
|---|
| 547 | | - n = strtoul(str, &endptr, 10); |
|---|
| 548 | | - if (errno || *endptr != '\0') { |
|---|
| 549 | | - fprintf(stderr, "malformed CID \"%s\"\n", str); |
|---|
| 550 | | - exit(EXIT_FAILURE); |
|---|
| 551 | | - } |
|---|
| 552 | | - return n; |
|---|
| 553 | | -} |
|---|
| 554 | 443 | |
|---|
| 555 | 444 | static const char optstring[] = ""; |
|---|
| 556 | 445 | static const struct option longopts[] = { |
|---|
| .. | .. |
|---|
| 575 | 464 | .val = 'p', |
|---|
| 576 | 465 | }, |
|---|
| 577 | 466 | { |
|---|
| 467 | + .name = "list", |
|---|
| 468 | + .has_arg = no_argument, |
|---|
| 469 | + .val = 'l', |
|---|
| 470 | + }, |
|---|
| 471 | + { |
|---|
| 472 | + .name = "skip", |
|---|
| 473 | + .has_arg = required_argument, |
|---|
| 474 | + .val = 's', |
|---|
| 475 | + }, |
|---|
| 476 | + { |
|---|
| 578 | 477 | .name = "help", |
|---|
| 579 | 478 | .has_arg = no_argument, |
|---|
| 580 | 479 | .val = '?', |
|---|
| .. | .. |
|---|
| 584 | 483 | |
|---|
| 585 | 484 | static void usage(void) |
|---|
| 586 | 485 | { |
|---|
| 587 | | - fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid>\n" |
|---|
| 486 | + fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n" |
|---|
| 588 | 487 | "\n" |
|---|
| 589 | 488 | " Server: vsock_diag_test --control-port=1234 --mode=server --peer-cid=3\n" |
|---|
| 590 | 489 | " Client: vsock_diag_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" |
|---|
| .. | .. |
|---|
| 598 | 497 | "listen address and the client requires an address to\n" |
|---|
| 599 | 498 | "connect to.\n" |
|---|
| 600 | 499 | "\n" |
|---|
| 601 | | - "The CID of the other side must be given with --peer-cid=<cid>.\n"); |
|---|
| 500 | + "The CID of the other side must be given with --peer-cid=<cid>.\n" |
|---|
| 501 | + "\n" |
|---|
| 502 | + "Options:\n" |
|---|
| 503 | + " --help This help message\n" |
|---|
| 504 | + " --control-host <host> Server IP address to connect to\n" |
|---|
| 505 | + " --control-port <port> Server port to listen on/connect to\n" |
|---|
| 506 | + " --mode client|server Server or client mode\n" |
|---|
| 507 | + " --peer-cid <cid> CID of the other side\n" |
|---|
| 508 | + " --list List of tests that will be executed\n" |
|---|
| 509 | + " --skip <test_id> Test ID to skip;\n" |
|---|
| 510 | + " use multiple --skip options to skip more tests\n" |
|---|
| 511 | + ); |
|---|
| 602 | 512 | exit(EXIT_FAILURE); |
|---|
| 603 | 513 | } |
|---|
| 604 | 514 | |
|---|
| .. | .. |
|---|
| 606 | 516 | { |
|---|
| 607 | 517 | const char *control_host = NULL; |
|---|
| 608 | 518 | const char *control_port = NULL; |
|---|
| 609 | | - int mode = TEST_MODE_UNSET; |
|---|
| 610 | | - unsigned int peer_cid = VMADDR_CID_ANY; |
|---|
| 611 | | - int i; |
|---|
| 519 | + struct test_opts opts = { |
|---|
| 520 | + .mode = TEST_MODE_UNSET, |
|---|
| 521 | + .peer_cid = VMADDR_CID_ANY, |
|---|
| 522 | + }; |
|---|
| 612 | 523 | |
|---|
| 613 | 524 | init_signals(); |
|---|
| 614 | 525 | |
|---|
| .. | .. |
|---|
| 624 | 535 | break; |
|---|
| 625 | 536 | case 'm': |
|---|
| 626 | 537 | if (strcmp(optarg, "client") == 0) |
|---|
| 627 | | - mode = TEST_MODE_CLIENT; |
|---|
| 538 | + opts.mode = TEST_MODE_CLIENT; |
|---|
| 628 | 539 | else if (strcmp(optarg, "server") == 0) |
|---|
| 629 | | - mode = TEST_MODE_SERVER; |
|---|
| 540 | + opts.mode = TEST_MODE_SERVER; |
|---|
| 630 | 541 | else { |
|---|
| 631 | 542 | fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); |
|---|
| 632 | 543 | return EXIT_FAILURE; |
|---|
| 633 | 544 | } |
|---|
| 634 | 545 | break; |
|---|
| 635 | 546 | case 'p': |
|---|
| 636 | | - peer_cid = parse_cid(optarg); |
|---|
| 547 | + opts.peer_cid = parse_cid(optarg); |
|---|
| 637 | 548 | break; |
|---|
| 638 | 549 | case 'P': |
|---|
| 639 | 550 | control_port = optarg; |
|---|
| 551 | + break; |
|---|
| 552 | + case 'l': |
|---|
| 553 | + list_tests(test_cases); |
|---|
| 554 | + break; |
|---|
| 555 | + case 's': |
|---|
| 556 | + skip_test(test_cases, ARRAY_SIZE(test_cases) - 1, |
|---|
| 557 | + optarg); |
|---|
| 640 | 558 | break; |
|---|
| 641 | 559 | case '?': |
|---|
| 642 | 560 | default: |
|---|
| .. | .. |
|---|
| 646 | 564 | |
|---|
| 647 | 565 | if (!control_port) |
|---|
| 648 | 566 | usage(); |
|---|
| 649 | | - if (mode == TEST_MODE_UNSET) |
|---|
| 567 | + if (opts.mode == TEST_MODE_UNSET) |
|---|
| 650 | 568 | usage(); |
|---|
| 651 | | - if (peer_cid == VMADDR_CID_ANY) |
|---|
| 569 | + if (opts.peer_cid == VMADDR_CID_ANY) |
|---|
| 652 | 570 | usage(); |
|---|
| 653 | 571 | |
|---|
| 654 | 572 | if (!control_host) { |
|---|
| 655 | | - if (mode != TEST_MODE_SERVER) |
|---|
| 573 | + if (opts.mode != TEST_MODE_SERVER) |
|---|
| 656 | 574 | usage(); |
|---|
| 657 | 575 | control_host = "0.0.0.0"; |
|---|
| 658 | 576 | } |
|---|
| 659 | 577 | |
|---|
| 660 | | - control_init(control_host, control_port, mode == TEST_MODE_SERVER); |
|---|
| 578 | + control_init(control_host, control_port, |
|---|
| 579 | + opts.mode == TEST_MODE_SERVER); |
|---|
| 661 | 580 | |
|---|
| 662 | | - for (i = 0; test_cases[i].name; i++) { |
|---|
| 663 | | - void (*run)(unsigned int peer_cid); |
|---|
| 664 | | - |
|---|
| 665 | | - printf("%s...", test_cases[i].name); |
|---|
| 666 | | - fflush(stdout); |
|---|
| 667 | | - |
|---|
| 668 | | - if (mode == TEST_MODE_CLIENT) |
|---|
| 669 | | - run = test_cases[i].run_client; |
|---|
| 670 | | - else |
|---|
| 671 | | - run = test_cases[i].run_server; |
|---|
| 672 | | - |
|---|
| 673 | | - if (run) |
|---|
| 674 | | - run(peer_cid); |
|---|
| 675 | | - |
|---|
| 676 | | - printf("ok\n"); |
|---|
| 677 | | - } |
|---|
| 581 | + run_tests(test_cases, &opts); |
|---|
| 678 | 582 | |
|---|
| 679 | 583 | control_cleanup(); |
|---|
| 680 | 584 | return EXIT_SUCCESS; |
|---|