mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-09 20:07:49 +00:00
Merge pull request #4961 from wllenyj/dragonball-ut-2
Built-in Sandbox: add more unit tests for dragonball
This commit is contained in:
commit
ffdd7e1ad8
24
.github/workflows/static-checks.yaml
vendored
24
.github/workflows/static-checks.yaml
vendored
@ -94,3 +94,27 @@ jobs:
|
|||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
|
||||||
run: |
|
run: |
|
||||||
cd ${GOPATH}/src/github.com/${{ github.repository }} && sudo -E PATH="$PATH" make test
|
cd ${GOPATH}/src/github.com/${{ github.repository }} && sudo -E PATH="$PATH" make test
|
||||||
|
|
||||||
|
test-dragonball:
|
||||||
|
runs-on: self-hosted
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Set env
|
||||||
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
|
||||||
|
run: |
|
||||||
|
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
|
||||||
|
- name: Install Rust
|
||||||
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
|
||||||
|
run: |
|
||||||
|
./ci/install_rust.sh
|
||||||
|
PATH=$PATH:"$HOME/.cargo/bin"
|
||||||
|
- name: Run Unit Test
|
||||||
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
|
||||||
|
run: |
|
||||||
|
cd src/dragonball
|
||||||
|
/root/.cargo/bin/cargo version
|
||||||
|
rustc --version
|
||||||
|
# TODO: Using the cargo command directly will get `sudo: cargo: command not found` error.
|
||||||
|
sudo -E /root/.cargo/bin/cargo test --all-features -- --nocapture
|
||||||
|
1
Makefile
1
Makefile
@ -8,6 +8,7 @@ COMPONENTS =
|
|||||||
|
|
||||||
COMPONENTS += libs
|
COMPONENTS += libs
|
||||||
COMPONENTS += agent
|
COMPONENTS += agent
|
||||||
|
COMPONENTS += dragonball
|
||||||
COMPONENTS += runtime
|
COMPONENTS += runtime
|
||||||
COMPONENTS += runtime-rs
|
COMPONENTS += runtime-rs
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ vm-memory = { version = "0.9.0", features = ["backend-mmap"] }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
slog-term = "2.9.0"
|
slog-term = "2.9.0"
|
||||||
slog-async = "2.7.0"
|
slog-async = "2.7.0"
|
||||||
|
test-utils = { path = "../libs/test-utils" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
acpi = []
|
acpi = []
|
||||||
|
@ -15,6 +15,9 @@ clippy:
|
|||||||
-- \
|
-- \
|
||||||
-D warnings
|
-D warnings
|
||||||
|
|
||||||
|
vendor:
|
||||||
|
@echo "INFO: vendor do nothing.."
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@echo "INFO: cargo fmt..."
|
@echo "INFO: cargo fmt..."
|
||||||
cargo fmt -- --check
|
cargo fmt -- --check
|
||||||
@ -23,5 +26,4 @@ clean:
|
|||||||
cargo clean
|
cargo clean
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@echo "INFO: testing dragonball for development build"
|
@echo "INFO: skip testing dragonball"
|
||||||
cargo test --all-features -- --nocapture
|
|
||||||
|
@ -35,8 +35,8 @@ use nix::unistd::dup;
|
|||||||
#[cfg(feature = "atomic-guest-memory")]
|
#[cfg(feature = "atomic-guest-memory")]
|
||||||
use vm_memory::GuestMemoryAtomic;
|
use vm_memory::GuestMemoryAtomic;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
address::Address, FileOffset, GuestAddress, GuestAddressSpace, GuestMemoryMmap, GuestMemoryRegion,
|
address::Address, FileOffset, GuestAddress, GuestAddressSpace, GuestMemoryMmap,
|
||||||
GuestRegionMmap, GuestUsize, MemoryRegionAddress, MmapRegion,
|
GuestMemoryRegion, GuestRegionMmap, GuestUsize, MemoryRegionAddress, MmapRegion,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::resource_manager::ResourceManager;
|
use crate::resource_manager::ResourceManager;
|
||||||
@ -270,7 +270,7 @@ impl AddressSpaceMgr {
|
|||||||
let size = info
|
let size = info
|
||||||
.size
|
.size
|
||||||
.checked_shl(20)
|
.checked_shl(20)
|
||||||
.ok_or_else(|| AddressManagerError::InvalidOperation)?;
|
.ok_or(AddressManagerError::InvalidOperation)?;
|
||||||
|
|
||||||
// Guest memory does not intersect with the MMIO hole.
|
// Guest memory does not intersect with the MMIO hole.
|
||||||
// TODO: make it work for ARM (issue #4307)
|
// TODO: make it work for ARM (issue #4307)
|
||||||
@ -281,13 +281,13 @@ impl AddressSpaceMgr {
|
|||||||
regions.push(region);
|
regions.push(region);
|
||||||
start_addr = start_addr
|
start_addr = start_addr
|
||||||
.checked_add(size)
|
.checked_add(size)
|
||||||
.ok_or_else(|| AddressManagerError::InvalidOperation)?;
|
.ok_or(AddressManagerError::InvalidOperation)?;
|
||||||
} else {
|
} else {
|
||||||
// Add guest memory below the MMIO hole, avoid splitting the memory region
|
// Add guest memory below the MMIO hole, avoid splitting the memory region
|
||||||
// if the available address region is small than MINIMAL_SPLIT_SPACE MiB.
|
// if the available address region is small than MINIMAL_SPLIT_SPACE MiB.
|
||||||
let mut below_size = dbs_boot::layout::MMIO_LOW_START
|
let mut below_size = dbs_boot::layout::MMIO_LOW_START
|
||||||
.checked_sub(start_addr)
|
.checked_sub(start_addr)
|
||||||
.ok_or_else(|| AddressManagerError::InvalidOperation)?;
|
.ok_or(AddressManagerError::InvalidOperation)?;
|
||||||
if below_size < (MINIMAL_SPLIT_SPACE) {
|
if below_size < (MINIMAL_SPLIT_SPACE) {
|
||||||
below_size = 0;
|
below_size = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -299,12 +299,12 @@ impl AddressSpaceMgr {
|
|||||||
let above_start = dbs_boot::layout::MMIO_LOW_END + 1;
|
let above_start = dbs_boot::layout::MMIO_LOW_END + 1;
|
||||||
let above_size = size
|
let above_size = size
|
||||||
.checked_sub(below_size)
|
.checked_sub(below_size)
|
||||||
.ok_or_else(|| AddressManagerError::InvalidOperation)?;
|
.ok_or(AddressManagerError::InvalidOperation)?;
|
||||||
let region = self.create_region(above_start, above_size, info, &mut param)?;
|
let region = self.create_region(above_start, above_size, info, &mut param)?;
|
||||||
regions.push(region);
|
regions.push(region);
|
||||||
start_addr = above_start
|
start_addr = above_start
|
||||||
.checked_add(above_size)
|
.checked_add(above_size)
|
||||||
.ok_or_else(|| AddressManagerError::InvalidOperation)?;
|
.ok_or(AddressManagerError::InvalidOperation)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,7 +502,7 @@ impl AddressSpaceMgr {
|
|||||||
fn configure_numa(&self, mmap_reg: &MmapRegion, node_id: u32) -> Result<()> {
|
fn configure_numa(&self, mmap_reg: &MmapRegion, node_id: u32) -> Result<()> {
|
||||||
let nodemask = 1_u64
|
let nodemask = 1_u64
|
||||||
.checked_shl(node_id)
|
.checked_shl(node_id)
|
||||||
.ok_or_else(|| AddressManagerError::InvalidOperation)?;
|
.ok_or(AddressManagerError::InvalidOperation)?;
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
libc::syscall(
|
libc::syscall(
|
||||||
libc::SYS_mbind,
|
libc::SYS_mbind,
|
||||||
|
@ -18,7 +18,7 @@ pub const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=1 pci=off nomodules 825
|
|||||||
i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd";
|
i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd";
|
||||||
|
|
||||||
/// Strongly typed data structure used to configure the boot source of the microvm.
|
/// Strongly typed data structure used to configure the boot source of the microvm.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Default)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Default)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct BootSourceConfig {
|
pub struct BootSourceConfig {
|
||||||
/// Path of the kernel image.
|
/// Path of the kernel image.
|
||||||
|
@ -10,7 +10,7 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
/// When Dragonball starts, the instance state is Uninitialized. Once start_microvm method is
|
/// When Dragonball starts, the instance state is Uninitialized. Once start_microvm method is
|
||||||
/// called, the state goes from Uninitialized to Starting. The state is changed to Running until
|
/// called, the state goes from Uninitialized to Starting. The state is changed to Running until
|
||||||
/// the start_microvm method ends. Halting and Halted are currently unsupported.
|
/// the start_microvm method ends. Halting and Halted are currently unsupported.
|
||||||
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub enum InstanceState {
|
pub enum InstanceState {
|
||||||
/// Microvm is not initialized.
|
/// Microvm is not initialized.
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
@ -29,7 +29,7 @@ pub enum InstanceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The state of async actions
|
/// The state of async actions
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||||
pub enum AsyncState {
|
pub enum AsyncState {
|
||||||
/// Uninitialized
|
/// Uninitialized
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
|
@ -10,7 +10,7 @@ pub const MAX_SUPPORTED_VCPUS: u8 = 254;
|
|||||||
pub const MEMORY_HOTPLUG_ALIGHMENT: u8 = 64;
|
pub const MEMORY_HOTPLUG_ALIGHMENT: u8 = 64;
|
||||||
|
|
||||||
/// Errors associated with configuring the microVM.
|
/// Errors associated with configuring the microVM.
|
||||||
#[derive(Debug, PartialEq, thiserror::Error)]
|
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||||
pub enum VmConfigError {
|
pub enum VmConfigError {
|
||||||
/// Cannot update the configuration of the microvm post boot.
|
/// Cannot update the configuration of the microvm post boot.
|
||||||
#[error("update operation is not allowed after boot")]
|
#[error("update operation is not allowed after boot")]
|
||||||
|
@ -83,13 +83,13 @@ pub enum VmmActionError {
|
|||||||
|
|
||||||
#[cfg(feature = "virtio-fs")]
|
#[cfg(feature = "virtio-fs")]
|
||||||
/// The action `InsertFsDevice` failed either because of bad user input or an internal error.
|
/// The action `InsertFsDevice` failed either because of bad user input or an internal error.
|
||||||
#[error("virtio-fs device: {0}")]
|
#[error("virtio-fs device error: {0}")]
|
||||||
FsDevice(#[source] FsDeviceError),
|
FsDevice(#[source] FsDeviceError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This enum represents the public interface of the VMM. Each action contains various
|
/// This enum represents the public interface of the VMM. Each action contains various
|
||||||
/// bits of information (ids, paths, etc.).
|
/// bits of information (ids, paths, etc.).
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum VmmAction {
|
pub enum VmmAction {
|
||||||
/// Configure the boot source of the microVM using `BootSourceConfig`.
|
/// Configure the boot source of the microVM using `BootSourceConfig`.
|
||||||
/// This action can only be called before the microVM has booted.
|
/// This action can only be called before the microVM has booted.
|
||||||
@ -298,7 +298,6 @@ impl VmmService {
|
|||||||
let mut cmdline = linux_loader::cmdline::Cmdline::new(dbs_boot::layout::CMDLINE_MAX_SIZE);
|
let mut cmdline = linux_loader::cmdline::Cmdline::new(dbs_boot::layout::CMDLINE_MAX_SIZE);
|
||||||
let boot_args = boot_source_config
|
let boot_args = boot_source_config
|
||||||
.boot_args
|
.boot_args
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| String::from(DEFAULT_KERNEL_CMDLINE));
|
.unwrap_or_else(|| String::from(DEFAULT_KERNEL_CMDLINE));
|
||||||
cmdline
|
cmdline
|
||||||
.insert_str(boot_args)
|
.insert_str(boot_args)
|
||||||
@ -634,3 +633,783 @@ fn handle_cpu_topology(
|
|||||||
|
|
||||||
Ok(cpu_topology)
|
Ok(cpu_topology)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use dbs_utils::epoll_manager::EpollManager;
|
||||||
|
use test_utils::skip_if_not_root;
|
||||||
|
use vmm_sys_util::tempfile::TempFile;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::vmm::tests::create_vmm_instance;
|
||||||
|
|
||||||
|
struct TestData<'a> {
|
||||||
|
req: Option<VmmAction>,
|
||||||
|
vm_state: InstanceState,
|
||||||
|
f: &'a dyn Fn(VmmRequestResult),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TestData<'a> {
|
||||||
|
fn new(req: VmmAction, vm_state: InstanceState, f: &'a dyn Fn(VmmRequestResult)) -> Self {
|
||||||
|
Self {
|
||||||
|
req: Some(req),
|
||||||
|
vm_state,
|
||||||
|
f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_request(&mut self) {
|
||||||
|
let (to_vmm, from_api) = channel();
|
||||||
|
let (to_api, from_vmm) = channel();
|
||||||
|
|
||||||
|
let vmm = Arc::new(Mutex::new(create_vmm_instance()));
|
||||||
|
let mut vservice = VmmService::new(from_api, to_api);
|
||||||
|
|
||||||
|
let epoll_mgr = EpollManager::default();
|
||||||
|
let mut event_mgr = EventManager::new(&vmm, epoll_mgr).unwrap();
|
||||||
|
let mut v = vmm.lock().unwrap();
|
||||||
|
|
||||||
|
let vm = v.get_vm_mut().unwrap();
|
||||||
|
vm.set_instance_state(self.vm_state);
|
||||||
|
|
||||||
|
to_vmm.send(Box::new(self.req.take().unwrap())).unwrap();
|
||||||
|
assert!(vservice.run_vmm_action(&mut v, &mut event_mgr).is_ok());
|
||||||
|
|
||||||
|
let response = from_vmm.try_recv();
|
||||||
|
assert!(response.is_ok());
|
||||||
|
(self.f)(*response.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_receive_unknown() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let (_to_vmm, from_api) = channel();
|
||||||
|
let (to_api, _from_vmm) = channel();
|
||||||
|
let vmm = Arc::new(Mutex::new(create_vmm_instance()));
|
||||||
|
let mut vservice = VmmService::new(from_api, to_api);
|
||||||
|
let epoll_mgr = EpollManager::default();
|
||||||
|
let mut event_mgr = EventManager::new(&vmm, epoll_mgr).unwrap();
|
||||||
|
let mut v = vmm.lock().unwrap();
|
||||||
|
|
||||||
|
assert!(vservice.run_vmm_action(&mut v, &mut event_mgr).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[should_panic]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_disconnected() {
|
||||||
|
let (to_vmm, from_api) = channel();
|
||||||
|
let (to_api, _from_vmm) = channel();
|
||||||
|
let vmm = Arc::new(Mutex::new(create_vmm_instance()));
|
||||||
|
let mut vservice = VmmService::new(from_api, to_api);
|
||||||
|
let epoll_mgr = EpollManager::default();
|
||||||
|
let mut event_mgr = EventManager::new(&vmm, epoll_mgr).unwrap();
|
||||||
|
let mut v = vmm.lock().unwrap();
|
||||||
|
|
||||||
|
drop(to_vmm);
|
||||||
|
vservice.run_vmm_action(&mut v, &mut event_mgr).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_config_boot_source() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let kernel_file = TempFile::new().unwrap();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::ConfigureBootSource(BootSourceConfig::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
if let Err(VmmActionError::BootSource(
|
||||||
|
BootSourceConfigError::UpdateNotAllowedPostBoot,
|
||||||
|
)) = result
|
||||||
|
{
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to configure boot source for VM: \
|
||||||
|
the update operation is not allowed after boot",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid kernel file path
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::ConfigureBootSource(BootSourceConfig::default()),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
if let Err(VmmActionError::BootSource(
|
||||||
|
BootSourceConfigError::InvalidKernelPath(_),
|
||||||
|
)) = result
|
||||||
|
{
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to configure boot source for VM: \
|
||||||
|
the kernel file cannot be opened due to invalid kernel path or invalid permissions: \
|
||||||
|
No such file or directory (os error 2)");
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
//success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::ConfigureBootSource(BootSourceConfig {
|
||||||
|
kernel_path: kernel_file.as_path().to_str().unwrap().to_string(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_set_vm_configuration() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::UpdateNotAllowedPostBoot
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
update operation is not allowed after boot",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid cpu count (0)
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
vcpu_count: 0,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::InvalidVcpuCount(0)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
the vCPU number '0' can only be 1 or an even number when hyperthreading is enabled");
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid max cpu count (too small)
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
vcpu_count: 4,
|
||||||
|
max_vcpu_count: 2,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::InvalidMaxVcpuCount(2)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
the max vCPU number '2' shouldn't less than vCPU count and can only be 1 or an even number when hyperthreading is enabled");
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid cpu topology (larger than 254)
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
vcpu_count: 254,
|
||||||
|
cpu_topology: CpuTopology {
|
||||||
|
threads_per_core: 2,
|
||||||
|
cores_per_die: 128,
|
||||||
|
dies_per_socket: 1,
|
||||||
|
sockets: 1,
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::VcpuCountExceedsMaximum
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
the vCPU number shouldn't large than 254",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(err_string, expected_err)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// cpu topology and max_vcpu_count are not matched - success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
vcpu_count: 16,
|
||||||
|
max_vcpu_count: 32,
|
||||||
|
cpu_topology: CpuTopology {
|
||||||
|
threads_per_core: 1,
|
||||||
|
cores_per_die: 128,
|
||||||
|
dies_per_socket: 1,
|
||||||
|
sockets: 1,
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
result.unwrap();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid threads_per_core
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
vcpu_count: 4,
|
||||||
|
max_vcpu_count: 4,
|
||||||
|
cpu_topology: CpuTopology {
|
||||||
|
threads_per_core: 4,
|
||||||
|
cores_per_die: 1,
|
||||||
|
dies_per_socket: 1,
|
||||||
|
sockets: 1,
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::InvalidThreadsPerCore(4)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
the threads_per_core number '4' can only be 1 or 2",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(err_string, expected_err)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid mem size
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
mem_size_mib: 3,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::InvalidMemorySize(3)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
the memory size 0x3MiB is invalid",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid mem path
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo {
|
||||||
|
mem_type: String::from("hugetlbfs"),
|
||||||
|
mem_file_path: String::from(""),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::MachineConfig(
|
||||||
|
VmConfigError::InvalidMemFilePath(_)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to set configuration for the VM: \
|
||||||
|
the memory file path is invalid",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::SetVmConfiguration(VmConfigInfo::default()),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_start_microvm() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state (running)
|
||||||
|
TestData::new(VmmAction::StartMicroVm, InstanceState::Running, &|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::StartMicroVm(
|
||||||
|
StartMicroVmError::MicroVMAlreadyRunning
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to boot the VM: \
|
||||||
|
the virtual machine is already running",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
}),
|
||||||
|
// no kernel configuration
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::StartMicroVm,
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::StartMicroVm(
|
||||||
|
StartMicroVmError::MissingKernelConfig
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to boot the VM: \
|
||||||
|
cannot start the virtual machine without kernel configuration",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_shutdown_microvm() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::ShutdownMicroVm,
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-blk")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_insert_block_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let dummy_file = TempFile::new().unwrap();
|
||||||
|
let dummy_path = dummy_file.as_path().to_owned();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertBlockDevice(BlockDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::Block(
|
||||||
|
BlockDeviceError::UpdateNotAllowedPostBoot
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-blk device error: \
|
||||||
|
block device does not support runtime update",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertBlockDevice(BlockDeviceConfigInfo {
|
||||||
|
path_on_host: dummy_path,
|
||||||
|
device_type: crate::device_manager::blk_dev_mgr::BlockDeviceType::RawBlock,
|
||||||
|
is_root_device: true,
|
||||||
|
part_uuid: None,
|
||||||
|
is_read_only: false,
|
||||||
|
is_direct: false,
|
||||||
|
no_drop: false,
|
||||||
|
drive_id: String::from("1"),
|
||||||
|
rate_limiter: None,
|
||||||
|
num_queues: BlockDeviceConfigInfo::default_num_queues(),
|
||||||
|
queue_size: 256,
|
||||||
|
use_shared_irq: None,
|
||||||
|
use_generic_irq: None,
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-blk")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_update_block_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid id
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::UpdateBlockDevice(BlockDeviceConfigUpdateInfo {
|
||||||
|
drive_id: String::from("1"),
|
||||||
|
rate_limiter: None,
|
||||||
|
}),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::Block(BlockDeviceError::InvalidDeviceId(_)))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-blk device error: \
|
||||||
|
invalid block device id '1'",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-blk")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_remove_block_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::RemoveBlockDevice(String::from("1")),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::Block(
|
||||||
|
BlockDeviceError::UpdateNotAllowedPostBoot
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-blk device error: \
|
||||||
|
block device does not support runtime update",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid id
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::RemoveBlockDevice(String::from("1")),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::Block(BlockDeviceError::InvalidDeviceId(_)))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-blk device error: \
|
||||||
|
invalid block device id '1'",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_insert_fs_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertFsDevice(FsDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::FsDevice(
|
||||||
|
FsDeviceError::UpdateNotAllowedPostBoot
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-fs device error: \
|
||||||
|
update operation is not allowed after boot",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertFsDevice(FsDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_manipulate_fs_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::ManipulateFsBackendFs(FsMountConfigInfo::default()),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::FsDevice(FsDeviceError::MicroVMNotRunning))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-fs device error: \
|
||||||
|
vm is not running when attaching a backend fs",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid backend
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::ManipulateFsBackendFs(FsMountConfigInfo::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::FsDevice(
|
||||||
|
FsDeviceError::AttachBackendFailed(_)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
println!("{}", err_string);
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-fs device error: \
|
||||||
|
Fs device attach a backend fs failed",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-net")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_insert_network_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// hotplug unready
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertNetworkDevice(VirtioNetDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::StartMicroVm(
|
||||||
|
StartMicroVmError::UpcallMissVsock
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to boot the VM: \
|
||||||
|
the upcall client needs a virtio-vsock device for communication",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertNetworkDevice(VirtioNetDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-net")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_update_network_interface() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid id
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::UpdateNetworkInterface(VirtioNetDeviceConfigUpdateInfo {
|
||||||
|
iface_id: String::from("1"),
|
||||||
|
rx_rate_limiter: None,
|
||||||
|
tx_rate_limiter: None,
|
||||||
|
}),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::VirtioNet(
|
||||||
|
VirtioNetDeviceError::InvalidIfaceId(_)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"virtio-net device error: \
|
||||||
|
invalid virtio-net iface id '1'",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-vsock")]
|
||||||
|
#[test]
|
||||||
|
fn test_vmm_action_insert_vsock_device() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
let tests = &mut [
|
||||||
|
// invalid state
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertVsockDevice(VsockDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Running,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::Vsock(
|
||||||
|
VsockDeviceError::UpdateNotAllowedPostBoot
|
||||||
|
))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to add virtio-vsock device: \
|
||||||
|
update operation is not allowed after boot",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// invalid guest_cid
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertVsockDevice(VsockDeviceConfigInfo::default()),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(VmmActionError::Vsock(VsockDeviceError::GuestCIDInvalid(0)))
|
||||||
|
));
|
||||||
|
let err_string = format!("{}", result.unwrap_err());
|
||||||
|
let expected_err = String::from(
|
||||||
|
"failed to add virtio-vsock device: \
|
||||||
|
the guest CID 0 is invalid",
|
||||||
|
);
|
||||||
|
assert_eq!(err_string, expected_err);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// success
|
||||||
|
TestData::new(
|
||||||
|
VmmAction::InsertVsockDevice(VsockDeviceConfigInfo {
|
||||||
|
guest_cid: 3,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
InstanceState::Uninitialized,
|
||||||
|
&|result| {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in tests.iter_mut() {
|
||||||
|
t.check_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -46,7 +46,7 @@ pub trait ConfigItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Struct to manage a group of configuration items.
|
/// Struct to manage a group of configuration items.
|
||||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct ConfigInfos<T>
|
pub struct ConfigInfos<T>
|
||||||
where
|
where
|
||||||
T: ConfigItem + Clone,
|
T: ConfigItem + Clone,
|
||||||
@ -316,7 +316,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for RateLimiter token bucket.
|
/// Configuration information for RateLimiter token bucket.
|
||||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct TokenBucketConfigInfo {
|
pub struct TokenBucketConfigInfo {
|
||||||
/// The size for the token bucket. A TokenBucket of `size` total capacity will take `refill_time`
|
/// The size for the token bucket. A TokenBucket of `size` total capacity will take `refill_time`
|
||||||
/// milliseconds to go from zero tokens to total capacity.
|
/// milliseconds to go from zero tokens to total capacity.
|
||||||
@ -349,7 +349,7 @@ impl From<&TokenBucketConfigInfo> for TokenBucket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for RateLimiter objects.
|
/// Configuration information for RateLimiter objects.
|
||||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct RateLimiterConfigInfo {
|
pub struct RateLimiterConfigInfo {
|
||||||
/// Data used to initialize the RateLimiter::bandwidth bucket.
|
/// Data used to initialize the RateLimiter::bandwidth bucket.
|
||||||
pub bandwidth: TokenBucketConfigInfo,
|
pub bandwidth: TokenBucketConfigInfo,
|
||||||
|
@ -106,7 +106,7 @@ pub enum BlockDeviceError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Type of low level storage device/protocol for virtio-blk devices.
|
/// Type of low level storage device/protocol for virtio-blk devices.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum BlockDeviceType {
|
pub enum BlockDeviceType {
|
||||||
/// Unknown low level device type.
|
/// Unknown low level device type.
|
||||||
Unknown,
|
Unknown,
|
||||||
@ -131,7 +131,7 @@ impl BlockDeviceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for a block device.
|
/// Configuration information for a block device.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct BlockDeviceConfigUpdateInfo {
|
pub struct BlockDeviceConfigUpdateInfo {
|
||||||
/// Unique identifier of the drive.
|
/// Unique identifier of the drive.
|
||||||
pub drive_id: String,
|
pub drive_id: String,
|
||||||
@ -151,7 +151,7 @@ impl BlockDeviceConfigUpdateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for a block device.
|
/// Configuration information for a block device.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct BlockDeviceConfigInfo {
|
pub struct BlockDeviceConfigInfo {
|
||||||
/// Unique identifier of the drive.
|
/// Unique identifier of the drive.
|
||||||
pub drive_id: String,
|
pub drive_id: String,
|
||||||
@ -625,7 +625,7 @@ impl BlockDeviceMgr {
|
|||||||
// we need to satisfy the condition by which a VMM can only have on root device
|
// we need to satisfy the condition by which a VMM can only have on root device
|
||||||
if block_device_config.is_root_device {
|
if block_device_config.is_root_device {
|
||||||
if self.has_root_block {
|
if self.has_root_block {
|
||||||
return Err(BlockDeviceError::RootBlockDeviceAlreadyAdded);
|
Err(BlockDeviceError::RootBlockDeviceAlreadyAdded)
|
||||||
} else {
|
} else {
|
||||||
self.has_root_block = true;
|
self.has_root_block = true;
|
||||||
self.read_only_root = block_device_config.is_read_only;
|
self.read_only_root = block_device_config.is_read_only;
|
||||||
|
@ -89,7 +89,7 @@ pub enum FsDeviceError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for a vhost-user-fs device.
|
/// Configuration information for a vhost-user-fs device.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct FsDeviceConfigInfo {
|
pub struct FsDeviceConfigInfo {
|
||||||
/// vhost-user socket path.
|
/// vhost-user socket path.
|
||||||
pub sock_path: String,
|
pub sock_path: String,
|
||||||
@ -201,7 +201,7 @@ impl FsDeviceConfigInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for virtio-fs.
|
/// Configuration information for virtio-fs.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct FsDeviceConfigUpdateInfo {
|
pub struct FsDeviceConfigUpdateInfo {
|
||||||
/// virtiofs mount tag name used inside the guest.
|
/// virtiofs mount tag name used inside the guest.
|
||||||
/// used as the device name during mount.
|
/// used as the device name during mount.
|
||||||
@ -242,7 +242,7 @@ impl ConfigItem for FsDeviceConfigInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information of manipulating backend fs for a virtiofs device.
|
/// Configuration information of manipulating backend fs for a virtiofs device.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Default)]
|
||||||
pub struct FsMountConfigInfo {
|
pub struct FsMountConfigInfo {
|
||||||
/// Mount operations, mount, update, umount
|
/// Mount operations, mount, update, umount
|
||||||
pub ops: String,
|
pub ops: String,
|
||||||
|
@ -147,7 +147,11 @@ pub type Result<T> = ::std::result::Result<T, DeviceMgrError>;
|
|||||||
/// Type of the dragonball virtio devices.
|
/// Type of the dragonball virtio devices.
|
||||||
#[cfg(feature = "dbs-virtio-devices")]
|
#[cfg(feature = "dbs-virtio-devices")]
|
||||||
pub type DbsVirtioDevice = Box<
|
pub type DbsVirtioDevice = Box<
|
||||||
dyn VirtioDevice<GuestAddressSpaceImpl, virtio_queue::QueueStateSync, vm_memory::GuestRegionMmap>,
|
dyn VirtioDevice<
|
||||||
|
GuestAddressSpaceImpl,
|
||||||
|
virtio_queue::QueueStateSync,
|
||||||
|
vm_memory::GuestRegionMmap,
|
||||||
|
>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// Type of the dragonball virtio mmio devices.
|
/// Type of the dragonball virtio mmio devices.
|
||||||
@ -997,7 +1001,7 @@ impl DeviceManager {
|
|||||||
{
|
{
|
||||||
self.vsock_manager
|
self.vsock_manager
|
||||||
.get_default_connector()
|
.get_default_connector()
|
||||||
.map(|d| Some(d))
|
.map(Some)
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "virtio-vsock"))]
|
#[cfg(not(feature = "virtio-vsock"))]
|
||||||
|
@ -93,7 +93,7 @@ pub enum VirtioNetDeviceError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for virtio net devices.
|
/// Configuration information for virtio net devices.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct VirtioNetDeviceConfigUpdateInfo {
|
pub struct VirtioNetDeviceConfigUpdateInfo {
|
||||||
/// ID of the guest network interface.
|
/// ID of the guest network interface.
|
||||||
pub iface_id: String,
|
pub iface_id: String,
|
||||||
@ -123,7 +123,7 @@ impl VirtioNetDeviceConfigUpdateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for virtio net devices.
|
/// Configuration information for virtio net devices.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Default)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Default)]
|
||||||
pub struct VirtioNetDeviceConfigInfo {
|
pub struct VirtioNetDeviceConfigInfo {
|
||||||
/// ID of the guest network interface.
|
/// ID of the guest network interface.
|
||||||
pub iface_id: String,
|
pub iface_id: String,
|
||||||
@ -264,7 +264,7 @@ impl VirtioNetDeviceMgr {
|
|||||||
config.use_generic_irq.unwrap_or(USE_GENERIC_IRQ),
|
config.use_generic_irq.unwrap_or(USE_GENERIC_IRQ),
|
||||||
)
|
)
|
||||||
.map_err(VirtioNetDeviceError::DeviceManager)?;
|
.map_err(VirtioNetDeviceError::DeviceManager)?;
|
||||||
ctx.insert_hotplug_mmio_device(&dev.clone(), None)
|
ctx.insert_hotplug_mmio_device(&dev, None)
|
||||||
.map_err(VirtioNetDeviceError::DeviceManager)?;
|
.map_err(VirtioNetDeviceError::DeviceManager)?;
|
||||||
// live-upgrade need save/restore device from info.device.
|
// live-upgrade need save/restore device from info.device.
|
||||||
mgr.info_list[device_index].set_device(dev);
|
mgr.info_list[device_index].set_device(dev);
|
||||||
|
@ -70,7 +70,7 @@ pub enum VsockDeviceError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for a vsock device.
|
/// Configuration information for a vsock device.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct VsockDeviceConfigInfo {
|
pub struct VsockDeviceConfigInfo {
|
||||||
/// ID of the vsock device.
|
/// ID of the vsock device.
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -210,14 +210,19 @@ mod x86_64 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use kvm_ioctls::Kvm;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||||
|
|
||||||
|
use kvm_ioctls::Kvm;
|
||||||
|
use test_utils::skip_if_not_root;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_kvm_context() {
|
fn test_create_kvm_context() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
let c = KvmContext::new(None).unwrap();
|
let c = KvmContext::new(None).unwrap();
|
||||||
|
|
||||||
assert!(c.max_memslots >= 32);
|
assert!(c.max_memslots >= 32);
|
||||||
@ -234,6 +239,8 @@ mod tests {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_supported_cpu_id() {
|
fn test_get_supported_cpu_id() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
let c = KvmContext::new(None).unwrap();
|
let c = KvmContext::new(None).unwrap();
|
||||||
|
|
||||||
let _ = c
|
let _ = c
|
||||||
@ -244,6 +251,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_vm() {
|
fn test_create_vm() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
let c = KvmContext::new(None).unwrap();
|
let c = KvmContext::new(None).unwrap();
|
||||||
|
|
||||||
let _ = c.create_vm().unwrap();
|
let _ = c.create_vm().unwrap();
|
||||||
|
@ -36,7 +36,7 @@ const PIO_MAX: u16 = 0xFFFF;
|
|||||||
const MMIO_SPACE_RESERVED: u64 = 0x400_0000;
|
const MMIO_SPACE_RESERVED: u64 = 0x400_0000;
|
||||||
|
|
||||||
/// Errors associated with resource management operations
|
/// Errors associated with resource management operations
|
||||||
#[derive(Debug, PartialEq, thiserror::Error)]
|
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||||
pub enum ResourceError {
|
pub enum ResourceError {
|
||||||
/// Unknown/unsupported resource type.
|
/// Unknown/unsupported resource type.
|
||||||
#[error("unsupported resource type")]
|
#[error("unsupported resource type")]
|
||||||
@ -569,9 +569,7 @@ impl ResourceManager {
|
|||||||
Resource::KvmMemSlot(slot) => self.free_kvm_mem_slot(*slot),
|
Resource::KvmMemSlot(slot) => self.free_kvm_mem_slot(*slot),
|
||||||
Resource::MacAddresss(_) => Ok(()),
|
Resource::MacAddresss(_) => Ok(()),
|
||||||
};
|
};
|
||||||
if result.is_err() {
|
result?;
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -588,9 +586,9 @@ mod tests {
|
|||||||
// Allocate/free shared IRQs multiple times.
|
// Allocate/free shared IRQs multiple times.
|
||||||
assert_eq!(mgr.allocate_legacy_irq(true, None).unwrap(), SHARED_IRQ);
|
assert_eq!(mgr.allocate_legacy_irq(true, None).unwrap(), SHARED_IRQ);
|
||||||
assert_eq!(mgr.allocate_legacy_irq(true, None).unwrap(), SHARED_IRQ);
|
assert_eq!(mgr.allocate_legacy_irq(true, None).unwrap(), SHARED_IRQ);
|
||||||
mgr.free_legacy_irq(SHARED_IRQ);
|
mgr.free_legacy_irq(SHARED_IRQ).unwrap();
|
||||||
mgr.free_legacy_irq(SHARED_IRQ);
|
mgr.free_legacy_irq(SHARED_IRQ).unwrap();
|
||||||
mgr.free_legacy_irq(SHARED_IRQ);
|
mgr.free_legacy_irq(SHARED_IRQ).unwrap();
|
||||||
|
|
||||||
// Allocate specified IRQs.
|
// Allocate specified IRQs.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -598,7 +596,7 @@ mod tests {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
LEGACY_IRQ_BASE + 10
|
LEGACY_IRQ_BASE + 10
|
||||||
);
|
);
|
||||||
mgr.free_legacy_irq(LEGACY_IRQ_BASE + 10);
|
mgr.free_legacy_irq(LEGACY_IRQ_BASE + 10).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mgr.allocate_legacy_irq(false, Some(LEGACY_IRQ_BASE + 10))
|
mgr.allocate_legacy_irq(false, Some(LEGACY_IRQ_BASE + 10))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -635,19 +633,19 @@ mod tests {
|
|||||||
let mgr = ResourceManager::new(None);
|
let mgr = ResourceManager::new(None);
|
||||||
|
|
||||||
let msi = mgr.allocate_msi_irq(3).unwrap();
|
let msi = mgr.allocate_msi_irq(3).unwrap();
|
||||||
mgr.free_msi_irq(msi, 3);
|
mgr.free_msi_irq(msi, 3).unwrap();
|
||||||
let msi = mgr.allocate_msi_irq(3).unwrap();
|
let msi = mgr.allocate_msi_irq(3).unwrap();
|
||||||
mgr.free_msi_irq(msi, 3);
|
mgr.free_msi_irq(msi, 3).unwrap();
|
||||||
|
|
||||||
let irq = mgr.allocate_msi_irq_aligned(8).unwrap();
|
let irq = mgr.allocate_msi_irq_aligned(8).unwrap();
|
||||||
assert_eq!(irq & 0x7, 0);
|
assert_eq!(irq & 0x7, 0);
|
||||||
mgr.free_msi_irq(msi, 8);
|
mgr.free_msi_irq(msi, 8).unwrap();
|
||||||
let irq = mgr.allocate_msi_irq_aligned(8).unwrap();
|
let irq = mgr.allocate_msi_irq_aligned(8).unwrap();
|
||||||
assert_eq!(irq & 0x7, 0);
|
assert_eq!(irq & 0x7, 0);
|
||||||
|
|
||||||
let irq = mgr.allocate_msi_irq_aligned(512).unwrap();
|
let irq = mgr.allocate_msi_irq_aligned(512).unwrap();
|
||||||
assert_eq!(irq, 512);
|
assert_eq!(irq, 512);
|
||||||
mgr.free_msi_irq(irq, 512);
|
mgr.free_msi_irq(irq, 512).unwrap();
|
||||||
let irq = mgr.allocate_msi_irq_aligned(512).unwrap();
|
let irq = mgr.allocate_msi_irq_aligned(512).unwrap();
|
||||||
assert_eq!(irq, 512);
|
assert_eq!(irq, 512);
|
||||||
|
|
||||||
@ -690,9 +688,9 @@ mod tests {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let resources = mgr.allocate_device_resources(&requests, false).unwrap();
|
let resources = mgr.allocate_device_resources(&requests, false).unwrap();
|
||||||
mgr.free_device_resources(&resources);
|
mgr.free_device_resources(&resources).unwrap();
|
||||||
let resources = mgr.allocate_device_resources(&requests, false).unwrap();
|
let resources = mgr.allocate_device_resources(&requests, false).unwrap();
|
||||||
mgr.free_device_resources(&resources);
|
mgr.free_device_resources(&resources).unwrap();
|
||||||
requests.push(ResourceConstraint::PioAddress {
|
requests.push(ResourceConstraint::PioAddress {
|
||||||
range: Some((0xc000, 0xc000)),
|
range: Some((0xc000, 0xc000)),
|
||||||
align: 0x1000,
|
align: 0x1000,
|
||||||
@ -702,7 +700,7 @@ mod tests {
|
|||||||
let resources = mgr
|
let resources = mgr
|
||||||
.allocate_device_resources(&requests[0..requests.len() - 1], false)
|
.allocate_device_resources(&requests[0..requests.len() - 1], false)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
mgr.free_device_resources(&resources);
|
mgr.free_device_resources(&resources).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -721,7 +719,7 @@ mod tests {
|
|||||||
let mgr = ResourceManager::new(None);
|
let mgr = ResourceManager::new(None);
|
||||||
assert_eq!(mgr.allocate_kvm_mem_slot(1, None).unwrap(), 0);
|
assert_eq!(mgr.allocate_kvm_mem_slot(1, None).unwrap(), 0);
|
||||||
assert_eq!(mgr.allocate_kvm_mem_slot(1, Some(200)).unwrap(), 200);
|
assert_eq!(mgr.allocate_kvm_mem_slot(1, Some(200)).unwrap(), 200);
|
||||||
mgr.free_kvm_mem_slot(200);
|
mgr.free_kvm_mem_slot(200).unwrap();
|
||||||
assert_eq!(mgr.allocate_kvm_mem_slot(1, Some(200)).unwrap(), 200);
|
assert_eq!(mgr.allocate_kvm_mem_slot(1, Some(200)).unwrap(), 200);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mgr.allocate_kvm_mem_slot(1, Some(KVM_USER_MEM_SLOTS))
|
mgr.allocate_kvm_mem_slot(1, Some(KVM_USER_MEM_SLOTS))
|
||||||
|
@ -533,16 +533,11 @@ impl Vcpu {
|
|||||||
fn check_io_port_info(&self, addr: u16, data: &[u8]) -> Result<bool> {
|
fn check_io_port_info(&self, addr: u16, data: &[u8]) -> Result<bool> {
|
||||||
let mut checked = false;
|
let mut checked = false;
|
||||||
|
|
||||||
match addr {
|
// debug info signal
|
||||||
// debug info signal
|
if addr == MAGIC_IOPORT_DEBUG_INFO && data.len() == 4 {
|
||||||
MAGIC_IOPORT_DEBUG_INFO => {
|
let data = unsafe { std::ptr::read(data.as_ptr() as *const u32) };
|
||||||
if data.len() == 4 {
|
log::warn!("KDBG: guest kernel debug info: 0x{:x}", data);
|
||||||
let data = unsafe { std::ptr::read(data.as_ptr() as *const u32) };
|
checked = true;
|
||||||
log::warn!("KDBG: guest kernel debug info: 0x{:x}", data);
|
|
||||||
checked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(checked)
|
Ok(checked)
|
||||||
@ -771,6 +766,7 @@ pub mod tests {
|
|||||||
use dbs_device::device_manager::IoManager;
|
use dbs_device::device_manager::IoManager;
|
||||||
use kvm_ioctls::Kvm;
|
use kvm_ioctls::Kvm;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use test_utils::skip_if_not_root;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::kvm_context::KvmContext;
|
use crate::kvm_context::KvmContext;
|
||||||
@ -880,6 +876,8 @@ pub mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vcpu_run_emulation() {
|
fn test_vcpu_run_emulation() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
let (mut vcpu, _) = create_vcpu();
|
let (mut vcpu, _) = create_vcpu();
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@ -964,6 +962,8 @@ pub mod tests {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vcpu_check_io_port_info() {
|
fn test_vcpu_check_io_port_info() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
let (vcpu, _receiver) = create_vcpu();
|
let (vcpu, _receiver) = create_vcpu();
|
||||||
|
|
||||||
// debug info signal
|
// debug info signal
|
||||||
|
@ -67,7 +67,7 @@ pub enum VmError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for user defined NUMA nodes.
|
/// Configuration information for user defined NUMA nodes.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct NumaRegionInfo {
|
pub struct NumaRegionInfo {
|
||||||
/// memory size for this region (unit: MiB)
|
/// memory size for this region (unit: MiB)
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
@ -80,7 +80,7 @@ pub struct NumaRegionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Information for cpu topology to guide guest init
|
/// Information for cpu topology to guide guest init
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct CpuTopology {
|
pub struct CpuTopology {
|
||||||
/// threads per core to indicate hyperthreading is enabled or not
|
/// threads per core to indicate hyperthreading is enabled or not
|
||||||
pub threads_per_core: u8,
|
pub threads_per_core: u8,
|
||||||
@ -104,7 +104,7 @@ impl Default for CpuTopology {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration information for virtual machine instance.
|
/// Configuration information for virtual machine instance.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct VmConfigInfo {
|
pub struct VmConfigInfo {
|
||||||
/// Number of vcpu to start.
|
/// Number of vcpu to start.
|
||||||
pub vcpu_count: u8,
|
pub vcpu_count: u8,
|
||||||
@ -814,3 +814,17 @@ impl Vm {
|
|||||||
Err(StartMicroVmError::MicroVMAlreadyRunning)
|
Err(StartMicroVmError::MicroVMAlreadyRunning)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Vm {
|
||||||
|
pub fn set_instance_state(&mut self, mstate: InstanceState) {
|
||||||
|
self.shared_info
|
||||||
|
.write()
|
||||||
|
.expect("Failed to start microVM because shared info couldn't be written due to poisoned lock")
|
||||||
|
.state = mstate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -189,6 +189,8 @@ impl Vmm {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
|
use test_utils::skip_if_not_root;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn create_vmm_instance() -> Vmm {
|
pub fn create_vmm_instance() -> Vmm {
|
||||||
@ -210,6 +212,8 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_vmm_instance() {
|
fn test_create_vmm_instance() {
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
create_vmm_instance();
|
create_vmm_instance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user