Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * vsock_test - vsock.ko test suite
0004  *
0005  * Copyright (C) 2017 Red Hat, Inc.
0006  *
0007  * Author: Stefan Hajnoczi <stefanha@redhat.com>
0008  */
0009 
0010 #include <getopt.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include <errno.h>
0015 #include <unistd.h>
0016 #include <linux/kernel.h>
0017 #include <sys/types.h>
0018 #include <sys/socket.h>
0019 #include <time.h>
0020 #include <sys/mman.h>
0021 
0022 #include "timeout.h"
0023 #include "control.h"
0024 #include "util.h"
0025 
0026 static void test_stream_connection_reset(const struct test_opts *opts)
0027 {
0028     union {
0029         struct sockaddr sa;
0030         struct sockaddr_vm svm;
0031     } addr = {
0032         .svm = {
0033             .svm_family = AF_VSOCK,
0034             .svm_port = 1234,
0035             .svm_cid = opts->peer_cid,
0036         },
0037     };
0038     int ret;
0039     int fd;
0040 
0041     fd = socket(AF_VSOCK, SOCK_STREAM, 0);
0042 
0043     timeout_begin(TIMEOUT);
0044     do {
0045         ret = connect(fd, &addr.sa, sizeof(addr.svm));
0046         timeout_check("connect");
0047     } while (ret < 0 && errno == EINTR);
0048     timeout_end();
0049 
0050     if (ret != -1) {
0051         fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
0052         exit(EXIT_FAILURE);
0053     }
0054     if (errno != ECONNRESET) {
0055         fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
0056         exit(EXIT_FAILURE);
0057     }
0058 
0059     close(fd);
0060 }
0061 
0062 static void test_stream_bind_only_client(const struct test_opts *opts)
0063 {
0064     union {
0065         struct sockaddr sa;
0066         struct sockaddr_vm svm;
0067     } addr = {
0068         .svm = {
0069             .svm_family = AF_VSOCK,
0070             .svm_port = 1234,
0071             .svm_cid = opts->peer_cid,
0072         },
0073     };
0074     int ret;
0075     int fd;
0076 
0077     /* Wait for the server to be ready */
0078     control_expectln("BIND");
0079 
0080     fd = socket(AF_VSOCK, SOCK_STREAM, 0);
0081 
0082     timeout_begin(TIMEOUT);
0083     do {
0084         ret = connect(fd, &addr.sa, sizeof(addr.svm));
0085         timeout_check("connect");
0086     } while (ret < 0 && errno == EINTR);
0087     timeout_end();
0088 
0089     if (ret != -1) {
0090         fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
0091         exit(EXIT_FAILURE);
0092     }
0093     if (errno != ECONNRESET) {
0094         fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
0095         exit(EXIT_FAILURE);
0096     }
0097 
0098     /* Notify the server that the client has finished */
0099     control_writeln("DONE");
0100 
0101     close(fd);
0102 }
0103 
0104 static void test_stream_bind_only_server(const struct test_opts *opts)
0105 {
0106     union {
0107         struct sockaddr sa;
0108         struct sockaddr_vm svm;
0109     } addr = {
0110         .svm = {
0111             .svm_family = AF_VSOCK,
0112             .svm_port = 1234,
0113             .svm_cid = VMADDR_CID_ANY,
0114         },
0115     };
0116     int fd;
0117 
0118     fd = socket(AF_VSOCK, SOCK_STREAM, 0);
0119 
0120     if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
0121         perror("bind");
0122         exit(EXIT_FAILURE);
0123     }
0124 
0125     /* Notify the client that the server is ready */
0126     control_writeln("BIND");
0127 
0128     /* Wait for the client to finish */
0129     control_expectln("DONE");
0130 
0131     close(fd);
0132 }
0133 
0134 static void test_stream_client_close_client(const struct test_opts *opts)
0135 {
0136     int fd;
0137 
0138     fd = vsock_stream_connect(opts->peer_cid, 1234);
0139     if (fd < 0) {
0140         perror("connect");
0141         exit(EXIT_FAILURE);
0142     }
0143 
0144     send_byte(fd, 1, 0);
0145     close(fd);
0146 }
0147 
0148 static void test_stream_client_close_server(const struct test_opts *opts)
0149 {
0150     int fd;
0151 
0152     fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
0153     if (fd < 0) {
0154         perror("accept");
0155         exit(EXIT_FAILURE);
0156     }
0157 
0158     /* Wait for the remote to close the connection, before check
0159      * -EPIPE error on send.
0160      */
0161     vsock_wait_remote_close(fd);
0162 
0163     send_byte(fd, -EPIPE, 0);
0164     recv_byte(fd, 1, 0);
0165     recv_byte(fd, 0, 0);
0166     close(fd);
0167 }
0168 
0169 static void test_stream_server_close_client(const struct test_opts *opts)
0170 {
0171     int fd;
0172 
0173     fd = vsock_stream_connect(opts->peer_cid, 1234);
0174     if (fd < 0) {
0175         perror("connect");
0176         exit(EXIT_FAILURE);
0177     }
0178 
0179     /* Wait for the remote to close the connection, before check
0180      * -EPIPE error on send.
0181      */
0182     vsock_wait_remote_close(fd);
0183 
0184     send_byte(fd, -EPIPE, 0);
0185     recv_byte(fd, 1, 0);
0186     recv_byte(fd, 0, 0);
0187     close(fd);
0188 }
0189 
0190 static void test_stream_server_close_server(const struct test_opts *opts)
0191 {
0192     int fd;
0193 
0194     fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
0195     if (fd < 0) {
0196         perror("accept");
0197         exit(EXIT_FAILURE);
0198     }
0199 
0200     send_byte(fd, 1, 0);
0201     close(fd);
0202 }
0203 
0204 /* With the standard socket sizes, VMCI is able to support about 100
0205  * concurrent stream connections.
0206  */
0207 #define MULTICONN_NFDS 100
0208 
0209 static void test_stream_multiconn_client(const struct test_opts *opts)
0210 {
0211     int fds[MULTICONN_NFDS];
0212     int i;
0213 
0214     for (i = 0; i < MULTICONN_NFDS; i++) {
0215         fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
0216         if (fds[i] < 0) {
0217             perror("connect");
0218             exit(EXIT_FAILURE);
0219         }
0220     }
0221 
0222     for (i = 0; i < MULTICONN_NFDS; i++) {
0223         if (i % 2)
0224             recv_byte(fds[i], 1, 0);
0225         else
0226             send_byte(fds[i], 1, 0);
0227     }
0228 
0229     for (i = 0; i < MULTICONN_NFDS; i++)
0230         close(fds[i]);
0231 }
0232 
0233 static void test_stream_multiconn_server(const struct test_opts *opts)
0234 {
0235     int fds[MULTICONN_NFDS];
0236     int i;
0237 
0238     for (i = 0; i < MULTICONN_NFDS; i++) {
0239         fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
0240         if (fds[i] < 0) {
0241             perror("accept");
0242             exit(EXIT_FAILURE);
0243         }
0244     }
0245 
0246     for (i = 0; i < MULTICONN_NFDS; i++) {
0247         if (i % 2)
0248             send_byte(fds[i], 1, 0);
0249         else
0250             recv_byte(fds[i], 1, 0);
0251     }
0252 
0253     for (i = 0; i < MULTICONN_NFDS; i++)
0254         close(fds[i]);
0255 }
0256 
0257 static void test_stream_msg_peek_client(const struct test_opts *opts)
0258 {
0259     int fd;
0260 
0261     fd = vsock_stream_connect(opts->peer_cid, 1234);
0262     if (fd < 0) {
0263         perror("connect");
0264         exit(EXIT_FAILURE);
0265     }
0266 
0267     send_byte(fd, 1, 0);
0268     close(fd);
0269 }
0270 
0271 static void test_stream_msg_peek_server(const struct test_opts *opts)
0272 {
0273     int fd;
0274 
0275     fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
0276     if (fd < 0) {
0277         perror("accept");
0278         exit(EXIT_FAILURE);
0279     }
0280 
0281     recv_byte(fd, 1, MSG_PEEK);
0282     recv_byte(fd, 1, 0);
0283     close(fd);
0284 }
0285 
0286 #define MESSAGES_CNT 7
0287 #define MSG_EOR_IDX (MESSAGES_CNT / 2)
0288 static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
0289 {
0290     int fd;
0291 
0292     fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
0293     if (fd < 0) {
0294         perror("connect");
0295         exit(EXIT_FAILURE);
0296     }
0297 
0298     /* Send several messages, one with MSG_EOR flag */
0299     for (int i = 0; i < MESSAGES_CNT; i++)
0300         send_byte(fd, 1, (i == MSG_EOR_IDX) ? MSG_EOR : 0);
0301 
0302     control_writeln("SENDDONE");
0303     close(fd);
0304 }
0305 
0306 static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
0307 {
0308     int fd;
0309     char buf[16];
0310     struct msghdr msg = {0};
0311     struct iovec iov = {0};
0312 
0313     fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
0314     if (fd < 0) {
0315         perror("accept");
0316         exit(EXIT_FAILURE);
0317     }
0318 
0319     control_expectln("SENDDONE");
0320     iov.iov_base = buf;
0321     iov.iov_len = sizeof(buf);
0322     msg.msg_iov = &iov;
0323     msg.msg_iovlen = 1;
0324 
0325     for (int i = 0; i < MESSAGES_CNT; i++) {
0326         if (recvmsg(fd, &msg, 0) != 1) {
0327             perror("message bound violated");
0328             exit(EXIT_FAILURE);
0329         }
0330 
0331         if ((i == MSG_EOR_IDX) ^ !!(msg.msg_flags & MSG_EOR)) {
0332             perror("MSG_EOR");
0333             exit(EXIT_FAILURE);
0334         }
0335     }
0336 
0337     close(fd);
0338 }
0339 
0340 #define MESSAGE_TRUNC_SZ 32
0341 static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
0342 {
0343     int fd;
0344     char buf[MESSAGE_TRUNC_SZ];
0345 
0346     fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
0347     if (fd < 0) {
0348         perror("connect");
0349         exit(EXIT_FAILURE);
0350     }
0351 
0352     if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
0353         perror("send failed");
0354         exit(EXIT_FAILURE);
0355     }
0356 
0357     control_writeln("SENDDONE");
0358     close(fd);
0359 }
0360 
0361 static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
0362 {
0363     int fd;
0364     char buf[MESSAGE_TRUNC_SZ / 2];
0365     struct msghdr msg = {0};
0366     struct iovec iov = {0};
0367 
0368     fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
0369     if (fd < 0) {
0370         perror("accept");
0371         exit(EXIT_FAILURE);
0372     }
0373 
0374     control_expectln("SENDDONE");
0375     iov.iov_base = buf;
0376     iov.iov_len = sizeof(buf);
0377     msg.msg_iov = &iov;
0378     msg.msg_iovlen = 1;
0379 
0380     ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
0381 
0382     if (ret != MESSAGE_TRUNC_SZ) {
0383         printf("%zi\n", ret);
0384         perror("MSG_TRUNC doesn't work");
0385         exit(EXIT_FAILURE);
0386     }
0387 
0388     if (!(msg.msg_flags & MSG_TRUNC)) {
0389         fprintf(stderr, "MSG_TRUNC expected\n");
0390         exit(EXIT_FAILURE);
0391     }
0392 
0393     close(fd);
0394 }
0395 
0396 static time_t current_nsec(void)
0397 {
0398     struct timespec ts;
0399 
0400     if (clock_gettime(CLOCK_REALTIME, &ts)) {
0401         perror("clock_gettime(3) failed");
0402         exit(EXIT_FAILURE);
0403     }
0404 
0405     return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
0406 }
0407 
0408 #define RCVTIMEO_TIMEOUT_SEC 1
0409 #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
0410 
0411 static void test_seqpacket_timeout_client(const struct test_opts *opts)
0412 {
0413     int fd;
0414     struct timeval tv;
0415     char dummy;
0416     time_t read_enter_ns;
0417     time_t read_overhead_ns;
0418 
0419     fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
0420     if (fd < 0) {
0421         perror("connect");
0422         exit(EXIT_FAILURE);
0423     }
0424 
0425     tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
0426     tv.tv_usec = 0;
0427 
0428     if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
0429         perror("setsockopt 'SO_RCVTIMEO'");
0430         exit(EXIT_FAILURE);
0431     }
0432 
0433     read_enter_ns = current_nsec();
0434 
0435     if (read(fd, &dummy, sizeof(dummy)) != -1) {
0436         fprintf(stderr,
0437             "expected 'dummy' read(2) failure\n");
0438         exit(EXIT_FAILURE);
0439     }
0440 
0441     if (errno != EAGAIN) {
0442         perror("EAGAIN expected");
0443         exit(EXIT_FAILURE);
0444     }
0445 
0446     read_overhead_ns = current_nsec() - read_enter_ns -
0447             1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
0448 
0449     if (read_overhead_ns > READ_OVERHEAD_NSEC) {
0450         fprintf(stderr,
0451             "too much time in read(2), %lu > %i ns\n",
0452             read_overhead_ns, READ_OVERHEAD_NSEC);
0453         exit(EXIT_FAILURE);
0454     }
0455 
0456     control_writeln("WAITDONE");
0457     close(fd);
0458 }
0459 
0460 static void test_seqpacket_timeout_server(const struct test_opts *opts)
0461 {
0462     int fd;
0463 
0464     fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
0465     if (fd < 0) {
0466         perror("accept");
0467         exit(EXIT_FAILURE);
0468     }
0469 
0470     control_expectln("WAITDONE");
0471     close(fd);
0472 }
0473 
0474 #define BUF_PATTERN_1 'a'
0475 #define BUF_PATTERN_2 'b'
0476 
0477 static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
0478 {
0479     int fd;
0480     unsigned char *buf1;
0481     unsigned char *buf2;
0482     int buf_size = getpagesize() * 3;
0483 
0484     fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
0485     if (fd < 0) {
0486         perror("connect");
0487         exit(EXIT_FAILURE);
0488     }
0489 
0490     buf1 = malloc(buf_size);
0491     if (!buf1) {
0492         perror("'malloc()' for 'buf1'");
0493         exit(EXIT_FAILURE);
0494     }
0495 
0496     buf2 = malloc(buf_size);
0497     if (!buf2) {
0498         perror("'malloc()' for 'buf2'");
0499         exit(EXIT_FAILURE);
0500     }
0501 
0502     memset(buf1, BUF_PATTERN_1, buf_size);
0503     memset(buf2, BUF_PATTERN_2, buf_size);
0504 
0505     if (send(fd, buf1, buf_size, 0) != buf_size) {
0506         perror("send failed");
0507         exit(EXIT_FAILURE);
0508     }
0509 
0510     if (send(fd, buf2, buf_size, 0) != buf_size) {
0511         perror("send failed");
0512         exit(EXIT_FAILURE);
0513     }
0514 
0515     close(fd);
0516 }
0517 
0518 static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
0519 {
0520     int fd;
0521     unsigned char *broken_buf;
0522     unsigned char *valid_buf;
0523     int page_size = getpagesize();
0524     int buf_size = page_size * 3;
0525     ssize_t res;
0526     int prot = PROT_READ | PROT_WRITE;
0527     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
0528     int i;
0529 
0530     fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
0531     if (fd < 0) {
0532         perror("accept");
0533         exit(EXIT_FAILURE);
0534     }
0535 
0536     /* Setup first buffer. */
0537     broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
0538     if (broken_buf == MAP_FAILED) {
0539         perror("mmap for 'broken_buf'");
0540         exit(EXIT_FAILURE);
0541     }
0542 
0543     /* Unmap "hole" in buffer. */
0544     if (munmap(broken_buf + page_size, page_size)) {
0545         perror("'broken_buf' setup");
0546         exit(EXIT_FAILURE);
0547     }
0548 
0549     valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
0550     if (valid_buf == MAP_FAILED) {
0551         perror("mmap for 'valid_buf'");
0552         exit(EXIT_FAILURE);
0553     }
0554 
0555     /* Try to fill buffer with unmapped middle. */
0556     res = read(fd, broken_buf, buf_size);
0557     if (res != -1) {
0558         fprintf(stderr,
0559             "expected 'broken_buf' read(2) failure, got %zi\n",
0560             res);
0561         exit(EXIT_FAILURE);
0562     }
0563 
0564     if (errno != ENOMEM) {
0565         perror("unexpected errno of 'broken_buf'");
0566         exit(EXIT_FAILURE);
0567     }
0568 
0569     /* Try to fill valid buffer. */
0570     res = read(fd, valid_buf, buf_size);
0571     if (res < 0) {
0572         perror("unexpected 'valid_buf' read(2) failure");
0573         exit(EXIT_FAILURE);
0574     }
0575 
0576     if (res != buf_size) {
0577         fprintf(stderr,
0578             "invalid 'valid_buf' read(2), expected %i, got %zi\n",
0579             buf_size, res);
0580         exit(EXIT_FAILURE);
0581     }
0582 
0583     for (i = 0; i < buf_size; i++) {
0584         if (valid_buf[i] != BUF_PATTERN_2) {
0585             fprintf(stderr,
0586                 "invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
0587                 i, BUF_PATTERN_2, valid_buf[i]);
0588             exit(EXIT_FAILURE);
0589         }
0590     }
0591 
0592     /* Unmap buffers. */
0593     munmap(broken_buf, page_size);
0594     munmap(broken_buf + page_size * 2, page_size);
0595     munmap(valid_buf, buf_size);
0596     close(fd);
0597 }
0598 
0599 static struct test_case test_cases[] = {
0600     {
0601         .name = "SOCK_STREAM connection reset",
0602         .run_client = test_stream_connection_reset,
0603     },
0604     {
0605         .name = "SOCK_STREAM bind only",
0606         .run_client = test_stream_bind_only_client,
0607         .run_server = test_stream_bind_only_server,
0608     },
0609     {
0610         .name = "SOCK_STREAM client close",
0611         .run_client = test_stream_client_close_client,
0612         .run_server = test_stream_client_close_server,
0613     },
0614     {
0615         .name = "SOCK_STREAM server close",
0616         .run_client = test_stream_server_close_client,
0617         .run_server = test_stream_server_close_server,
0618     },
0619     {
0620         .name = "SOCK_STREAM multiple connections",
0621         .run_client = test_stream_multiconn_client,
0622         .run_server = test_stream_multiconn_server,
0623     },
0624     {
0625         .name = "SOCK_STREAM MSG_PEEK",
0626         .run_client = test_stream_msg_peek_client,
0627         .run_server = test_stream_msg_peek_server,
0628     },
0629     {
0630         .name = "SOCK_SEQPACKET msg bounds",
0631         .run_client = test_seqpacket_msg_bounds_client,
0632         .run_server = test_seqpacket_msg_bounds_server,
0633     },
0634     {
0635         .name = "SOCK_SEQPACKET MSG_TRUNC flag",
0636         .run_client = test_seqpacket_msg_trunc_client,
0637         .run_server = test_seqpacket_msg_trunc_server,
0638     },
0639     {
0640         .name = "SOCK_SEQPACKET timeout",
0641         .run_client = test_seqpacket_timeout_client,
0642         .run_server = test_seqpacket_timeout_server,
0643     },
0644     {
0645         .name = "SOCK_SEQPACKET invalid receive buffer",
0646         .run_client = test_seqpacket_invalid_rec_buffer_client,
0647         .run_server = test_seqpacket_invalid_rec_buffer_server,
0648     },
0649     {},
0650 };
0651 
0652 static const char optstring[] = "";
0653 static const struct option longopts[] = {
0654     {
0655         .name = "control-host",
0656         .has_arg = required_argument,
0657         .val = 'H',
0658     },
0659     {
0660         .name = "control-port",
0661         .has_arg = required_argument,
0662         .val = 'P',
0663     },
0664     {
0665         .name = "mode",
0666         .has_arg = required_argument,
0667         .val = 'm',
0668     },
0669     {
0670         .name = "peer-cid",
0671         .has_arg = required_argument,
0672         .val = 'p',
0673     },
0674     {
0675         .name = "list",
0676         .has_arg = no_argument,
0677         .val = 'l',
0678     },
0679     {
0680         .name = "skip",
0681         .has_arg = required_argument,
0682         .val = 's',
0683     },
0684     {
0685         .name = "help",
0686         .has_arg = no_argument,
0687         .val = '?',
0688     },
0689     {},
0690 };
0691 
0692 static void usage(void)
0693 {
0694     fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
0695         "\n"
0696         "  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
0697         "  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
0698         "\n"
0699         "Run vsock.ko tests.  Must be launched in both guest\n"
0700         "and host.  One side must use --mode=client and\n"
0701         "the other side must use --mode=server.\n"
0702         "\n"
0703         "A TCP control socket connection is used to coordinate tests\n"
0704         "between the client and the server.  The server requires a\n"
0705         "listen address and the client requires an address to\n"
0706         "connect to.\n"
0707         "\n"
0708         "The CID of the other side must be given with --peer-cid=<cid>.\n"
0709         "\n"
0710         "Options:\n"
0711         "  --help                 This help message\n"
0712         "  --control-host <host>  Server IP address to connect to\n"
0713         "  --control-port <port>  Server port to listen on/connect to\n"
0714         "  --mode client|server   Server or client mode\n"
0715         "  --peer-cid <cid>       CID of the other side\n"
0716         "  --list                 List of tests that will be executed\n"
0717         "  --skip <test_id>       Test ID to skip;\n"
0718         "                         use multiple --skip options to skip more tests\n"
0719         );
0720     exit(EXIT_FAILURE);
0721 }
0722 
0723 int main(int argc, char **argv)
0724 {
0725     const char *control_host = NULL;
0726     const char *control_port = NULL;
0727     struct test_opts opts = {
0728         .mode = TEST_MODE_UNSET,
0729         .peer_cid = VMADDR_CID_ANY,
0730     };
0731 
0732     init_signals();
0733 
0734     for (;;) {
0735         int opt = getopt_long(argc, argv, optstring, longopts, NULL);
0736 
0737         if (opt == -1)
0738             break;
0739 
0740         switch (opt) {
0741         case 'H':
0742             control_host = optarg;
0743             break;
0744         case 'm':
0745             if (strcmp(optarg, "client") == 0)
0746                 opts.mode = TEST_MODE_CLIENT;
0747             else if (strcmp(optarg, "server") == 0)
0748                 opts.mode = TEST_MODE_SERVER;
0749             else {
0750                 fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
0751                 return EXIT_FAILURE;
0752             }
0753             break;
0754         case 'p':
0755             opts.peer_cid = parse_cid(optarg);
0756             break;
0757         case 'P':
0758             control_port = optarg;
0759             break;
0760         case 'l':
0761             list_tests(test_cases);
0762             break;
0763         case 's':
0764             skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
0765                   optarg);
0766             break;
0767         case '?':
0768         default:
0769             usage();
0770         }
0771     }
0772 
0773     if (!control_port)
0774         usage();
0775     if (opts.mode == TEST_MODE_UNSET)
0776         usage();
0777     if (opts.peer_cid == VMADDR_CID_ANY)
0778         usage();
0779 
0780     if (!control_host) {
0781         if (opts.mode != TEST_MODE_SERVER)
0782             usage();
0783         control_host = "0.0.0.0";
0784     }
0785 
0786     control_init(control_host, control_port,
0787              opts.mode == TEST_MODE_SERVER);
0788 
0789     run_tests(test_cases, &opts);
0790 
0791     control_cleanup();
0792     return EXIT_SUCCESS;
0793 }