Skip to content

Commit 831ed1c

Browse files
committed
kernel/vsock: add in-svsm tests for VsockStream
Add a test that performs some basic checks on vsock functionalities: - double connection - recv a buffer from the host - send a buffer to the host - recv a buffer after local shutdown - send a buffer after local shutdown The vsock server is created on the host using ncat. Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
1 parent f68932d commit 831ed1c

File tree

4 files changed

+149
-4
lines changed

4 files changed

+149
-4
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ SVSM_ARGS += --features ${FEATURES}
44
XBUILD_ARGS += -f ${FEATURES}
55
endif
66

7-
FEATURES_TEST ?= vtpm,virtio-drivers,block
7+
FEATURES_TEST ?= vtpm,virtio-drivers,block,vsock
88
SVSM_ARGS_TEST += --no-default-features
99
ifneq ($(FEATURES_TEST),)
1010
SVSM_ARGS_TEST += --features ${FEATURES_TEST}

kernel/src/testing.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub enum IORequest {
4242
GetLaunchMeasurement = 0x01,
4343
/// Virtio-blk tests: Get Sha256 hash of the svsm state disk image
4444
GetStateImageSha256 = 0x02,
45+
/// Virtio-vsock tests: Ask host to start a vsock server
46+
StartVsockServer = 0x03,
4547
}
4648

4749
/// Return the serial port to communicate with the host for a given request

kernel/src/vsock/stream.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,127 @@ impl Drop for VsockStream {
175175
let _ = VSOCK_DEVICE.shutdown(self.remote_cid, self.local_port, self.remote_port, true);
176176
}
177177
}
178+
179+
#[cfg(all(test, test_in_svsm))]
180+
mod tests {
181+
use crate::{testutils::has_test_iorequests, vsock::VMADDR_CID_HOST};
182+
use zerocopy::IntoBytes;
183+
184+
use super::*;
185+
186+
fn start_vsock_server_host() -> u32 {
187+
use crate::serial::Terminal;
188+
use crate::testing::{IORequest, svsm_test_io};
189+
190+
let mut sp = svsm_test_io().unwrap();
191+
192+
sp.put_byte(IORequest::StartVsockServer as u8);
193+
194+
let mut vsock_port: u32 = 0;
195+
196+
sp.read(vsock_port.as_mut_bytes())
197+
.expect("unable to get the vsock port");
198+
199+
vsock_port
200+
}
201+
202+
#[test]
203+
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
204+
fn test_virtio_vsock_double_connect() {
205+
if !has_test_iorequests() {
206+
return;
207+
}
208+
209+
let remote_port = start_vsock_server_host();
210+
211+
let mut stream =
212+
VsockStream::connect(remote_port, VMADDR_CID_HOST).expect("connection failed");
213+
214+
VsockStream::connect(remote_port, VMADDR_CID_HOST)
215+
.expect_err("The second connection operation was expected to fail, but it succeeded.");
216+
217+
stream.shutdown().expect("shutdown failed");
218+
}
219+
220+
#[test]
221+
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
222+
fn test_virtio_vsock_write() {
223+
if !has_test_iorequests() {
224+
return;
225+
}
226+
227+
let remote_port = start_vsock_server_host();
228+
229+
let mut stream =
230+
VsockStream::connect(remote_port, VMADDR_CID_HOST).expect("connection failed");
231+
232+
let buffer: &[u8] = b"Hello world!";
233+
234+
let n_bytes = stream.write(buffer).expect("write failed");
235+
assert_eq!(n_bytes, buffer.len(), "Sent less bytes than requested");
236+
237+
stream.shutdown().expect("shutdown failed");
238+
}
239+
240+
#[test]
241+
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
242+
fn test_virtio_vsock_read() {
243+
if !has_test_iorequests() {
244+
return;
245+
}
246+
247+
let remote_port = start_vsock_server_host();
248+
249+
let mut stream =
250+
VsockStream::connect(remote_port, VMADDR_CID_HOST).expect("connection failed");
251+
252+
let mut buffer: [u8; 11] = [0; 11];
253+
let n_bytes = stream.read(&mut buffer).expect("read failed");
254+
assert_eq!(n_bytes, buffer.len(), "Received less bytes than requested");
255+
256+
let string = core::str::from_utf8(&buffer).unwrap();
257+
log::info!("received: {string:?}");
258+
assert_eq!(string, "hello_world", "Received wrong message");
259+
260+
stream.shutdown().expect("shutdown failed");
261+
}
262+
263+
#[test]
264+
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
265+
fn test_virtio_vsock_read_shutdown() {
266+
if !has_test_iorequests() {
267+
return;
268+
}
269+
270+
let remote_port = start_vsock_server_host();
271+
272+
let mut stream =
273+
VsockStream::connect(remote_port, VMADDR_CID_HOST).expect("connection failed");
274+
275+
stream.shutdown().expect("shutdown failed");
276+
277+
let mut buffer: [u8; 11] = [0; 11];
278+
stream
279+
.read(&mut buffer)
280+
.expect_err("The read operation was expected to fail, but it succeeded");
281+
}
282+
283+
#[test]
284+
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
285+
fn test_virtio_vsock_write_shutdown() {
286+
if !has_test_iorequests() {
287+
return;
288+
}
289+
290+
let remote_port = start_vsock_server_host();
291+
292+
let mut stream =
293+
VsockStream::connect(remote_port, VMADDR_CID_HOST).expect("connection failed");
294+
295+
stream.shutdown().expect("shutdown failed");
296+
297+
stream
298+
.write(b"hello world")
299+
.expect_err("The write operation was expected to fail, but it succeeded");
300+
}
301+
}

