Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
fork
Configure Feed
Select the types of activity you want to include in your feed.
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
18#include "timeout.h"
19#include "control.h"
20#include "util.h"
21
22static void test_stream_connection_reset(const struct test_opts *opts)
23{
24 union {
25 struct sockaddr sa;
26 struct sockaddr_vm svm;
27 } addr = {
28 .svm = {
29 .svm_family = AF_VSOCK,
30 .svm_port = 1234,
31 .svm_cid = opts->peer_cid,
32 },
33 };
34 int ret;
35 int fd;
36
37 fd = socket(AF_VSOCK, SOCK_STREAM, 0);
38
39 timeout_begin(TIMEOUT);
40 do {
41 ret = connect(fd, &addr.sa, sizeof(addr.svm));
42 timeout_check("connect");
43 } while (ret < 0 && errno == EINTR);
44 timeout_end();
45
46 if (ret != -1) {
47 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
48 exit(EXIT_FAILURE);
49 }
50 if (errno != ECONNRESET) {
51 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
52 exit(EXIT_FAILURE);
53 }
54
55 close(fd);
56}
57
58static void test_stream_client_close_client(const struct test_opts *opts)
59{
60 int fd;
61
62 fd = vsock_stream_connect(opts->peer_cid, 1234);
63 if (fd < 0) {
64 perror("connect");
65 exit(EXIT_FAILURE);
66 }
67
68 send_byte(fd, 1, 0);
69 close(fd);
70}
71
72static void test_stream_client_close_server(const struct test_opts *opts)
73{
74 int fd;
75
76 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
77 if (fd < 0) {
78 perror("accept");
79 exit(EXIT_FAILURE);
80 }
81
82 /* Wait for the remote to close the connection, before check
83 * -EPIPE error on send.
84 */
85 vsock_wait_remote_close(fd);
86
87 send_byte(fd, -EPIPE, 0);
88 recv_byte(fd, 1, 0);
89 recv_byte(fd, 0, 0);
90 close(fd);
91}
92
93static void test_stream_server_close_client(const struct test_opts *opts)
94{
95 int fd;
96
97 fd = vsock_stream_connect(opts->peer_cid, 1234);
98 if (fd < 0) {
99 perror("connect");
100 exit(EXIT_FAILURE);
101 }
102
103 /* Wait for the remote to close the connection, before check
104 * -EPIPE error on send.
105 */
106 vsock_wait_remote_close(fd);
107
108 send_byte(fd, -EPIPE, 0);
109 recv_byte(fd, 1, 0);
110 recv_byte(fd, 0, 0);
111 close(fd);
112}
113
114static void test_stream_server_close_server(const struct test_opts *opts)
115{
116 int fd;
117
118 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
119 if (fd < 0) {
120 perror("accept");
121 exit(EXIT_FAILURE);
122 }
123
124 send_byte(fd, 1, 0);
125 close(fd);
126}
127
128/* With the standard socket sizes, VMCI is able to support about 100
129 * concurrent stream connections.
130 */
131#define MULTICONN_NFDS 100
132
133static void test_stream_multiconn_client(const struct test_opts *opts)
134{
135 int fds[MULTICONN_NFDS];
136 int i;
137
138 for (i = 0; i < MULTICONN_NFDS; i++) {
139 fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
140 if (fds[i] < 0) {
141 perror("connect");
142 exit(EXIT_FAILURE);
143 }
144 }
145
146 for (i = 0; i < MULTICONN_NFDS; i++) {
147 if (i % 2)
148 recv_byte(fds[i], 1, 0);
149 else
150 send_byte(fds[i], 1, 0);
151 }
152
153 for (i = 0; i < MULTICONN_NFDS; i++)
154 close(fds[i]);
155}
156
157static void test_stream_multiconn_server(const struct test_opts *opts)
158{
159 int fds[MULTICONN_NFDS];
160 int i;
161
162 for (i = 0; i < MULTICONN_NFDS; i++) {
163 fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
164 if (fds[i] < 0) {
165 perror("accept");
166 exit(EXIT_FAILURE);
167 }
168 }
169
170 for (i = 0; i < MULTICONN_NFDS; i++) {
171 if (i % 2)
172 send_byte(fds[i], 1, 0);
173 else
174 recv_byte(fds[i], 1, 0);
175 }
176
177 for (i = 0; i < MULTICONN_NFDS; i++)
178 close(fds[i]);
179}
180
181static void test_stream_msg_peek_client(const struct test_opts *opts)
182{
183 int fd;
184
185 fd = vsock_stream_connect(opts->peer_cid, 1234);
186 if (fd < 0) {
187 perror("connect");
188 exit(EXIT_FAILURE);
189 }
190
191 send_byte(fd, 1, 0);
192 close(fd);
193}
194
195static void test_stream_msg_peek_server(const struct test_opts *opts)
196{
197 int fd;
198
199 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
200 if (fd < 0) {
201 perror("accept");
202 exit(EXIT_FAILURE);
203 }
204
205 recv_byte(fd, 1, MSG_PEEK);
206 recv_byte(fd, 1, 0);
207 close(fd);
208}
209
210static struct test_case test_cases[] = {
211 {
212 .name = "SOCK_STREAM connection reset",
213 .run_client = test_stream_connection_reset,
214 },
215 {
216 .name = "SOCK_STREAM client close",
217 .run_client = test_stream_client_close_client,
218 .run_server = test_stream_client_close_server,
219 },
220 {
221 .name = "SOCK_STREAM server close",
222 .run_client = test_stream_server_close_client,
223 .run_server = test_stream_server_close_server,
224 },
225 {
226 .name = "SOCK_STREAM multiple connections",
227 .run_client = test_stream_multiconn_client,
228 .run_server = test_stream_multiconn_server,
229 },
230 {
231 .name = "SOCK_STREAM MSG_PEEK",
232 .run_client = test_stream_msg_peek_client,
233 .run_server = test_stream_msg_peek_server,
234 },
235 {},
236};
237
238static const char optstring[] = "";
239static const struct option longopts[] = {
240 {
241 .name = "control-host",
242 .has_arg = required_argument,
243 .val = 'H',
244 },
245 {
246 .name = "control-port",
247 .has_arg = required_argument,
248 .val = 'P',
249 },
250 {
251 .name = "mode",
252 .has_arg = required_argument,
253 .val = 'm',
254 },
255 {
256 .name = "peer-cid",
257 .has_arg = required_argument,
258 .val = 'p',
259 },
260 {
261 .name = "list",
262 .has_arg = no_argument,
263 .val = 'l',
264 },
265 {
266 .name = "skip",
267 .has_arg = required_argument,
268 .val = 's',
269 },
270 {
271 .name = "help",
272 .has_arg = no_argument,
273 .val = '?',
274 },
275 {},
276};
277
278static void usage(void)
279{
280 fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
281 "\n"
282 " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
283 " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
284 "\n"
285 "Run vsock.ko tests. Must be launched in both guest\n"
286 "and host. One side must use --mode=client and\n"
287 "the other side must use --mode=server.\n"
288 "\n"
289 "A TCP control socket connection is used to coordinate tests\n"
290 "between the client and the server. The server requires a\n"
291 "listen address and the client requires an address to\n"
292 "connect to.\n"
293 "\n"
294 "The CID of the other side must be given with --peer-cid=<cid>.\n"
295 "\n"
296 "Options:\n"
297 " --help This help message\n"
298 " --control-host <host> Server IP address to connect to\n"
299 " --control-port <port> Server port to listen on/connect to\n"
300 " --mode client|server Server or client mode\n"
301 " --peer-cid <cid> CID of the other side\n"
302 " --list List of tests that will be executed\n"
303 " --skip <test_id> Test ID to skip;\n"
304 " use multiple --skip options to skip more tests\n"
305 );
306 exit(EXIT_FAILURE);
307}
308
309int main(int argc, char **argv)
310{
311 const char *control_host = NULL;
312 const char *control_port = NULL;
313 struct test_opts opts = {
314 .mode = TEST_MODE_UNSET,
315 .peer_cid = VMADDR_CID_ANY,
316 };
317
318 init_signals();
319
320 for (;;) {
321 int opt = getopt_long(argc, argv, optstring, longopts, NULL);
322
323 if (opt == -1)
324 break;
325
326 switch (opt) {
327 case 'H':
328 control_host = optarg;
329 break;
330 case 'm':
331 if (strcmp(optarg, "client") == 0)
332 opts.mode = TEST_MODE_CLIENT;
333 else if (strcmp(optarg, "server") == 0)
334 opts.mode = TEST_MODE_SERVER;
335 else {
336 fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
337 return EXIT_FAILURE;
338 }
339 break;
340 case 'p':
341 opts.peer_cid = parse_cid(optarg);
342 break;
343 case 'P':
344 control_port = optarg;
345 break;
346 case 'l':
347 list_tests(test_cases);
348 break;
349 case 's':
350 skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
351 optarg);
352 break;
353 case '?':
354 default:
355 usage();
356 }
357 }
358
359 if (!control_port)
360 usage();
361 if (opts.mode == TEST_MODE_UNSET)
362 usage();
363 if (opts.peer_cid == VMADDR_CID_ANY)
364 usage();
365
366 if (!control_host) {
367 if (opts.mode != TEST_MODE_SERVER)
368 usage();
369 control_host = "0.0.0.0";
370 }
371
372 control_init(control_host, control_port,
373 opts.mode == TEST_MODE_SERVER);
374
375 run_tests(test_cases, &opts);
376
377 control_cleanup();
378 return EXIT_SUCCESS;
379}