.. | .. |
---|
| 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; |
---|