diff --git a/tests/ci-test-iter/host-companions/vsock-client-send/Cargo.lock b/tests/ci-test-iter/host-companions/vsock-client-send/Cargo.lock new file mode 100644 index 00000000..75c765fe --- /dev/null +++ b/tests/ci-test-iter/host-companions/vsock-client-send/Cargo.lock @@ -0,0 +1,79 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "vsock" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2da6e4ac76cd19635dce0f98985378bb62f8044ee2ff80abd2a7334b920ed63" +dependencies = [ + "libc", + "nix", +] + +[[package]] +name = "vsock-client-send" +version = "0.1.0" +dependencies = [ + "anyhow", + "vsock", +] diff --git a/tests/ci-test-iter/host-companions/vsock-client-send/Cargo.toml b/tests/ci-test-iter/host-companions/vsock-client-send/Cargo.toml new file mode 100644 index 00000000..45426327 --- /dev/null +++ b/tests/ci-test-iter/host-companions/vsock-client-send/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "vsock-client-send" +version = "0.1.0" +edition = "2021" + +# Exclude from parent workspace +[workspace] + +[dependencies] +vsock = "0.5" +anyhow = "1.0" + diff --git a/tests/ci-test-iter/host-companions/vsock-client-send/src/main.rs b/tests/ci-test-iter/host-companions/vsock-client-send/src/main.rs new file mode 100644 index 00000000..99bcf0ed --- /dev/null +++ b/tests/ci-test-iter/host-companions/vsock-client-send/src/main.rs @@ -0,0 +1,71 @@ +// vsock client for sending data stress tests +// Connects to StarryOS guest VM, then sends test data +// about stress: +// - data size increased to 100MB +// - verify data integrity by checking sent/received byte counts +// - check if there are any exceptions in the continuous transmission of data, +// as the old problem was that it stalled after a single transmission of 1K + +use anyhow::{Context, Result}; +use std::io::{Read, Write}; +use std::time::Duration; +use vsock::{VsockAddr, VsockStream}; + +const GUEST_CID: u32 = 103; // QEMU guest CID configured in starry_vm_runner.py +const GUEST_PORT: u32 = 1234; // Port where guest test is listening +const MAX_RETRIES: u32 = 30; // Maximum connection retries +const RETRY_DELAY_MS: u64 = 1000; // Delay between retries (1 second) +const DATA_SIZE: usize = 10 * 1024 * 1024; // 100MB + +// A pseudo-random generator with specified random seeds +fn generate_sequence(size: usize) -> Vec { + let mut data = Vec::with_capacity(size); + let mut seed: u32 = 42; + for _ in 0..size { + seed = seed.wrapping_mul(1103515245).wrapping_add(12345); + let byte = ((seed >> 16) & 0xFF) as u8; + data.push(byte); + } + data +} + +fn main() -> Result<()> { + // Prepare data + let data_to_send = generate_sequence(DATA_SIZE); + + // Retry loop for connecting to guest + let mut stream = None; + for attempt in 1..=MAX_RETRIES { + match VsockStream::connect(&VsockAddr::new(GUEST_CID, GUEST_PORT)) { + Ok(s) => { + println!("VSOCK-HOST: Connected successfully!"); + stream = Some(s); + break; + } + Err(e) => { + std::thread::sleep(Duration::from_millis(RETRY_DELAY_MS)); + } + } + } + let mut stream = stream.context("Failed to connect to guest after multiple retries")?; + + // send data + let mut sent_count = 0; + let chunk_size = 1024; + while sent_count < DATA_SIZE { + let end = std::cmp::min(sent_count + chunk_size, DATA_SIZE); + let chunk = &data_to_send[sent_count..end]; + let n = stream.write(chunk).expect("VSOCK-HOST: write failed"); + sent_count += n; + } + + // flush + stream.flush().unwrap(); + println!("VSOCK-HOST: Data transmission complete ({} bytes)", sent_count); + + // wait for receiving end to verify + std::thread::sleep(std::time::Duration::from_secs(2)); + + println!("VSOCK-HOST: Test Finished Successfully."); + Ok(()) +} diff --git a/tests/stress/cases/vsock_recv/.gitignore b/tests/stress/cases/vsock_recv/.gitignore new file mode 100644 index 00000000..a6de038d --- /dev/null +++ b/tests/stress/cases/vsock_recv/.gitignore @@ -0,0 +1,3 @@ +/target/ +/artifacts/ + diff --git a/tests/stress/cases/vsock_recv/Cargo.lock b/tests/stress/cases/vsock_recv/Cargo.lock new file mode 100644 index 00000000..affebc3f --- /dev/null +++ b/tests/stress/cases/vsock_recv/Cargo.lock @@ -0,0 +1,247 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "vsock" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2da6e4ac76cd19635dce0f98985378bb62f8044ee2ff80abd2a7334b920ed63" +dependencies = [ + "libc", + "nix", +] + +[[package]] +name = "vsock_recv" +version = "0.1.0" +dependencies = [ + "rand", + "serde", + "serde_json", + "vsock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" diff --git a/tests/stress/cases/vsock_recv/Cargo.toml b/tests/stress/cases/vsock_recv/Cargo.toml new file mode 100644 index 00000000..d4dce4d4 --- /dev/null +++ b/tests/stress/cases/vsock_recv/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "vsock_recv" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" +rand = "0.8" +vsock = "0.5" + +[workspace] + diff --git a/tests/stress/cases/vsock_recv/src/main.rs b/tests/stress/cases/vsock_recv/src/main.rs new file mode 100644 index 00000000..c0f618eb --- /dev/null +++ b/tests/stress/cases/vsock_recv/src/main.rs @@ -0,0 +1,67 @@ +use serde::Serialize; +use std::io::{Write, Read}; +use vsock::{VsockAddr, VsockListener, VMADDR_CID_ANY}; + +const DATA_SIZE: usize = 10 * 1024 * 1024; // 100MB +const PORT: u32 = 1234; + +#[derive(Serialize)] +struct TestResult { + status: &'static str, +} + +// A pseudo-random generator with specified random seeds +fn generate_sequence(size: usize) -> Vec { + let mut data = Vec::with_capacity(size); + let mut seed: u32 = 42; + for _ in 0..size { + seed = seed.wrapping_mul(1103515245).wrapping_add(12345); + let byte = ((seed >> 16) & 0xFF) as u8; + data.push(byte); + } + data +} + +fn main() { + // Prepare data + let data_to_send = generate_sequence(DATA_SIZE); + + // wait for connection + let addr = VsockAddr::new(VMADDR_CID_ANY, PORT); + let listener = VsockListener::bind(&addr).expect("VSOCK-GUEST: Failed to bind to vsock"); + let (mut stream, client_addr) = listener.accept().expect("VSOCK-GUEST: accept failed"); + println!("VSOCK-GUEST: Accepted connection from CID:{}", client_addr.cid()); + + // keep receiving data + let mut received_data = Vec::with_capacity(DATA_SIZE); + let mut buffer = vec![0u8; 1024]; + let mut received_count = 0; + while received_count < DATA_SIZE { + let n = stream.read(&mut buffer).unwrap_or_else(|_| panic!("VSOCK-GUEST: read failed")); + assert!(n > 0, "VSOCK-GUEST: GUEST disconnected unexpectedly during receiving"); + received_data.extend_from_slice(&buffer[..n]); + received_count += n; + if received_count % (1024 * 1024) == 0 { + println!("VSOCK-GUEST: Recv {} MB", received_count / (1024 * 1024)); + } + } + + // Data reception completed, verification begins + assert!(received_count == DATA_SIZE, "VSOCK-GUEST: Data size mismatch! Expected: {} bytes, Received: {} bytes", DATA_SIZE, received_count); + + // Time series verification + let mut errors = 0; + for i in 0..DATA_SIZE { + if received_data[i] != data_to_send[i] { + errors += 1; + } + } + + // output verification results + let result = if errors == 0 { + TestResult { status: "pass" } + } else { + TestResult { status: "fail" } + }; + println!("{}", serde_json::to_string(&result).unwrap()); +} \ No newline at end of file diff --git a/tests/stress/run_vsock_recv.sh b/tests/stress/run_vsock_recv.sh new file mode 100755 index 00000000..7290111a --- /dev/null +++ b/tests/stress/run_vsock_recv.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Wrapper script for running VSOCK tests with host companion +set -euo pipefail + +if [[ $# -lt 1 ]]; then + echo "用法: $0 [companion-name]" >&2 + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WORKSPACE="$(cd "${SCRIPT_DIR}/../.." && pwd)" + +BINARY_NAME="$1" +COMPANION_NAME="$2" + +# Ensure vhost-vsock device is accessible for VSOCK tests +if [[ -e /dev/vhost-vsock ]]; then + sudo chmod 666 /dev/vhost-vsock || true +fi + +# Build host companion and verify it exists +COMPANION_PATH="${WORKSPACE}/artifacts/host-companions/${COMPANION_NAME}" +echo "[vsock-stress-recv] Building host companion: ${COMPANION_NAME}" >&2 +"${WORKSPACE}/tests/ci-test-iter/host-companions/build.sh" + +if [[ ! -x "${COMPANION_PATH}" ]]; then + echo "[vsock-stress-recv] Failed to build or find host companion: ${COMPANION_PATH}" >&2 + exit 1 +fi + +# Export host companion path for run_case.sh +export STARRY_HOST_COMPANION="${COMPANION_PATH}" +export STARRY_COMPANION_DELAY="${STARRY_COMPANION_DELAY:-3}" +export STARRY_COMPANION_TIMEOUT="${STARRY_COMPANION_TIMEOUT:-30}" + +# Run the actual test case +exec "${SCRIPT_DIR}/run_case.sh" "${BINARY_NAME}" diff --git a/tests/stress/suite.toml b/tests/stress/suite.toml index 6d49acdc..921017b4 100644 --- a/tests/stress/suite.toml +++ b/tests/stress/suite.toml @@ -11,6 +11,12 @@ path = "tests/stress/run_case.sh" args = ["cpu_saturator", "4", "15"] timeout_secs = 120 +[[cases]] +name = "vsock-recv-demo" +description = "Detecting timing, credit requests and updates, and result matching during vsock reception through long data transmission" +path = "tests/stress/run_vsock_recv.sh" +args = ["vsock_recv", "vsock-client-send"] + [[cases]] name = "vsock-send-demo" description = "Detecting timing, credit requests and updates, and result matching during vsock reception through long data transmission"