Skip to content

Commit 7486f35

Browse files
committed
devices/vsock: integration test
Added a vsock integration test, along with a new testing tool (tests/host_tools/vsock_helper.c). Signed-off-by: Dan Horobeanu <[email protected]>
1 parent bb63011 commit 7486f35

File tree

3 files changed

+524
-0
lines changed

3 files changed

+524
-0
lines changed

tests/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,15 @@ def aux_bin_paths(test_session_root_path):
230230
cloner_bin_path
231231
)
232232

233+
vsock_helper_bin_path = os.path.join(
234+
test_session_root_path,
235+
'vsock_helper'
236+
)
237+
_gcc_compile(
238+
'host_tools/vsock_helper.c',
239+
vsock_helper_bin_path
240+
)
241+
233242
seccomp_build_path = os.path.join(
234243
test_session_root_path,
235244
build_tools.CARGO_RELEASE_REL_PATH
@@ -274,6 +283,7 @@ def aux_bin_paths(test_session_root_path):
274283

275284
yield {
276285
'cloner': cloner_bin_path,
286+
'vsock_helper': vsock_helper_bin_path,
277287
'demo_basic_jailer': demo_basic_jailer,
278288
'demo_advanced_jailer': demo_advanced_jailer,
279289
'demo_harmless': demo_harmless,

tests/host_tools/vsock_helper.c

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// This is a vsock helper tool, used by the Firecracker integration tests,
5+
// to - well - test the virtio vsock device. It can be used to:
6+
// 1. Run a forking echo server, that echoes back any data received from
7+
// a client; and
8+
// 2. Run a vsock echo client, that reads data from STDIN, sends it to an
9+
// echo server, then forwards the server's reply to STDOUT.
10+
11+
#include <sys/socket.h>
12+
#include <sys/types.h>
13+
#include <sys/select.h>
14+
#include <sys/wait.h>
15+
#include <linux/vm_sockets.h>
16+
#include <stdio.h>
17+
#include <stdlib.h>
18+
#include <stdint.h>
19+
#include <string.h>
20+
#include <unistd.h>
21+
#include <stdio.h>
22+
#include <errno.h>
23+
24+
25+
#define BUF_SIZE (16 * 1024)
26+
#define SERVER_ACCEPT_BACKLOG 128
27+
28+
29+
int print_usage() {
30+
fprintf(stderr, "Usage: ./vsock-helper {echosrv [-d] <port> | echo <cid> <port>}\n");
31+
fprintf(stderr, "\n");
32+
fprintf(stderr, " echosrv start a vsock echo server. The server will accept\n");
33+
fprintf(stderr, " any incoming connection, and echo back any data\n");
34+
fprintf(stderr, " received on it.\n");
35+
fprintf(stderr, " -d can be used to daemonize the server.\n");
36+
fprintf(stderr, "\n");
37+
fprintf(stderr, " echo connect to an echo server, listening on CID:port.\n");
38+
fprintf(stderr, " STDIN will be piped through to the echo server, and\n");
39+
fprintf(stderr, " data coming from the server will pe sent to STDOUT.\n");
40+
fprintf(stderr, "\n");
41+
return -1;
42+
}
43+
44+
int xfer(int src_fd, int dst_fd) {
45+
char buf[BUF_SIZE];
46+
int count = read(src_fd, buf, sizeof(buf));
47+
48+
if (!count) return 0;
49+
if (count < 0) return -1;
50+
51+
int offset = 0;
52+
do {
53+
int written;
54+
written = write(dst_fd, &buf[offset], count - offset);
55+
if (written <= 0) return -1;
56+
offset += written;
57+
} while (offset < count);
58+
59+
return offset;
60+
}
61+
62+
63+
int run_echosrv(uint32_t port) {
64+
65+
struct sockaddr_vm vsock_addr = {
66+
.svm_family = AF_VSOCK,
67+
.svm_port = port,
68+
.svm_cid = VMADDR_CID_ANY
69+
};
70+
71+
int srv_sock = socket(AF_VSOCK, SOCK_STREAM, 0);
72+
if (srv_sock < 0) {
73+
perror("socket()");
74+
return -1;
75+
}
76+
77+
int res = bind(srv_sock, (struct sockaddr*)&vsock_addr, sizeof(struct sockaddr_vm));
78+
if (res) {
79+
perror("bind()");
80+
return -1;
81+
}
82+
83+
res = listen(srv_sock, SERVER_ACCEPT_BACKLOG);
84+
if (res) {
85+
perror("listen()");
86+
return -1;
87+
}
88+
89+
for (;;) {
90+
struct sockaddr cl_addr;
91+
socklen_t sockaddr_len = sizeof(cl_addr);
92+
int cl_sock = accept(srv_sock, &cl_addr, &sockaddr_len);
93+
if (cl_sock < 0) {
94+
perror("accept()");
95+
continue;
96+
}
97+
98+
int pid = fork();
99+
if (pid < 0) {
100+
perror("fork()");
101+
close(cl_sock);
102+
continue;
103+
}
104+
105+
if (!pid) {
106+
int res;
107+
do {
108+
res = xfer(cl_sock, cl_sock);
109+
} while (res > 0);
110+
return res >= 0 ? 0 : -1;
111+
}
112+
113+
close(cl_sock);
114+
int cstatus;
115+
waitpid(-1, &cstatus, WNOHANG);
116+
printf("New client forked...\n");
117+
}
118+
119+
return 0;
120+
}
121+
122+
123+
int run_echo(uint32_t cid, uint32_t port) {
124+
125+
int sock = socket(AF_VSOCK, SOCK_STREAM, 0);
126+
if (sock < 0) {
127+
perror("socket()");
128+
return -1;
129+
}
130+
131+
struct sockaddr_vm vsock_addr = {
132+
.svm_family = AF_VSOCK,
133+
.svm_port = port,
134+
.svm_cid = cid
135+
};
136+
if (connect(sock, (struct sockaddr*)&vsock_addr, sizeof(vsock_addr)) < 0) {
137+
perror("connect()");
138+
return -1;
139+
}
140+
141+
for (;;) {
142+
int ping_cnt = xfer(STDIN_FILENO, sock);
143+
if (!ping_cnt) break;
144+
if (ping_cnt < 0) return -1;
145+
146+
int pong_cnt = 0;
147+
while (pong_cnt < ping_cnt) {
148+
int res = xfer(sock, STDOUT_FILENO);
149+
if (res <= 0) return -1;
150+
pong_cnt += res;
151+
}
152+
}
153+
154+
return 0;
155+
}
156+
157+
158+
int main(int argc, char **argv) {
159+
160+
if (argc < 3) {
161+
return print_usage();
162+
}
163+
164+
if (strcmp(argv[1], "echosrv") == 0) {
165+
uint32_t port;
166+
if (strcmp(argv[2], "-d") == 0) {
167+
if (argc < 4) {
168+
return print_usage();
169+
}
170+
port = atoi(argv[3]);
171+
if (!port) {
172+
return print_usage();
173+
}
174+
int pid = fork();
175+
if (pid < 0) return -1;
176+
if (pid) {
177+
printf("Forked vsock echo daemon listening on port %d\n", port);
178+
return 0;
179+
}
180+
setsid();
181+
close(STDIN_FILENO);
182+
close(STDOUT_FILENO);
183+
}
184+
else {
185+
port = atoi(argv[2]);
186+
if (!port) {
187+
return print_usage();
188+
}
189+
}
190+
return run_echosrv(port);
191+
}
192+
193+
if (strcmp(argv[1], "echo") == 0) {
194+
if (argc != 4) {
195+
return print_usage();
196+
}
197+
uint32_t cid = atoi(argv[2]);
198+
uint32_t port = atoi(argv[3]);
199+
if (!cid || !port) {
200+
return print_usage();
201+
}
202+
return run_echo(cid, port);
203+
}
204+
205+
return print_usage();
206+
}

0 commit comments

Comments
 (0)