Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/e2e_tests/tests/vsock.rs
5394 views
1
// Copyright 2022 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! Testing vsock.
6
7
#![cfg(any(target_os = "android", target_os = "linux"))]
8
9
use std::io::Write;
10
use std::path::Path;
11
use std::process::Command;
12
use std::process::Stdio;
13
use std::time::Duration;
14
15
use fixture::utils::retry;
16
use fixture::utils::retry_with_delay;
17
use fixture::utils::ChildExt;
18
use fixture::utils::CommandExt;
19
use fixture::vhost_user::CmdType;
20
use fixture::vhost_user::Config as VuConfig;
21
use fixture::vhost_user::VhostUserBackend;
22
use fixture::vm::Config;
23
use fixture::vm::TestVm;
24
use tempfile::tempdir;
25
use tempfile::NamedTempFile;
26
27
const ANY_CID: &str = "4294967295"; // -1U
28
const HOST_CID: u64 = 2;
29
30
const SERVER_TIMEOUT: Duration = Duration::from_secs(3);
31
const NCAT_RETRIES: usize = 15;
32
const NCAT_RETRY_DELAY: Duration = Duration::from_millis(300);
33
34
const MESSAGE_TO_HOST: &str = "Connection from the host is successfully established";
35
const MESSAGE_TO_GUEST: &str = "Connection from the guest is successfully established";
36
37
// generate a random CID to avoid conflicts with other VMs run on different processes
38
fn generate_guest_cid() -> u32 {
39
// avoid special CIDs and negative values
40
rand::random_range(3..0x8000_0000)
41
}
42
43
fn generate_vhost_port() -> u32 {
44
rand::random_range(10000..99999)
45
}
46
47
#[test]
48
fn host_to_guest() {
49
let guest_port = generate_vhost_port();
50
let guest_cid = generate_guest_cid();
51
let config = Config::new().extra_args(vec!["--cid".to_string(), guest_cid.to_string()]);
52
let mut vm = TestVm::new(config).unwrap();
53
host_to_guest_connection(&mut vm, guest_cid, guest_port);
54
}
55
56
#[test]
57
fn host_to_guest_disable_sandbox() {
58
let guest_port = generate_vhost_port();
59
let guest_cid = generate_guest_cid();
60
let config = Config::new()
61
.extra_args(vec!["--cid".to_string(), guest_cid.to_string()])
62
.disable_sandbox();
63
let mut vm = TestVm::new(config).unwrap();
64
host_to_guest_connection(&mut vm, guest_cid, guest_port);
65
}
66
67
#[test]
68
fn host_to_guest_snapshot_restore() {
69
let guest_port = generate_vhost_port();
70
let guest_cid = generate_guest_cid();
71
let config = Config::new().extra_args(vec![
72
"--cid".to_string(),
73
guest_cid.to_string(),
74
"--no-usb".to_string(),
75
]);
76
let mut vm = TestVm::new(config).unwrap();
77
host_to_guest_connection(&mut vm, guest_cid, guest_port);
78
let dir = tempdir().unwrap();
79
let snap = dir.path().join("snapshot.bkp");
80
vm.snapshot(&snap).unwrap();
81
let config = Config::new().extra_args(vec![
82
"--cid".to_string(),
83
guest_cid.to_string(),
84
"--restore".to_string(),
85
snap.to_str().unwrap().to_string(),
86
"--no-usb".to_string(),
87
]);
88
drop(vm);
89
vm = TestVm::new_restore(config).unwrap();
90
host_to_guest_connection(&mut vm, guest_cid, guest_port);
91
}
92
93
#[test]
94
fn host_to_guest_disable_sandbox_snapshot_restore() {
95
let guest_port = generate_vhost_port();
96
let guest_cid = generate_guest_cid();
97
let config = Config::new().extra_args(vec![
98
"--cid".to_string(),
99
guest_cid.to_string(),
100
"--no-usb".to_string(),
101
]);
102
let mut vm = TestVm::new(config.disable_sandbox()).unwrap();
103
host_to_guest_connection(&mut vm, guest_cid, guest_port);
104
let dir = tempdir().unwrap();
105
let snap = dir.path().join("snapshot.bkp");
106
vm.snapshot(&snap).unwrap();
107
let config = Config::new().extra_args(vec![
108
"--cid".to_string(),
109
guest_cid.to_string(),
110
"--restore".to_string(),
111
snap.to_str().unwrap().to_string(),
112
"--no-usb".to_string(),
113
]);
114
drop(vm);
115
vm = TestVm::new_restore(config.disable_sandbox()).unwrap();
116
host_to_guest_connection(&mut vm, guest_cid, guest_port);
117
}
118
119
fn host_to_guest_connection(vm: &mut TestVm, guest_cid: u32, guest_port: u32) {
120
let guest_cmd = vm
121
.exec_in_guest_async(&format!(
122
"echo {MESSAGE_TO_HOST} | ncat -v -l --vsock --send-only {ANY_CID} {guest_port}"
123
))
124
.unwrap();
125
126
let output = retry_with_delay(
127
|| {
128
// This will instantly fail if the guest isn't listening on the port yet, so we need to
129
// retry with a delay.
130
Command::new("ncat")
131
.args([
132
"-v",
133
"--recv-only",
134
"--vsock",
135
&guest_cid.to_string(),
136
&guest_port.to_string(),
137
])
138
.stderr(Stdio::inherit())
139
.log()
140
.output_checked()
141
},
142
NCAT_RETRIES,
143
NCAT_RETRY_DELAY,
144
)
145
.unwrap();
146
147
let host_stdout = std::str::from_utf8(&output.stdout).unwrap();
148
assert_eq!(host_stdout.trim(), MESSAGE_TO_HOST);
149
150
guest_cmd.wait_ok(vm).unwrap();
151
}
152
153
#[test]
154
fn guest_to_host() {
155
let host_port = generate_vhost_port();
156
let guest_cid = generate_guest_cid();
157
let config = Config::new().extra_args(vec!["--cid".to_string(), guest_cid.to_string()]);
158
let mut vm = TestVm::new(config).unwrap();
159
guest_to_host_connection(&mut vm, host_port);
160
}
161
162
#[test]
163
fn guest_to_host_disable_sandbox() {
164
let host_port = generate_vhost_port();
165
let guest_cid = generate_guest_cid();
166
let config = Config::new()
167
.extra_args(vec!["--cid".to_string(), guest_cid.to_string()])
168
.disable_sandbox();
169
let mut vm = TestVm::new(config).unwrap();
170
guest_to_host_connection(&mut vm, host_port);
171
}
172
173
#[test]
174
fn guest_to_host_snapshot_restore() {
175
let host_port = generate_vhost_port();
176
let guest_cid = generate_guest_cid();
177
let config = Config::new().extra_args(vec![
178
"--cid".to_string(),
179
guest_cid.to_string(),
180
"--no-usb".to_string(),
181
]);
182
let mut vm = TestVm::new(config).unwrap();
183
guest_to_host_connection(&mut vm, host_port);
184
let dir = tempdir().unwrap();
185
let snap = dir.path().join("snapshot.bkp");
186
vm.snapshot(&snap).unwrap();
187
let config = Config::new().extra_args(vec![
188
"--cid".to_string(),
189
guest_cid.to_string(),
190
"--no-usb".to_string(),
191
"--restore".to_string(),
192
snap.to_str().unwrap().to_string(),
193
]);
194
drop(vm);
195
vm = TestVm::new_restore(config).unwrap();
196
guest_to_host_connection(&mut vm, host_port);
197
}
198
199
#[test]
200
fn guest_to_host_disable_sandbox_snapshot_restore() {
201
let host_port = generate_vhost_port();
202
let guest_cid = generate_guest_cid();
203
let config = Config::new()
204
.extra_args(vec![
205
"--cid".to_string(),
206
guest_cid.to_string(),
207
"--no-usb".to_string(),
208
])
209
.disable_sandbox();
210
let mut vm = TestVm::new(config).unwrap();
211
guest_to_host_connection(&mut vm, host_port);
212
let dir = tempdir().unwrap();
213
let snap = dir.path().join("snapshot.bkp");
214
vm.snapshot(&snap).unwrap();
215
let config = Config::new().extra_args(vec![
216
"--cid".to_string(),
217
guest_cid.to_string(),
218
"--no-usb".to_string(),
219
"--restore".to_string(),
220
snap.to_str().unwrap().to_string(),
221
]);
222
drop(vm);
223
vm = TestVm::new_restore(config.disable_sandbox()).unwrap();
224
guest_to_host_connection(&mut vm, host_port);
225
}
226
227
fn guest_to_host_connection(vm: &mut TestVm, host_port: u32) {
228
let mut host_ncat = Command::new("ncat")
229
.arg("-l")
230
.arg("--send-only")
231
.args(["--vsock", ANY_CID, &host_port.to_string()])
232
.stdin(Stdio::piped())
233
.log()
234
.spawn()
235
.expect("failed to execute process");
236
237
host_ncat
238
.stdin
239
.take()
240
.unwrap()
241
.write_all(MESSAGE_TO_GUEST.as_bytes())
242
.unwrap();
243
244
let cmd = format!("ncat --recv-only --vsock {HOST_CID} {host_port}; echo ''");
245
let guest_stdout = retry(|| vm.exec_in_guest(&cmd), NCAT_RETRIES).unwrap();
246
assert_eq!(guest_stdout.stdout.trim(), MESSAGE_TO_GUEST);
247
248
host_ncat.wait_with_timeout(SERVER_TIMEOUT).unwrap();
249
}
250
251
fn create_vu_config(cmd_type: CmdType, socket: &Path, cid: u32) -> VuConfig {
252
let socket_path = socket.to_str().unwrap();
253
println!("cid={cid}, socket={socket_path}");
254
match cmd_type {
255
CmdType::Device => VuConfig::new(cmd_type, "vsock").extra_args(vec![
256
"vsock".to_string(),
257
"--socket-path".to_string(),
258
socket_path.to_string(),
259
"--cid".to_string(),
260
cid.to_string(),
261
]),
262
CmdType::Devices => VuConfig::new(cmd_type, "vsock").extra_args(vec![
263
"--vsock".to_string(),
264
format!("vhost={},cid={}", socket_path, cid),
265
]),
266
}
267
}
268
269
#[test]
270
fn vhost_user_host_to_guest() {
271
let guest_port = generate_vhost_port();
272
let guest_cid = generate_guest_cid();
273
let socket = NamedTempFile::new().unwrap();
274
275
let vu_config = create_vu_config(CmdType::Device, socket.path(), guest_cid);
276
let _vu_device = VhostUserBackend::new(vu_config).unwrap();
277
278
let config = Config::new().extra_args(vec![
279
"--vhost-user".to_string(),
280
format!("vsock,socket={}", socket.path().to_str().unwrap()),
281
]);
282
283
let mut vm = TestVm::new(config).unwrap();
284
host_to_guest_connection(&mut vm, guest_cid, guest_port);
285
}
286
287
#[test]
288
fn vhost_user_host_to_guest_with_devices() {
289
let guest_port = generate_vhost_port();
290
let guest_cid = generate_guest_cid();
291
let socket = NamedTempFile::new().unwrap();
292
293
let vu_config = create_vu_config(CmdType::Devices, socket.path(), guest_cid);
294
let _vu_device = VhostUserBackend::new(vu_config).unwrap();
295
296
let config = Config::new().extra_args(vec![
297
"--vhost-user".to_string(),
298
format!("vsock,socket={}", socket.path().to_str().unwrap()),
299
]);
300
301
let mut vm = TestVm::new(config).unwrap();
302
host_to_guest_connection(&mut vm, guest_cid, guest_port);
303
}
304
305
#[test]
306
fn vhost_user_guest_to_host() {
307
let host_port = generate_vhost_port();
308
let guest_cid = generate_guest_cid();
309
let socket = NamedTempFile::new().unwrap();
310
311
let vu_config = create_vu_config(CmdType::Device, socket.path(), guest_cid);
312
let _vu_device = VhostUserBackend::new(vu_config).unwrap();
313
314
let config = Config::new().extra_args(vec![
315
"--vhost-user".to_string(),
316
format!("vsock,socket={}", socket.path().to_str().unwrap()),
317
]);
318
319
let mut vm = TestVm::new(config).unwrap();
320
guest_to_host_connection(&mut vm, host_port);
321
}
322
323
#[test]
324
fn vhost_user_guest_to_host_with_devices() {
325
let host_port = generate_vhost_port();
326
let guest_cid = generate_guest_cid();
327
let socket = NamedTempFile::new().unwrap();
328
329
let vu_config = create_vu_config(CmdType::Devices, socket.path(), guest_cid);
330
let _vu_device = VhostUserBackend::new(vu_config).unwrap();
331
332
let config = Config::new().extra_args(vec![
333
"--vhost-user".to_string(),
334
format!("vsock,socket={}", socket.path().to_str().unwrap()),
335
]);
336
337
let mut vm = TestVm::new(config).unwrap();
338
guest_to_host_connection(&mut vm, host_port);
339
}
340
341