scripts/test-in-svsm.sh

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
set -e
99

1010
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
11+
VSOCK_PORT=12345
12+
VSOCK_CID=10
1113

1214
test_io(){
1315
PIPE_IN=$1
@@ -28,6 +30,13 @@ test_io(){
2830
"02")
2931
sha256sum "$TEST_DIR/svsm_state.raw" | cut -f 1 -d ' ' | xxd -p -r > "$PIPE_IN"
3032
;;
33+
"03")
34+
# virtio-vsock in svsm does not handle half duplex connections.
35+
echo -n "hello_world" | ncat --no-shutdown -l --vsock -p $VSOCK_PORT &
36+
sleep 1
37+
# write port number as an unsigned int and not as ascii
38+
python3 -c "import sys,struct; sys.stdout.buffer.write(struct.pack('I', $VSOCK_PORT))" > $PIPE_IN
39+
;;
3140
"")
3241
# skip EOF
3342
;;
@@ -44,9 +53,6 @@ mkfifo $TEST_DIR/pipe.out
4453
# Create a raw disk image (512kB in size) for virtio-blk tests containing random data
4554
dd if=/dev/urandom of="$TEST_DIR/svsm_state.raw" bs=512 count=1024
4655

47-
test_io $TEST_DIR/pipe.in $TEST_DIR/pipe.out &
48-
TEST_IO_PID=$!
49-
5056
LAUNCH_GUEST_ARGS=""
5157

5258
while [[ $# -gt 0 ]]; do
@@ -55,6 +61,16 @@ while [[ $# -gt 0 ]]; do
5561
LAUNCH_GUEST_ARGS+="--nocc "
5662
shift
5763
;;
64+
--vsock-cid)
65+
VSOCK_CID="$2"
66+
shift
67+
shift
68+
;;
69+
--vsock-port)
70+
VSOCK_PORT="$2"
71+
shift
72+
shift
73+
;;
5874
--)
5975
shift
6076
break
@@ -66,9 +82,12 @@ while [[ $# -gt 0 ]]; do
6682
esac
6783
done
6884

85+
test_io $TEST_DIR/pipe.in $TEST_DIR/pipe.out &
86+
TEST_IO_PID=$!
6987

7088
$SCRIPT_DIR/launch_guest.sh --igvm $SCRIPT_DIR/../bin/coconut-test-qemu.igvm \
7189
--state "$TEST_DIR/svsm_state.raw" \
90+
--vsock "$VSOCK_CID" \
7291
--unit-tests $TEST_DIR/pipe \
7392
$LAUNCH_GUEST_ARGS "$@" || svsm_exit_code=$?
7493

0 commit comments

Comments
 (0)