mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a63fa2613 | ||
|
|
3a63143f33 | ||
|
|
064c1e2c8b | ||
|
|
15b9d14876 | ||
|
|
9da363e79b | ||
|
|
bbfd810c3b | ||
|
|
8fb86d2284 | ||
|
|
797110cca1 | ||
|
|
19ca5c0b84 | ||
|
|
9fe9b8504d | ||
|
|
4fc3dd5004 | ||
|
|
6bc6365c35 | ||
|
|
e139cdfd69 | ||
|
|
541de8b757 | ||
|
|
184dac70a0 | ||
|
|
022b489e7b | ||
|
|
399e2f9f7d | ||
|
|
22cc96494f | ||
|
|
f98402ec15 | ||
|
|
acc54ade7b | ||
|
|
0ebbb3f8a2 | ||
|
|
95511287ec | ||
|
|
5a3af30e6a | ||
|
|
034b48faf7 | ||
|
|
ba3e02ce86 | ||
|
|
5492259af9 | ||
|
|
cc1254d5e1 | ||
|
|
34bb3319d4 | ||
|
|
d530569ac2 | ||
|
|
75956e64ec | ||
|
|
ae646c2a00 | ||
|
|
04d3e5bbf5 | ||
|
|
cbe972659c | ||
|
|
1e4e03d110 | ||
|
|
4876f7550d | ||
|
|
c0146e3ef1 | ||
|
|
77a205881b | ||
|
|
321421c53e | ||
|
|
48a87e699d | ||
|
|
147a800d5d | ||
|
|
eaf8cbd47d | ||
|
|
9d24e862eb | ||
|
|
11324ac21c | ||
|
|
ce75865e2c |
5
.github/workflows/build.yaml
vendored
5
.github/workflows/build.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- "1.64"
|
||||
- "1.62"
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
@@ -42,9 +42,6 @@ jobs:
|
||||
- name: Build (default features + tdx)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (default features + dbus_api)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "dbus_api" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (default features + guest_debug)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
|
||||
26
.github/workflows/hadolint.yaml
vendored
26
.github/workflows/hadolint.yaml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Lint Dockerfile
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- resources/Dockerfile
|
||||
pull_request:
|
||||
paths:
|
||||
- resources/Dockerfile
|
||||
|
||||
jobs:
|
||||
hadolint:
|
||||
name: Run Hadolint Dockerfile Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Lint Dockerfile
|
||||
uses: hadolint/hadolint-action@master
|
||||
with:
|
||||
dockerfile: ./resources/Dockerfile
|
||||
format: tty
|
||||
no-fail: false
|
||||
verbose: true
|
||||
failure-threshold: info
|
||||
1165
Cargo.lock
generated
1165
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
19
Cargo.toml
19
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "33.0.0"
|
||||
version = "31.2.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -15,7 +15,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
# a.) A dependency requires it,
|
||||
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
|
||||
# c.) There is a security issue that is addressed by the toolchain update.
|
||||
rust-version = "1.64"
|
||||
rust-version = "1.62"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
@@ -29,7 +29,7 @@ strip = false
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
api_client = { path = "api_client" }
|
||||
argh = "0.1.9"
|
||||
dhat = { version = "0.3.2", optional = true }
|
||||
@@ -40,34 +40,31 @@ libc = "0.2.139"
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = "0.3.0"
|
||||
serde_json = "1.0.96"
|
||||
serde_json = "1.0.95"
|
||||
signal-hook = "0.3.15"
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
tpm = { path = "tpm"}
|
||||
tracer = { path = "tracer" }
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.11.0"
|
||||
zbus = { version = "3.11.1", optional = true }
|
||||
vm-memory = "0.10.0"
|
||||
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
vhost = { git = "https://github.com/rust-vmm/vhost", branch = "main" }
|
||||
|
||||
[dev-dependencies]
|
||||
dirs = "5.0.0"
|
||||
dirs = "4.0.0"
|
||||
net_util = { path = "net_util" }
|
||||
once_cell = "1.17.1"
|
||||
serde_json = "1.0.96"
|
||||
serde_json = "1.0.95"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = ["kvm"]
|
||||
dbus_api = ["zbus", "vmm/dbus_api"]
|
||||
dhat-heap = ["dhat"] # For heap profiling
|
||||
guest_debug = ["vmm/guest_debug"]
|
||||
kvm = ["vmm/kvm"]
|
||||
|
||||
@@ -140,10 +140,7 @@ The Ubuntu cloud images do not ship with a default password so it necessary to
|
||||
use a `cloud-init` disk image to customise the image on the first boot. A basic
|
||||
`cloud-init` image is generated by this [script](scripts/create-cloud-init.sh).
|
||||
This seeds the image with a default username/password of `cloud/cloud123`. It
|
||||
is only necessary to add this disk image on the first boot. Script also assigns
|
||||
default IP address using `test_data/cloud-init/ubuntu/local/network-config` details
|
||||
with `--net "mac=12:34:56:78:90:ab,tap="` option. Then the matching mac address
|
||||
interface will be enabled as per `network-config` details.
|
||||
is only necessary to add this disk image on the first boot.
|
||||
|
||||
```shell
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
|
||||
@@ -9,18 +9,18 @@ default = []
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
linux-loader = { version = "0.9.0", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.40"
|
||||
uuid = "1.3.4"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.39"
|
||||
uuid = "1.3.0"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@ use super::layout::{
|
||||
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
||||
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use vm_fdt::{FdtWriter, FdtWriterResult};
|
||||
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
||||
|
||||
@@ -42,12 +40,8 @@ const VIRTIO_IOMMU_PHANDLE: u32 = 5;
|
||||
// NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
|
||||
// This is a value for uniquely identifying the FDT node containing the first vCPU.
|
||||
// The last number of vCPU phandle depends on the number of vCPUs.
|
||||
const FIRST_VCPU_PHANDLE: u32 = 8;
|
||||
const FIRST_VCPU_PHANDLE: u32 = 6;
|
||||
|
||||
// This is a value for uniquely identifying the FDT node containing the L2 cache info
|
||||
const L2_CACHE_PHANDLE: u32 = 6;
|
||||
// This is a value for uniquely identifying the FDT node containing the L3 cache info
|
||||
const L3_CACHE_PHANDLE: u32 = 7;
|
||||
// Read the documentation specified when appending the root node to the FDT.
|
||||
const ADDRESS_CELLS: u32 = 0x2;
|
||||
const SIZE_CELLS: u32 = 0x2;
|
||||
@@ -87,97 +81,6 @@ pub enum Error {
|
||||
}
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub enum CacheLevel {
|
||||
/// L1 data cache
|
||||
L1D = 0,
|
||||
/// L1 instruction cache
|
||||
L1I = 1,
|
||||
/// L2 cache
|
||||
L2 = 2,
|
||||
/// L3 cache
|
||||
L3 = 3,
|
||||
}
|
||||
|
||||
/// NOTE: CACHE SIZE file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/size".
|
||||
pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/size",
|
||||
CacheLevel::L1I => file_directory += "/index1/size",
|
||||
CacheLevel::L2 => file_directory += "/index2/size",
|
||||
CacheLevel::L3 => file_directory += "/index3/size",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
// The content of the file is as simple as a size, like: "32K"
|
||||
let src = src.trim();
|
||||
let src_digits: u32 = src[0..src.len() - 1].parse().unwrap();
|
||||
let src_unit = &src[src.len() - 1..];
|
||||
|
||||
src_digits
|
||||
* match src_unit {
|
||||
"K" => 1024,
|
||||
"M" => 1024u32.pow(2),
|
||||
"G" => 1024u32.pow(3),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: CACHE COHERENCY LINE SIZE file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size".
|
||||
pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/coherency_line_size",
|
||||
CacheLevel::L1I => file_directory += "/index1/coherency_line_size",
|
||||
CacheLevel::L2 => file_directory += "/index2/coherency_line_size",
|
||||
CacheLevel::L3 => file_directory += "/index3/coherency_line_size",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
src.trim().parse::<u32>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: CACHE NUMBER OF SETS file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/number_of_sets".
|
||||
pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/number_of_sets",
|
||||
CacheLevel::L1I => file_directory += "/index1/number_of_sets",
|
||||
CacheLevel::L2 => file_directory += "/index2/number_of_sets",
|
||||
CacheLevel::L3 => file_directory += "/index3/number_of_sets",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
src.trim().parse::<u32>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the flattened device tree for this aarch64 VM.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||
@@ -256,54 +159,6 @@ fn create_cpu_nodes(
|
||||
|
||||
let num_cpus = vcpu_mpidr.len();
|
||||
|
||||
// Add cache info.
|
||||
// L1 Data Cache Info.
|
||||
let mut l1_d_cache_size: u32 = 0;
|
||||
let mut l1_d_cache_line_size: u32 = 0;
|
||||
let mut l1_d_cache_sets: u32 = 0;
|
||||
|
||||
// L1 Instruction Cache Info.
|
||||
let mut l1_i_cache_size: u32 = 0;
|
||||
let mut l1_i_cache_line_size: u32 = 0;
|
||||
let mut l1_i_cache_sets: u32 = 0;
|
||||
|
||||
// L2 Cache Info.
|
||||
let mut l2_cache_size: u32 = 0;
|
||||
let mut l2_cache_line_size: u32 = 0;
|
||||
let mut l2_cache_sets: u32 = 0;
|
||||
|
||||
// L3 Cache Info.
|
||||
let mut l3_cache_size: u32 = 0;
|
||||
let mut l3_cache_line_size: u32 = 0;
|
||||
let mut l3_cache_sets: u32 = 0;
|
||||
|
||||
let cache_path = Path::new("/sys/devices/system/cpu/cpu0/cache");
|
||||
let cache_exist: bool = cache_path.exists();
|
||||
if !cache_exist {
|
||||
error!("cache sysfs system does not exist.");
|
||||
} else {
|
||||
info!("cache sysfs system exists.");
|
||||
// L1 Data Cache Info.
|
||||
l1_d_cache_size = get_cache_size(CacheLevel::L1D);
|
||||
l1_d_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1D);
|
||||
l1_d_cache_sets = get_cache_number_of_sets(CacheLevel::L1D);
|
||||
|
||||
// L1 Instruction Cache Info.
|
||||
l1_i_cache_size = get_cache_size(CacheLevel::L1I);
|
||||
l1_i_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1I);
|
||||
l1_i_cache_sets = get_cache_number_of_sets(CacheLevel::L1I);
|
||||
|
||||
// L2 Cache Info.
|
||||
l2_cache_size = get_cache_size(CacheLevel::L2);
|
||||
l2_cache_line_size = get_cache_coherency_line_size(CacheLevel::L2);
|
||||
l2_cache_sets = get_cache_number_of_sets(CacheLevel::L2);
|
||||
|
||||
// L3 Cache Info.
|
||||
l3_cache_size = get_cache_size(CacheLevel::L3);
|
||||
l3_cache_line_size = get_cache_coherency_line_size(CacheLevel::L3);
|
||||
l3_cache_sets = get_cache_number_of_sets(CacheLevel::L3);
|
||||
}
|
||||
|
||||
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
||||
let cpu_name = format!("cpu@{cpu_id:x}");
|
||||
let cpu_node = fdt.begin_node(&cpu_name)?;
|
||||
@@ -318,21 +173,6 @@ fn create_cpu_nodes(
|
||||
fdt.property_u32("reg", (mpidr & 0x7FFFFF) as u32)?;
|
||||
fdt.property_u32("phandle", cpu_id as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
|
||||
if cache_exist && l1_d_cache_size != 0 && l1_i_cache_size != 0 {
|
||||
// Add cache info.
|
||||
fdt.property_u32("d-cache-size", l1_d_cache_size)?;
|
||||
fdt.property_u32("d-cache-line-size", l1_d_cache_line_size)?;
|
||||
fdt.property_u32("d-cache-sets", l1_d_cache_sets)?;
|
||||
|
||||
fdt.property_u32("i-cache-size", l1_i_cache_size)?;
|
||||
fdt.property_u32("i-cache-line-size", l1_i_cache_line_size)?;
|
||||
fdt.property_u32("i-cache-sets", l1_i_cache_sets)?;
|
||||
|
||||
if l2_cache_size != 0 {
|
||||
fdt.property_u32("next-level-cache", L2_CACHE_PHANDLE)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Add `numa-node-id` property if there is any numa config.
|
||||
if numa_nodes.len() > 1 {
|
||||
for numa_node_idx in 0..numa_nodes.len() {
|
||||
@@ -346,36 +186,6 @@ fn create_cpu_nodes(
|
||||
fdt.end_node(cpu_node)?;
|
||||
}
|
||||
|
||||
if cache_exist && l2_cache_size != 0 {
|
||||
let l2_cache_name = "l2-cache0";
|
||||
let l2_cache_node = fdt.begin_node(l2_cache_name)?;
|
||||
fdt.property_u32("phandle", L2_CACHE_PHANDLE)?;
|
||||
fdt.property_string("compatible", "cache")?;
|
||||
fdt.property_u32("cache-size", l2_cache_size)?;
|
||||
fdt.property_u32("cache-line-size", l2_cache_line_size)?;
|
||||
fdt.property_u32("cache-sets", l2_cache_sets)?;
|
||||
fdt.property_u32("cache-level", 2)?;
|
||||
|
||||
if l3_cache_size != 0 {
|
||||
fdt.property_u32("next-level-cache", L3_CACHE_PHANDLE)?;
|
||||
}
|
||||
|
||||
fdt.end_node(l2_cache_node)?;
|
||||
}
|
||||
|
||||
if cache_exist && l3_cache_size != 0 {
|
||||
let l3_cache_name = "l3-cache0";
|
||||
let l3_cache_node = fdt.begin_node(l3_cache_name)?;
|
||||
fdt.property_u32("phandle", L3_CACHE_PHANDLE)?;
|
||||
fdt.property_string("compatible", "cache")?;
|
||||
fdt.property_null("cache-unified")?;
|
||||
fdt.property_u32("cache-size", l3_cache_size)?;
|
||||
fdt.property_u32("cache-line-size", l3_cache_line_size)?;
|
||||
fdt.property_u32("cache-sets", l3_cache_sets)?;
|
||||
fdt.property_u32("cache-level", 3)?;
|
||||
fdt.end_node(l3_cache_node)?;
|
||||
}
|
||||
|
||||
if let Some(topology) = vcpu_topology {
|
||||
let (threads_per_core, cores_per_package, packages) = topology;
|
||||
let cpu_map_node = fdt.begin_node("cpu-map")?;
|
||||
|
||||
@@ -180,8 +180,11 @@ pub fn initramfs_load_addr(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||
let host_cpu_phys_bits = hypervisor.get_host_ipa_limit().try_into().unwrap();
|
||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
// A dummy hypervisor created only for querying the host IPA size and will
|
||||
// be freed after the query.
|
||||
let hv = hypervisor::new().unwrap();
|
||||
let host_cpu_phys_bits = hv.get_host_ipa_limit().try_into().unwrap();
|
||||
if host_cpu_phys_bits == 0 {
|
||||
// Host kernel does not support `get_host_ipa_limit`,
|
||||
// we return the default value 40 here.
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::GuestMemoryMmap;
|
||||
use crate::InitramfsConfig;
|
||||
use crate::RegionType;
|
||||
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
|
||||
use hypervisor::{HypervisorCpuError, HypervisorError};
|
||||
use linux_loader::loader::bootparam::boot_params;
|
||||
use linux_loader::loader::elf::start_info::{
|
||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||
@@ -210,6 +210,7 @@ impl From<Error> for super::Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CpuidReg {
|
||||
EAX,
|
||||
@@ -1139,7 +1140,7 @@ pub fn initramfs_load_addr(
|
||||
Ok(aligned_addr)
|
||||
}
|
||||
|
||||
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
// SAFETY: call cpuid with valid leaves
|
||||
unsafe {
|
||||
let leaf = x86_64::__cpuid(0x8000_0000);
|
||||
@@ -1148,7 +1149,9 @@ pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u
|
||||
// Some physical address bits may become reserved when the feature is enabled.
|
||||
// See AMD64 Architecture Programmer's Manual Volume 2, Section 7.10.1
|
||||
let reduced = if leaf.eax >= 0x8000_001f
|
||||
&& matches!(hypervisor.get_cpu_vendor(), CpuVendor::AMD)
|
||||
&& leaf.ebx == 0x6874_7541 // Vendor ID: AuthenticAMD
|
||||
&& leaf.ecx == 0x444d_4163
|
||||
&& leaf.edx == 0x6974_6e65
|
||||
&& x86_64::__cpuid(0x8000_001f).eax & 0x1 != 0
|
||||
{
|
||||
(x86_64::__cpuid(0x8000_001f).ebx >> 6) & 0x3f
|
||||
|
||||
@@ -13,13 +13,13 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
qcow = { path = "../qcow" }
|
||||
smallvec = "1.10.0"
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.7.1"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
4
build.rs
4
build.rs
@@ -17,8 +17,8 @@ fn main() {
|
||||
}
|
||||
|
||||
// This println!() has a special behavior, as it will set the environment
|
||||
// variable BUILD_VERSION, so that it can be reused from the binary.
|
||||
// variable BUILT_VERSION, so that it can be reused from the binary.
|
||||
// Particularly, this is used from src/main.rs to display the exact
|
||||
// version.
|
||||
println!("cargo:rustc-env=BUILD_VERSION={version}");
|
||||
println!("cargo:rustc-env=BUILT_VERSION={version}");
|
||||
}
|
||||
|
||||
@@ -6,19 +6,19 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "2.3.3"
|
||||
bitflags = "1.3.2"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
tpm = { path = "../tpm" }
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@ impl Aml for AcpiGedDevice {
|
||||
true,
|
||||
self.address.0,
|
||||
self.address.0 + GED_DEVICE_ACPI_SIZE as u64 - 1,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
&aml::OpRegion::new(
|
||||
|
||||
158
docs/api.md
158
docs/api.md
@@ -1,21 +1,18 @@
|
||||
- [Cloud Hypervisor API](#cloud-hypervisor-api)
|
||||
- [External API](#external-api)
|
||||
- [REST API](#rest-api)
|
||||
- [REST API Location and availability](#rest-api-location-and-availability)
|
||||
- [REST API Endpoints](#rest-api-endpoints)
|
||||
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
|
||||
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
|
||||
- [REST API Examples](#rest-api-examples)
|
||||
- [Create a Virtual Machine](#create-a-virtual-machine)
|
||||
- [Boot a Virtual Machine](#boot-a-virtual-machine)
|
||||
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
|
||||
- [Reboot a Virtual Machine](#reboot-a-virtual-machine)
|
||||
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down)
|
||||
- [D-Bus API](#d-bus-api)
|
||||
- [D-Bus API Location and availability](#d-bus-api-location-and-availability)
|
||||
- [D-Bus API Interface](#d-bus-api-interface)
|
||||
- [Location and availability](#location-and-availability)
|
||||
- [Endpoints](#endpoints)
|
||||
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
|
||||
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
|
||||
- [REST API Examples](#rest-api-examples)
|
||||
- [Create a Virtual Machine](#create-a-virtual-machine)
|
||||
- [Boot a Virtual Machine](#boot-a-virtual-machine)
|
||||
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
|
||||
- [Reboot a Virtual Machine](#reboot-a-virtual-machine)
|
||||
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [REST API, D-Bus API and CLI Architectural Relationship](#rest-api-and-cli-architectural-relationship)
|
||||
- [REST API and CLI Architectural Relationship](#rest-api-and-cli-architectural-relationship)
|
||||
- [Internal API](#internal-api)
|
||||
- [Goals and Design](#goals-and-design)
|
||||
- [End to End Example](#end-to-end-example)
|
||||
@@ -24,11 +21,9 @@
|
||||
|
||||
The Cloud Hypervisor API is made of 2 distinct interfaces:
|
||||
|
||||
1. **The External API** This is the user facing API. Users and operators
|
||||
can control and manage the Cloud Hypervisor through various options
|
||||
including a REST API, a Command Line Interface (CLI) or a D-Bus based API,
|
||||
which is not compiled into Cloud Hypervisor by default.
|
||||
|
||||
1. **The external API**. This is the user facing API. Users and operators can
|
||||
control and manage Cloud Hypervisor through either a REST API or a Command
|
||||
Line Interface (CLI).
|
||||
1. **The internal API**, based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/)
|
||||
module. This API is used internally by the Cloud Hypervisor threads to
|
||||
communicate between each others.
|
||||
@@ -45,10 +40,10 @@ API triggers VM and VMM specific actions, and as such it is designed as a
|
||||
collection of RPC-style, static methods.
|
||||
|
||||
The API is [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
|
||||
compliant. Please consult the [Cloud Hypervisor OpenAPI Document](https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
|
||||
for more details about the API payloads and responses.
|
||||
compliant. Please consult the [Cloud Hypervisor API](https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
|
||||
document for more details about the API payloads and responses.
|
||||
|
||||
#### REST API Location and availability
|
||||
### Location and availability
|
||||
|
||||
The REST API is available as soon as the Cloud Hypervisor binary is started,
|
||||
through a local UNIX socket.
|
||||
@@ -70,18 +65,18 @@ Cloud Hypervisor Guest
|
||||
Disk(s): None
|
||||
```
|
||||
|
||||
#### REST API Endpoints
|
||||
### Endpoints
|
||||
|
||||
The Cloud Hypervisor API exposes the following actions through its endpoints:
|
||||
|
||||
##### Virtual Machine Manager (VMM) Actions
|
||||
#### Virtual Machine Manager (VMM) Actions
|
||||
|
||||
| Action | Endpoint | Request Body | Response Body | Prerequisites |
|
||||
| ----------------------------------- | --------------- | ------------ | -------------------------- | ------------------ |
|
||||
| Check for the REST API availability | `/vmm.ping` | N/A | `/schemas/VmmPingResponse` | N/A |
|
||||
| Shut the VMM down | `/vmm.shutdown` | N/A | N/A | The VMM is running |
|
||||
|
||||
##### Virtual Machine (VM) Actions
|
||||
#### Virtual Machine (VM) Actions
|
||||
|
||||
| Action | Endpoint | Request Body | Response Body | Prerequisites |
|
||||
| ---------------------------------- | ----------------------- | ------------------------------- | ------------------------ | ------------------------------------------------------ |
|
||||
@@ -115,10 +110,10 @@ The Cloud Hypervisor API exposes the following actions through its endpoints:
|
||||
|
||||
* The `vmcoredump` action is available exclusively for the `x86_64`
|
||||
architecture and can be executed only when the `guest_debug` feature is
|
||||
enabled. Without this feature, the corresponding [REST API](#rest-api) or
|
||||
[D-Bus API](#d-bus-api) endpoints are not available.
|
||||
enabled. Without this feature, the corresponding REST API endpoint is not
|
||||
available.
|
||||
|
||||
#### REST API Examples
|
||||
### REST API Examples
|
||||
|
||||
For the following set of examples, we assume Cloud Hypervisor is started with
|
||||
the REST API available at `/tmp/cloud-hypervisor.sock`:
|
||||
@@ -134,7 +129,7 @@ Cloud Hypervisor Guest
|
||||
Disk(s): None
|
||||
```
|
||||
|
||||
##### Create a Virtual Machine
|
||||
#### Create a Virtual Machine
|
||||
|
||||
We want to create a virtual machine with the following characteristics:
|
||||
|
||||
@@ -162,7 +157,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
}'
|
||||
```
|
||||
|
||||
##### Boot a Virtual Machine
|
||||
#### Boot a Virtual Machine
|
||||
|
||||
Once the VM is created, we can boot it:
|
||||
|
||||
@@ -172,7 +167,7 @@ Once the VM is created, we can boot it:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
|
||||
```
|
||||
|
||||
##### Dump a Virtual Machine Information
|
||||
#### Dump a Virtual Machine Information
|
||||
|
||||
We can fetch information about any VM, as soon as it's created:
|
||||
|
||||
@@ -184,7 +179,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
-H 'Accept: application/json'
|
||||
```
|
||||
|
||||
##### Reboot a Virtual Machine
|
||||
#### Reboot a Virtual Machine
|
||||
|
||||
We can reboot a VM that's already booted:
|
||||
|
||||
@@ -194,7 +189,7 @@ We can reboot a VM that's already booted:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
|
||||
```
|
||||
|
||||
##### Shut a Virtual Machine Down
|
||||
#### Shut a Virtual Machine Down
|
||||
|
||||
Once booted, we can shut a VM down from the REST API:
|
||||
|
||||
@@ -204,50 +199,6 @@ Once booted, we can shut a VM down from the REST API:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
|
||||
```
|
||||
|
||||
### D-Bus API
|
||||
|
||||
Cloud Hypervisor offers a D-Bus API as an alternative to its REST API. As of
|
||||
writing this document, the D-Bus API mirrors the functionality of the REST
|
||||
API and shares the same set of endpoints, meaning that it supports every call
|
||||
that is supported by the REST API and can be a drop-in replacement since it
|
||||
also consumes/produces JSON.
|
||||
|
||||
#### D-Bus API Location and availability
|
||||
|
||||
This feature is not compiled into Cloud Hypervisor by default. Users who
|
||||
wish to use the D-Bus API, must explicitly enable it with the `dbus_api`
|
||||
feature flag when compiling Cloud Hypervisor.
|
||||
|
||||
```sh
|
||||
$ ./scripts/dev_cli.sh build --release --libc musl -- --features dbus_api
|
||||
```
|
||||
|
||||
Once this feature is enabled, it can be configured with the following
|
||||
CLI options:
|
||||
|
||||
```
|
||||
--dbus-service-name
|
||||
well known name of the service
|
||||
--dbus-object-path
|
||||
object path to serve the dbus interface
|
||||
--dbus-system-bus use the system bus instead of a session bus
|
||||
```
|
||||
|
||||
Example invocation:
|
||||
|
||||
```sh
|
||||
$ ./cloud-hypervisor --dbus-service-name "org.cloudhypervisor.DBusApi" \
|
||||
--dbus-object-path "/org/cloudhypervisor/DBusApi"
|
||||
```
|
||||
|
||||
This will start serving a service with the name `org.cloudhypervisor.DBusApi1`
|
||||
which in turn can be used to control and manage Cloud Hypervisor.
|
||||
|
||||
#### D-Bus API Interface
|
||||
|
||||
Please refer to the [REST API](#rest-api) documentation. As previously
|
||||
mentioned, the D-Bus API currently mirrors the behaviour of the REST API.
|
||||
|
||||
### Command Line Interface
|
||||
|
||||
The Cloud Hypervisor Command Line Interface (CLI) can only be used for launching
|
||||
@@ -255,26 +206,22 @@ the Cloud Hypervisor binary, i.e. it can not be used for controlling the VMM or
|
||||
the launched VM once they're up and running.
|
||||
|
||||
If you want to inspect the VMM, or control the VM after launching Cloud
|
||||
Hypervisor from the CLI, you must use either the [REST API](#rest-api)
|
||||
or the [D-Bus API](#d-bus-api).
|
||||
Hypervisor from the CLI, you must use the [REST API](#rest-api).
|
||||
|
||||
From the CLI, one can:
|
||||
From the CLI, one can either:
|
||||
|
||||
1. Create and boot a complete virtual machine by using the CLI options to build
|
||||
the VM config. Run `cloud-hypervisor --help` for a complete list of CLI
|
||||
options. As soon as the `cloud-hypervisor` binary is launched, contrary
|
||||
to the [D-Bus API](#d-bus-api), the [REST API](#rest-api) is available
|
||||
for controlling and managing the VM. The [D-Bus API](#d-bus-api) doesn't start
|
||||
automatically and needs to be explicitly configured in order to be run.
|
||||
1. Start either the REST API, D-Bus API or both simultaneously without passing
|
||||
any VM configuration options. The VM can then be asynchronously created and
|
||||
booted by calling API methods of choice. It should be noted that one external
|
||||
API does not exclude another; it is possible to have both the REST and D-Bus
|
||||
APIs running simultaneously.
|
||||
options. As soon as the `cloud-hypervisor` binary is launched, the
|
||||
[REST API](#rest-api) is available for controlling and managing the VM.
|
||||
1. Start the [REST API](#rest-api) server only, by not passing any VM
|
||||
configuration options. The VM can then be asynchronously created and booted
|
||||
by sending HTTP commands to the [REST API](#rest-api). Check the
|
||||
[REST API examples](#rest-api-examples) section for more details.
|
||||
|
||||
### REST API, D-Bus API and CLI Architectural Relationship
|
||||
### REST API and CLI Architectural Relationship
|
||||
|
||||
The REST API, D-Bus API and the CLI all rely on a common, [internal API](#internal-api).
|
||||
The REST API and the CLI both rely on a common, [internal API](#internal-api).
|
||||
|
||||
The CLI options are parsed by the
|
||||
[argh crate](https://docs.rs/argh/latest/argh/) and then translated into
|
||||
@@ -285,11 +232,7 @@ The REST API is processed by an HTTP thread using the
|
||||
crate. As with the CLI, the HTTP requests eventually get translated into
|
||||
[internal API](#internal-api) commands.
|
||||
|
||||
The D-Bus API is implemented using the [zbus](https://github.com/dbus2/zbus)
|
||||
crate and runs in its own thread. Whenever it needs to call the [internal API](#internal-api),
|
||||
the [blocking](https://github.com/smol-rs/blocking) crate is used perform the call in zbus' async context.
|
||||
|
||||
As a summary, the REST API, the D-Bus API and the CLI are essentially frontends for the
|
||||
As a summary, the REST API and the CLI are essentially frontends for the
|
||||
[internal API](#internal-api):
|
||||
|
||||
```
|
||||
@@ -300,11 +243,11 @@ As a summary, the REST API, the D-Bus API and the CLI are essentially frontends
|
||||
| +------------------+ |
|
||||
| | +------------------------+
|
||||
| | | |
|
||||
+------------+ | +----------+ | | |
|
||||
| | | D-Bus API | | | | +--------------+ |
|
||||
| User +---------+----------->+ zbus +--------------+------> | Internal API | |
|
||||
| | | | | | | +--------------+ |
|
||||
+------------+ | +----------+ | | |
|
||||
+------------+ | | | |
|
||||
| | | | | +--------------+ |
|
||||
| User +---------+ +------> | Internal API | |
|
||||
| | | | | +--------------+ |
|
||||
+------------+ | | | |
|
||||
| | | |
|
||||
| | +------------------------+
|
||||
| +----------+ | VMM
|
||||
@@ -319,23 +262,22 @@ As a summary, the REST API, the D-Bus API and the CLI are essentially frontends
|
||||
## Internal API
|
||||
|
||||
The Cloud Hypervisor internal API, as its name suggests, is used internally
|
||||
by the different Cloud Hypervisor threads (VMM, HTTP, D-Bus, control loop,
|
||||
etc) to send commands and responses to each others.
|
||||
by the different Cloud Hypervisor threads (VMM, HTTP, control loop, etc) to
|
||||
send commands and responses to each others.
|
||||
|
||||
It is based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/),
|
||||
and the single consumer (a.k.a. the API receiver) is the Cloud Hypervisor
|
||||
control loop.
|
||||
|
||||
API producers are the HTTP thread handling the [REST API](#rest-api), the
|
||||
D-Bus thread handling the [D-Bus API](#d-bus-api) and the main thread that
|
||||
initially parses the [CLI](#command-line-interface).
|
||||
API producers are the HTTP thread handling the [REST API](#rest-api) and the
|
||||
main thread that initially parses the [CLI](#command-line-interface).
|
||||
|
||||
### Goals and Design
|
||||
|
||||
The internal API is designed for controlling, managing and inspecting a Cloud
|
||||
Hypervisor VMM and its guest. It is a backend for handling external, user
|
||||
visible requests through the [REST API](#rest-api), the [D-Bus API](#d-bus-api)
|
||||
or the [CLI](#command-line-interface) interfaces.
|
||||
visible requests through either the [REST API](#rest-api) or the
|
||||
[CLI](#command-line-interface) interfaces.
|
||||
|
||||
The API follows a command-response scheme that closely maps the [REST API](#rest-api).
|
||||
Any command must be replied to with a response.
|
||||
|
||||
@@ -225,7 +225,7 @@ Number Start End Size File system Name Flags
|
||||
|
||||
### Create a macvtap interface
|
||||
|
||||
Rely on the following [documentation](macvtap-bridge.md) to set up a
|
||||
Rely on the following [documentation](docs/macvtap-bridge.md) to set up a
|
||||
macvtap interface to provide your VM with proper connectivity.
|
||||
|
||||
### Boot the image
|
||||
|
||||
@@ -6,5 +6,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.139"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.95"
|
||||
|
||||
151
fuzz/Cargo.lock
generated
151
fuzz/Cargo.lock
generated
@@ -5,16 +5,16 @@ version = 3
|
||||
[[package]]
|
||||
name = "acpi_tables"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#05a609136387cc1cc9b499cee4320020325c263f"
|
||||
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#0b892e2c2053c4ecfac8d9e5a52babae75114702"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -100,12 +100,6 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
|
||||
|
||||
[[package]]
|
||||
name = "block_util"
|
||||
version = "0.1.0"
|
||||
@@ -119,7 +113,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vhdx",
|
||||
"virtio-bindings",
|
||||
"virtio-bindings 0.2.0",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
@@ -149,7 +143,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "32.0.0"
|
||||
version = "30.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -214,9 +208,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.1"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -224,27 +218,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.1"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.15",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.1"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -254,7 +248,7 @@ dependencies = [
|
||||
"acpi_tables",
|
||||
"anyhow",
|
||||
"arch",
|
||||
"bitflags 2.3.2",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"hypervisor",
|
||||
"libc",
|
||||
@@ -275,7 +269,7 @@ version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -302,9 +296,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -332,9 +326,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.19.0"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7cc8d38244d84278262c8ebe6930cc44283d194cbabae2651f6112103802fb5"
|
||||
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
@@ -351,7 +345,7 @@ version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -399,9 +393,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
version = "0.2.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@@ -416,18 +410,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.9.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d3adb7b28e189741eca3b1a4a27de0bf15e0907c9d4b0c74bd2d7d84ef72e08"
|
||||
checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
@@ -459,7 +456,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"virtio-bindings",
|
||||
"virtio-bindings 0.2.0",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
@@ -468,9 +465,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
@@ -501,9 +498,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -521,9 +518,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -545,7 +542,7 @@ checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -580,29 +577,29 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.164"
|
||||
version = "1.0.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.164"
|
||||
version = "1.0.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.99"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -611,9 +608,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.0.0"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
|
||||
checksum = "331bb8c3bf9b92457ab7abecf07078c13f7d270ba490103e84e8b014490cd0b0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_with_macros",
|
||||
@@ -621,14 +618,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.0.0"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"
|
||||
checksum = "859011bddcc11f289f07f467cc1fe01c7a941daa4d8f6c40d4d1c92eb6d9319c"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -679,9 +676,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -705,7 +702,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -734,15 +731,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.3.4"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81"
|
||||
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
@@ -777,7 +774,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#89f8e77dd1a2829197ecde65b686bafcc8a1def4"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -785,7 +782,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#89f8e77dd1a2829197ecde65b686bafcc8a1def4"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -801,9 +798,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#eef6bec4d421f08ed1688fe67c5ea33aabbf5069"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#afbbd5722885e961ce12baea12efe01d52ce14b0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags",
|
||||
"libc",
|
||||
"log",
|
||||
"serde",
|
||||
@@ -830,16 +827,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.7.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84f81f436bca4541f4d33172e1202882c9d437db34ed17fc6d84c8ff2bde21f5"
|
||||
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "virtio-bindings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
|
||||
|
||||
[[package]]
|
||||
name = "virtio-bindings"
|
||||
version = "0.2.0"
|
||||
@@ -871,7 +874,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vhost",
|
||||
"virtio-bindings",
|
||||
"virtio-bindings 0.2.0",
|
||||
"virtio-queue",
|
||||
"vm-allocator",
|
||||
"vm-device",
|
||||
@@ -883,12 +886,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-queue"
|
||||
version = "0.8.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91aebb1df33db33cbf04d4c2445e4f78d0b0c8e65acfd16a4ee95ef63ca252f8"
|
||||
checksum = "3ba81e2bcc21c0d2fc5e6683e79367e26ad219197423a498df801d79d5ba77bd"
|
||||
dependencies = [
|
||||
"log",
|
||||
"virtio-bindings",
|
||||
"virtio-bindings 0.1.0",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -922,9 +925,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.11.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6ea57fe00f9086c59eeeb68e102dd611686bc3c28520fa465996d4d4bdce07"
|
||||
checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -961,7 +964,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"arch",
|
||||
"bitflags 2.3.2",
|
||||
"bitflags",
|
||||
"block_util",
|
||||
"devices",
|
||||
"epoll",
|
||||
@@ -1006,7 +1009,7 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags",
|
||||
"libc",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
||||
@@ -12,20 +12,20 @@ cargo-fuzz = true
|
||||
block_util = { path = "../block_util" }
|
||||
devices = { path = "../devices" }
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.147"
|
||||
libc = "0.2.141"
|
||||
libfuzzer-sys = "0.4.6"
|
||||
linux-loader = { version = "0.9.0", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||
net_util = { path = "../net_util" }
|
||||
once_cell = "1.18.0"
|
||||
once_cell = "1.17.1"
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = "0.3.0"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = "0.8.0"
|
||||
virtio-queue = "0.7.1"
|
||||
vmm = { path = "../vmm" }
|
||||
vmm-sys-util = "0.11.1"
|
||||
vm-memory = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
|
||||
|
||||
@@ -11,23 +11,23 @@ mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
kvm-ioctls = { version = "0.13.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_with = { version = "3.0.0", default-features = false, features = ["macros"] }
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_with = { version = "2.3.1", default-features = false, features = ["macros"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
version = "1.19.0"
|
||||
version = "1.18.0"
|
||||
default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ pub const MTRR_MEM_TYPE_WB: u64 = 0x6;
|
||||
pub const NUM_IOAPIC_PINS: usize = 24;
|
||||
|
||||
// X86 Exceptions
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Exception {
|
||||
DE = 0, // Divide Error
|
||||
|
||||
@@ -21,15 +21,6 @@ use crate::MpState;
|
||||
use thiserror::Error;
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub enum CpuVendor {
|
||||
#[default]
|
||||
Unknown,
|
||||
Intel,
|
||||
AMD,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
///
|
||||
/// Enum for CPU error
|
||||
|
||||
@@ -9,14 +9,10 @@
|
||||
//
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86::CpuIdEntry;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::cpu::CpuVendor;
|
||||
#[cfg(feature = "tdx")]
|
||||
use crate::kvm::TdxCapabilities;
|
||||
use crate::vm::Vm;
|
||||
use crate::HypervisorType;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::x86_64;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -79,11 +75,6 @@ pub enum HypervisorError {
|
||||
///
|
||||
#[error("Failed to set partition property:{0}")]
|
||||
SetPartitionProperty(#[source] anyhow::Error),
|
||||
///
|
||||
/// Running on an unsupported CPU
|
||||
///
|
||||
#[error("Unsupported CPU:{0}")]
|
||||
UnsupportedCpu(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
///
|
||||
@@ -145,27 +136,4 @@ pub trait Hypervisor: Send + Sync {
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Determine CPU vendor
|
||||
///
|
||||
fn get_cpu_vendor(&self) -> CpuVendor {
|
||||
// SAFETY: call cpuid with valid leaves
|
||||
unsafe {
|
||||
let leaf = x86_64::__cpuid(0x0);
|
||||
|
||||
if leaf.ebx == 0x756e_6547 && leaf.ecx == 0x6c65_746e && leaf.edx == 0x4965_6e69 {
|
||||
// Vendor string GenuineIntel
|
||||
CpuVendor::Intel
|
||||
} else if leaf.ebx == 0x6874_7541 && leaf.ecx == 0x444d_4163 && leaf.edx == 0x6974_6e65
|
||||
{
|
||||
// Vendor string AuthenticAMD
|
||||
CpuVendor::AMD
|
||||
} else {
|
||||
// Not known yet, the corresponding manufacturer manual should contain the
|
||||
// necesssary info. See also https://wiki.osdev.org/CPUID#CPU_Vendor_ID_String
|
||||
CpuVendor::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +243,7 @@ impl KvmGicV3Its {
|
||||
}
|
||||
|
||||
/// Method to initialize the GIC device
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
|
||||
// This is inside KVM module
|
||||
let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
|
||||
|
||||
@@ -49,8 +49,6 @@ mod cpu;
|
||||
mod device;
|
||||
|
||||
pub use crate::hypervisor::{Hypervisor, HypervisorError};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use cpu::CpuVendor;
|
||||
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
|
||||
pub use device::HypervisorDeviceError;
|
||||
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
|
||||
|
||||
@@ -461,10 +461,10 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* Advance RIP and update RAX */
|
||||
let arr_reg_name_value = [
|
||||
(
|
||||
hv_register_name_HV_X64_REGISTER_RIP,
|
||||
hv_x64_register_name_HV_X64_REGISTER_RIP,
|
||||
info.header.rip + insn_len,
|
||||
),
|
||||
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
];
|
||||
set_registers_64!(self.fd, arr_reg_name_value)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||
@@ -510,10 +510,10 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* Advance RIP and update RAX */
|
||||
let arr_reg_name_value = [
|
||||
(
|
||||
hv_register_name_HV_X64_REGISTER_RIP,
|
||||
hv_x64_register_name_HV_X64_REGISTER_RIP,
|
||||
info.header.rip + insn_len,
|
||||
),
|
||||
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
];
|
||||
set_registers_64!(self.fd, arr_reg_name_value)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
impl<T> __IncompleteArrayField<T> {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
impl<T> __IncompleteArrayField<T> {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
#![allow(clippy::all)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
@@ -11,13 +11,13 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.164"
|
||||
thiserror = "1.0.40"
|
||||
serde = "1.0.151"
|
||||
thiserror = "1.0.39"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.7.1"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -25,4 +25,4 @@ vmm-sys-util = "0.11.0"
|
||||
once_cell = "1.17.1"
|
||||
pnet = "0.33.0"
|
||||
pnet_datalink = "0.33.0"
|
||||
serde_json = "1.0.96"
|
||||
serde_json = "1.0.95"
|
||||
|
||||
@@ -10,7 +10,7 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
|
||||
@@ -20,11 +20,11 @@ vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
thiserror = "1.0.40"
|
||||
serde = { version = "1.0.151", features = ["derive"] }
|
||||
thiserror = "1.0.39"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
@@ -452,9 +452,10 @@ impl From<PciBarType> for PciBarRegionType {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PciBarRegionType> for PciBarType {
|
||||
fn from(val: PciBarRegionType) -> Self {
|
||||
match val {
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<PciBarType> for PciBarRegionType {
|
||||
fn into(self) -> PciBarType {
|
||||
match self {
|
||||
PciBarRegionType::IoRegion => PciBarType::Io,
|
||||
PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
|
||||
PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
|
||||
@@ -468,9 +469,10 @@ pub enum PciBarPrefetchable {
|
||||
Prefetchable = 0x08,
|
||||
}
|
||||
|
||||
impl From<PciBarPrefetchable> for bool {
|
||||
fn from(val: PciBarPrefetchable) -> Self {
|
||||
match val {
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<bool> for PciBarPrefetchable {
|
||||
fn into(self) -> bool {
|
||||
match self {
|
||||
PciBarPrefetchable::NotPrefetchable => false,
|
||||
PciBarPrefetchable::Prefetchable => true,
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ build = "../build.rs"
|
||||
|
||||
[dependencies]
|
||||
argh = "0.1.9"
|
||||
dirs = "5.0.0"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
dirs = "4.0.0"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.95"
|
||||
test_infra = { path = "../test_infra" }
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -671,7 +671,7 @@ fn main() {
|
||||
let opts: Options = argh::from_env();
|
||||
|
||||
if opts.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,6 @@ impl QcowRawFile {
|
||||
pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
|
||||
for count in table {
|
||||
buffer.write_u16::<BigEndian>(*count)?;
|
||||
}
|
||||
|
||||
191
release-notes.md
191
release-notes.md
@@ -1,13 +1,4 @@
|
||||
- [v33.0](#v330)
|
||||
- [D-Bus based API](#d-bus-based-api)
|
||||
- [Passthrough CPU cache information for AArch64](#passthrough-cpu-cache-information-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v32.0](#v320)
|
||||
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
||||
- [API Changes](#api-changes)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v31.2](#v312)
|
||||
- [v31.1](#v311)
|
||||
- [v31.0](#v310)
|
||||
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
||||
@@ -15,15 +6,15 @@
|
||||
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
|
||||
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
|
||||
- [Documentation Improvements](#documentation-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v30.0](#v300)
|
||||
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
|
||||
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
|
||||
- [Heap Profiling Support](#heap-profiling-support)
|
||||
- [Documentation Improvements](#documentation-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v28.2](#v282)
|
||||
- [v29.0](#v290)
|
||||
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
|
||||
@@ -33,10 +24,10 @@
|
||||
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
|
||||
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
|
||||
- [TCP Offload Control](#tcp-offload-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Removals](#removals)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v28.1](#v281)
|
||||
- [v28.0](#v280)
|
||||
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
||||
@@ -44,9 +35,9 @@
|
||||
- [Virtualised TPM Support](#virtualised-tpm-support)
|
||||
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
||||
- [README Quick Start Improved](#readme-quick-start-improved)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Removals](#removals-1)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v27.0](#v270)
|
||||
- [Community Engagement](#community-engagement)
|
||||
- [Prebuilt Packages](#prebuilt-packages)
|
||||
@@ -55,41 +46,41 @@
|
||||
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
|
||||
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
|
||||
- [GDB Support for AArch64](#gdb-support-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v26.0](#v260)
|
||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
||||
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Deprecations](#deprecations-2)
|
||||
- [Removals](#removals-2)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v25.0](#v250)
|
||||
- [`ch-remote` Improvements](#ch-remote-improvements-1)
|
||||
- [VM "Coredump" Support](#vm-coredump-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Removals](#removals-3)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v24.0](#v240)
|
||||
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
||||
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
||||
- [Sparse Mmap support](#sparse-mmap-support)
|
||||
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Notable Improvements](#notable-improvements)
|
||||
- [Deprecations](#deprecations-3)
|
||||
- [New on the Website](#new-on-the-website)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v23.1](#v231)
|
||||
- [v23.0](#v230)
|
||||
- [vDPA Support](#vdpa-support)
|
||||
- [Updated OS Support list](#updated-os-support-list)
|
||||
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
||||
- [`AMX` Support](#amx-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Deprecations](#deprecations-4)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v22.1](#v221)
|
||||
- [v22.0](#v220)
|
||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||
@@ -100,13 +91,13 @@
|
||||
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
||||
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
||||
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v21.0](#v210)
|
||||
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
||||
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-12)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-10)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v20.2](#v202)
|
||||
- [v20.1](#v201)
|
||||
- [v20.0](#v200)
|
||||
@@ -115,8 +106,8 @@
|
||||
- [Improved VFIO support](#improved-vfio-support)
|
||||
- [Safer code](#safer-code)
|
||||
- [Extended documentation](#extended-documentation)
|
||||
- [Notable bug fixes](#notable-bug-fixes-13)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Notable bug fixes](#notable-bug-fixes-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v19.0](#v190)
|
||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||
@@ -124,8 +115,8 @@
|
||||
- [Live migration enhancements](#live-migration-enhancements)
|
||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||
- [Notable bug fixes](#notable-bug-fixes-14)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Notable bug fixes](#notable-bug-fixes-12)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v18.0](#v180)
|
||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||
@@ -135,23 +126,23 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes-15)
|
||||
- [Contributors](#contributors-15)
|
||||
- [Notable bug fixes](#notable-bug-fixes-13)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v17.0](#v170)
|
||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||
- [Improved SGX support](#improved-sgx-support)
|
||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||
- [Notable bug fixes](#notable-bug-fixes-16)
|
||||
- [Contributors](#contributors-16)
|
||||
- [Notable bug fixes](#notable-bug-fixes-14)
|
||||
- [Contributors](#contributors-14)
|
||||
- [v16.0](#v160)
|
||||
- [Improved live migration support](#improved-live-migration-support)
|
||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||
- [Notable bug fixes](#notable-bug-fixes-17)
|
||||
- [Notable bug fixes](#notable-bug-fixes-15)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-17)
|
||||
- [Contributors](#contributors-15)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -159,7 +150,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations-5)
|
||||
- [Contributors](#contributors-18)
|
||||
- [Contributors](#contributors-16)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -169,7 +160,7 @@
|
||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||
- [Block device rate limiting](#block-device-rate-limiting)
|
||||
- [Deprecations](#deprecations-6)
|
||||
- [Contributors](#contributors-19)
|
||||
- [Contributors](#contributors-17)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -177,13 +168,13 @@
|
||||
- [VHD disk image support](#vhd-disk-image-support)
|
||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||
- [Contributors](#contributors-20)
|
||||
- [Contributors](#contributors-18)
|
||||
- [v0.12.0](#v0120)
|
||||
- [ARM64 enhancements](#arm64-enhancements)
|
||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||
- [Enhanced "info" API](#enhanced-info-api)
|
||||
- [Contributors](#contributors-21)
|
||||
- [Contributors](#contributors-19)
|
||||
- [v0.11.0](#v0110)
|
||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||
- [Windows Guest Support](#windows-guest-support)
|
||||
@@ -195,15 +186,15 @@
|
||||
- [Default Log Level Changed](#default-log-level-changed)
|
||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-18)
|
||||
- [Contributors](#contributors-22)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-16)
|
||||
- [Contributors](#contributors-20)
|
||||
- [v0.10.0](#v0100)
|
||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||
- [Memory Zones](#memory-zones)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-19)
|
||||
- [Contributors](#contributors-23)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-17)
|
||||
- [Contributors](#contributors-21)
|
||||
- [v0.9.0](#v090)
|
||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||
@@ -216,17 +207,17 @@
|
||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||
- [Intel SGX Support](#intel-sgx-support)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-20)
|
||||
- [Contributors](#contributors-24)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-18)
|
||||
- [Contributors](#contributors-22)
|
||||
- [v0.8.0](#v080)
|
||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-21)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-19)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-25)
|
||||
- [Contributors](#contributors-23)
|
||||
- [v0.7.0](#v070)
|
||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||
- [Alternative `libc` Support](#alternative-libc-support)
|
||||
@@ -236,14 +227,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-26)
|
||||
- [Contributors](#contributors-24)
|
||||
- [v0.6.0](#v060)
|
||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [PVH Boot](#pvh-boot)
|
||||
- [Contributors](#contributors-27)
|
||||
- [Contributors](#contributors-25)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -251,7 +242,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-28)
|
||||
- [Contributors](#contributors-26)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -260,7 +251,7 @@
|
||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||
- [Contributors](#contributors-29)
|
||||
- [Contributors](#contributors-27)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -287,93 +278,23 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v33.0
|
||||
# v31.2
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v33.0. The following user visible changes have been made:
|
||||
|
||||
### D-Bus based API
|
||||
|
||||
A D-Bus based API has been added as an alternative to the existing REST
|
||||
API. This feature is gated by the `dbus_api` feature. Details can be
|
||||
found in the [API documentation](docs/api.md).
|
||||
|
||||
### Expose Host CPU Cache Details for AArch64
|
||||
|
||||
Now the CPU cache information on the host is properly exposed to the
|
||||
guest on AArch64.
|
||||
|
||||
### Notable Bug Fixes
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* The number of vCPUs is capped at the hypervisor maximum (#5357)
|
||||
* Fixes for TTY reset (#5414)
|
||||
* CPU topology fixes on MSHV (#5325)
|
||||
* Seccomp fixes for older distributions (#5397)
|
||||
* Report errors explicitly to users when VM failed to boot (#5453)
|
||||
* Fix VFIO on platforms with non-4k page size (#5450, #5469)
|
||||
* Fix TDX initialization (#5454)
|
||||
* Ensure all guest memory regions are page-size aligned (#5496)
|
||||
* Fix seccomp filter lists related to virtio-console, serial and pty
|
||||
(#5506, #5524)
|
||||
(#5506, #5524)
|
||||
* Populate APIC ID properly (#5512)
|
||||
* Ignore and warn TAP FDs in more situations (#5522)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Rafael Mendonca <rafaelmendsr@gmail.com>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Yu Li <liyu.yukiteru@bytedance.com>
|
||||
* zhongbingnan <zhongbingnan@bytedance.com>
|
||||
|
||||
# v32.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v32.0. The following user visible changes have been made:
|
||||
|
||||
### Increased PCI Segment Limit
|
||||
|
||||
The maximum number of PCI segments that can be used is now 96 (up from 16).
|
||||
|
||||
### API Changes
|
||||
|
||||
* The VmmPingResponse now includes the PID as well as the build details.
|
||||
(#5348)
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
|
||||
* Properly preserve and close valid FDs for TAP devices (#5373)
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Only touch the tty flags if it's being used (#5343)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
* The number of vCPUs is capped at the hypervisor maximum (#5357)
|
||||
* Fixes for TTY reset (#5414)
|
||||
* CPU topology fixes on MSHV (#5325)
|
||||
* Seccomp fixes for older distributions (#5397)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Hao Xu <howeyxu@tencent.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Rafael Mendonca <rafaelmendsr@gmail.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Smit Gardhariya <gardhariya.smit@gmail.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
|
||||
# v31.1
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
@@ -15,67 +15,58 @@ ARG CARGO_GIT_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_git_registry"
|
||||
ENV CARGO_HOME=/usr/local/rust
|
||||
ENV RUSTUP_HOME=$CARGO_HOME
|
||||
ENV PATH="$PATH:$CARGO_HOME/bin"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install all CI dependencies
|
||||
# DL3015 ignored cause not installing openvswitch-switch-dpdk recommended packages breaks ovs_dpdk test
|
||||
# hadolint ignore=DL3008,DL3015
|
||||
RUN apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
iproute2 \
|
||||
dbus \
|
||||
&& apt-get install openvswitch-switch-dpdk -yq \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
openvswitch-switch-dpdk \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq gcc-multilib gawk \
|
||||
libtool expect gnutls-dev gnutls-bin libfuse-dev \
|
||||
libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \
|
||||
net-tools softhsm2 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old; fi
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq gcc-multilib gawk \
|
||||
libtool expect gnutls-dev gnutls-bin libfuse-dev \
|
||||
libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \
|
||||
net-tools softhsm2 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# On AArch64, `setcap` binary should be installed via `libcap2-bin`.
|
||||
# The `setcap` binary is used in integration tests.
|
||||
@@ -83,7 +74,7 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# kernel (any version) image in `/boot` and modules in `/lib/modules`.
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
libcap2-bin \
|
||||
libguestfs-tools \
|
||||
linux-image-generic \
|
||||
@@ -93,12 +84,11 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
perl \
|
||||
texinfo \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old; fi
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
|
||||
# Fix the libssl-dev install
|
||||
# hadolint ignore=SC2155
|
||||
RUN export ARCH="$(uname -m)" \
|
||||
&& cp /usr/include/"$ARCH"-linux-gnu/openssl/opensslconf.h /usr/include/openssl/
|
||||
&& cp /usr/include/$ARCH-linux-gnu/openssl/opensslconf.h /usr/include/openssl/
|
||||
ENV X86_64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
ENV X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
ENV AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
|
||||
@@ -106,10 +96,9 @@ ENV AARCH64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
|
||||
ENV OPENSSL_INCLUDE_DIR=/usr/include/
|
||||
|
||||
# Install the rust toolchain
|
||||
# hadolint ignore=DL4006,SC2155
|
||||
RUN export ARCH="$(uname -m)" \
|
||||
&& nohup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN" \
|
||||
&& rustup target add "$ARCH"-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||
&& rustup target add $ARCH-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup toolchain add --profile minimal $RUST_TOOLCHAIN-x86_64-unknown-linux-musl; fi \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add rustfmt; fi \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \
|
||||
@@ -119,14 +108,12 @@ RUN export ARCH="$(uname -m)" \
|
||||
&& ln -s "$CARGO_GIT_REGISTRY_DIR" "$CARGO_HOME/git"
|
||||
|
||||
# Set the rust environment
|
||||
# hadolint ignore=SC2016
|
||||
RUN echo 'source $CARGO_HOME/env' >> "$HOME"/.bashrc \
|
||||
&& mkdir "$HOME"/.cargo \
|
||||
&& ln -s $CARGO_HOME/env "$HOME"/.cargo/env
|
||||
RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
|
||||
&& mkdir $HOME/.cargo \
|
||||
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
|
||||
|
||||
# install SPDK NVMe
|
||||
# only for 'x86_64' platform images as 'docker buildx' can't build 'spdk'
|
||||
# hadolint ignore=DL3003,SC2046
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/spdk/spdk \
|
||||
&& cd spdk \
|
||||
@@ -136,7 +123,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
&& ./scripts/pkgdep.sh \
|
||||
&& apt-get clean \
|
||||
&& ./configure --with-vfio-user \
|
||||
&& make -j $(nproc) \
|
||||
&& make -j `nproc` \
|
||||
&& mkdir /usr/local/bin/spdk-nvme \
|
||||
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
|
||||
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||
@@ -144,7 +131,6 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
&& cd .. && rm -rf spdk; fi
|
||||
|
||||
# install swtpm only for x86_64 arch
|
||||
# hadolint ignore=DL3003
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/stefanberger/libtpms libtpms_build \
|
||||
&& cd libtpms_build \
|
||||
@@ -165,7 +151,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
|
||||
# install ethr tool for performance tests
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
wget -nv https://github.com/microsoft/ethr/releases/latest/download/ethr_linux.zip \
|
||||
wget https://github.com/microsoft/ethr/releases/latest/download/ethr_linux.zip \
|
||||
&& unzip ethr_linux.zip \
|
||||
&& cp ethr /usr/local/bin \
|
||||
&& rm ethr_linux.zip; fi
|
||||
|
||||
@@ -3,7 +3,7 @@ set -x
|
||||
|
||||
rm -f /tmp/ubuntu-cloudinit.img
|
||||
mkdosfs -n CIDATA -C /tmp/ubuntu-cloudinit.img 8192
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/meta-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/network-config ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/meta-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/network-config ::
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
CLI_NAME="Cloud Hypervisor"
|
||||
|
||||
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
|
||||
CTR_IMAGE_VERSION="20230620-0"
|
||||
CTR_IMAGE_VERSION="20230316-0"
|
||||
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||
|
||||
DOCKER_RUNTIME="docker"
|
||||
@@ -426,7 +426,7 @@ cmd_tests() {
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
"$CTR_IMAGE" \
|
||||
dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
if [ "$integration_sgx" = true ]; then
|
||||
@@ -539,7 +539,6 @@ cmd_tests() {
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
@@ -225,8 +225,8 @@ fi
|
||||
|
||||
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
@@ -281,12 +281,4 @@ else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --features "dbus_api" --all --release --target $BUILD_TARGET
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test "dbus_api::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -42,8 +42,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
@@ -7,42 +7,9 @@ source $(dirname "$0")/test-util.sh
|
||||
process_common_args "$@"
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
if [ ! -f "$FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||
FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
|
||||
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
sha1sum sha1sums-x86_64 --check --ignore-missing
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
build_custom_linux
|
||||
@@ -64,7 +31,7 @@ VFIO_DIR="$WORKLOADS_DIR/vfio"
|
||||
VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img"
|
||||
rm -rf $VFIO_DIR $VFIO_DISK_IMAGE
|
||||
mkdir -p $VFIO_DIR
|
||||
cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR
|
||||
cp $FOCAL_OS_IMAGE $VFIO_DIR
|
||||
cp $FW $VFIO_DIR
|
||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -26,8 +26,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -189,13 +189,4 @@ if [ $RES -eq 0 ]; then
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --no-default-features --features "kvm,mshv,dbus_api" --all --release --target $BUILD_TARGET
|
||||
export RUST_BACKTRACE=1
|
||||
# integration tests now do not reply on build feature "dbus_api"
|
||||
time cargo test $test_features "dbus_api::$test_filter" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -107,12 +107,7 @@ fi
|
||||
# Ensure that git commands can be run in this directory (for metrics report)
|
||||
git config --global --add safe.directory $PWD
|
||||
|
||||
RUST_BACKTRACE_VALUE=`echo $RUST_BACKTRACE`
|
||||
if [ -z $RUST_BACKTRACE_VALUE ];then
|
||||
export RUST_BACKTRACE=1
|
||||
else
|
||||
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
|
||||
fi
|
||||
export RUST_BACKTRACE=1
|
||||
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
|
||||
@@ -3,3 +3,4 @@ f1eccdc5e1b515dbad294426ab081b47ebfb97c0 focal-server-cloudimg-amd64-custom-2021
|
||||
7f5a8358243a96adf61f5c20139b29f308f2c0e3 focal-server-cloudimg-amd64-custom-20210609-0.raw
|
||||
864c074e2f1bd753667a35188b510d83a1d62793 jammy-server-cloudimg-amd64-custom-20230119-0.qcow2
|
||||
24358ee053f94e7f710ea4ce9e7a63eff2a1eb25 jammy-server-cloudimg-amd64-custom-20230119-0.raw
|
||||
|
||||
|
||||
@@ -11,19 +11,13 @@ use argh::FromArgs;
|
||||
use option_parser::{ByteSized, ByteSizedParseError};
|
||||
use std::fmt;
|
||||
use std::io::Read;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::process;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use zbus::{dbus_proxy, zvariant::Optional};
|
||||
|
||||
type ApiResult = Result<(), Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
HttpApiClient(ApiClientError),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApiClient(zbus::Error),
|
||||
Connect(std::io::Error),
|
||||
ApiClient(ApiClientError),
|
||||
InvalidMemorySize(ByteSizedParseError),
|
||||
InvalidBalloonSize(ByteSizedParseError),
|
||||
AddDeviceConfig(vmm::config::Error),
|
||||
@@ -43,9 +37,8 @@ impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Error::*;
|
||||
match self {
|
||||
HttpApiClient(e) => e.fmt(f),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApiClient(e) => write!(f, "Error D-Bus proxy: {e}"),
|
||||
ApiClient(e) => e.fmt(f),
|
||||
Connect(e) => write!(f, "Error opening HTTP socket: {e}"),
|
||||
InvalidMemorySize(e) => write!(f, "Error parsing memory size: {e:?}"),
|
||||
InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {e:?}"),
|
||||
AddDeviceConfig(e) => write!(f, "Error parsing device syntax: {e}"),
|
||||
@@ -63,430 +56,12 @@ impl fmt::Display for Error {
|
||||
}
|
||||
}
|
||||
|
||||
enum TargetApi<'a> {
|
||||
HttpApi(UnixStream, PhantomData<&'a ()>),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApi(DBusApi1ProxyBlocking<'a>),
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[dbus_proxy(name = "org.cloudhypervisor.DBusApi1", assume_defaults = false)]
|
||||
trait DBusApi1 {
|
||||
fn vmm_ping(&self) -> zbus::Result<String>;
|
||||
fn vmm_shutdown(&self) -> zbus::Result<()>;
|
||||
fn vm_add_device(&self, device_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_disk(&self, disk_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_fs(&self, fs_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_net(&self, net_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_pmem(&self, pmem_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_user_device(&self, vm_add_user_device: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_vdpa(&self, vdpa_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_vsock(&self, vsock_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_boot(&self) -> zbus::Result<()>;
|
||||
fn vm_coredump(&self, vm_coredump_data: &str) -> zbus::Result<()>;
|
||||
fn vm_counters(&self) -> zbus::Result<Optional<String>>;
|
||||
fn vm_create(&self, vm_config: &str) -> zbus::Result<()>;
|
||||
fn vm_delete(&self) -> zbus::Result<()>;
|
||||
fn vm_info(&self) -> zbus::Result<String>;
|
||||
fn vm_pause(&self) -> zbus::Result<()>;
|
||||
fn vm_power_button(&self) -> zbus::Result<()>;
|
||||
fn vm_reboot(&self) -> zbus::Result<()>;
|
||||
fn vm_remove_device(&self, vm_remove_device: &str) -> zbus::Result<()>;
|
||||
fn vm_resize(&self, vm_resize: &str) -> zbus::Result<()>;
|
||||
fn vm_resize_zone(&self, vm_resize_zone: &str) -> zbus::Result<()>;
|
||||
fn vm_restore(&self, restore_config: &str) -> zbus::Result<()>;
|
||||
fn vm_receive_migration(&self, receive_migration_data: &str) -> zbus::Result<()>;
|
||||
fn vm_send_migration(&self, receive_migration_data: &str) -> zbus::Result<()>;
|
||||
fn vm_resume(&self) -> zbus::Result<()>;
|
||||
fn vm_shutdown(&self) -> zbus::Result<()>;
|
||||
fn vm_snapshot(&self, vm_snapshot_config: &str) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
impl<'a> DBusApi1ProxyBlocking<'a> {
|
||||
fn new_connection(name: &'a str, path: &'a str, system_bus: bool) -> Result<Self, zbus::Error> {
|
||||
let connection = if system_bus {
|
||||
zbus::blocking::Connection::system()?
|
||||
} else {
|
||||
zbus::blocking::Connection::session()?
|
||||
};
|
||||
|
||||
Self::builder(&connection)
|
||||
.destination(name)?
|
||||
.path(path)?
|
||||
.build()
|
||||
}
|
||||
|
||||
fn print_response(&self, result: zbus::Result<Optional<String>>) -> ApiResult {
|
||||
result
|
||||
.map(|ret| {
|
||||
if let Some(ref output) = *ret {
|
||||
println!("{output}");
|
||||
}
|
||||
})
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vmm_ping(&self) -> ApiResult {
|
||||
self.vmm_ping()
|
||||
.map(|ping| println!("{ping}"))
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vmm_shutdown(&self) -> ApiResult {
|
||||
self.vmm_shutdown().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_add_device(&self, device_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_device(device_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_disk(&self, disk_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_disk(disk_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_fs(&self, fs_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_fs(fs_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_net(&self, net_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_net(net_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_pmem(&self, pmem_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_pmem(pmem_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_user_device(&self, vm_add_user_device: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_user_device(vm_add_user_device))
|
||||
}
|
||||
|
||||
fn api_vm_add_vdpa(&self, vdpa_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_vdpa(vdpa_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_vsock(&self, vsock_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_vsock(vsock_config))
|
||||
}
|
||||
|
||||
fn api_vm_boot(&self) -> ApiResult {
|
||||
self.vm_boot().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_coredump(&self, vm_coredump_data: &str) -> ApiResult {
|
||||
self.vm_coredump(vm_coredump_data)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_counters(&self) -> ApiResult {
|
||||
self.print_response(self.vm_counters())
|
||||
}
|
||||
|
||||
fn api_vm_create(&self, vm_config: &str) -> ApiResult {
|
||||
self.vm_create(vm_config).map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_delete(&self) -> ApiResult {
|
||||
self.vm_delete().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_info(&self) -> ApiResult {
|
||||
self.vm_info()
|
||||
.map(|info| println!("{info}"))
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_pause(&self) -> ApiResult {
|
||||
self.vm_pause().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_power_button(&self) -> ApiResult {
|
||||
self.vm_power_button().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_reboot(&self) -> ApiResult {
|
||||
self.vm_reboot().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_remove_device(&self, vm_remove_device: &str) -> ApiResult {
|
||||
self.vm_remove_device(vm_remove_device)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_resize(&self, vm_resize: &str) -> ApiResult {
|
||||
self.vm_resize(vm_resize).map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_resize_zone(&self, vm_resize_zone: &str) -> ApiResult {
|
||||
self.vm_resize_zone(vm_resize_zone)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_restore(&self, restore_config: &str) -> ApiResult {
|
||||
self.vm_restore(restore_config)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_receive_migration(&self, receive_migration_data: &str) -> ApiResult {
|
||||
self.vm_receive_migration(receive_migration_data)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_send_migration(&self, send_migration_data: &str) -> ApiResult {
|
||||
self.vm_send_migration(send_migration_data)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_resume(&self) -> ApiResult {
|
||||
self.vm_resume().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_shutdown(&self) -> ApiResult {
|
||||
self.vm_shutdown().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_snapshot(&self, vm_snapshot_config: &str) -> ApiResult {
|
||||
self.vm_snapshot(vm_snapshot_config)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TargetApi<'a> {
|
||||
fn do_command(&mut self, toplevel: &TopLevel) -> ApiResult {
|
||||
match self {
|
||||
Self::HttpApi(api_socket, _) => rest_api_do_command(toplevel, api_socket),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
Self::DBusApi(proxy) => dbus_api_do_command(toplevel, proxy),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rest_api_do_command(toplevel: &TopLevel, socket: &mut UnixStream) -> ApiResult {
|
||||
match toplevel.command {
|
||||
SubCommandEnum::Boot(_) => {
|
||||
simple_api_command(socket, "PUT", "boot", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Delete(_) => {
|
||||
simple_api_command(socket, "PUT", "delete", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::ShutdownVmm(_) => {
|
||||
simple_api_full_command(socket, "PUT", "vmm.shutdown", None)
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Resume(_) => {
|
||||
simple_api_command(socket, "PUT", "resume", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::PowerButton(_) => {
|
||||
simple_api_command(socket, "PUT", "power-button", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Reboot(_) => {
|
||||
simple_api_command(socket, "PUT", "reboot", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Pause(_) => {
|
||||
simple_api_command(socket, "PUT", "pause", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Info(_) => {
|
||||
simple_api_command(socket, "GET", "info", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Counters(_) => {
|
||||
simple_api_command(socket, "GET", "counters", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Ping(_) => {
|
||||
simple_api_full_command(socket, "GET", "vmm.ping", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Shutdown(_) => {
|
||||
simple_api_command(socket, "PUT", "shutdown", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Resize(ref config) => {
|
||||
let resize = resize_config(config.cpus, &config.memory, &config.balloon)?;
|
||||
simple_api_command(socket, "PUT", "resize", Some(&resize)).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::ResizeZone(ref config) => {
|
||||
let resize_zone = resize_zone_config(&config.id, &config.size)?;
|
||||
simple_api_command(socket, "PUT", "resize-zone", Some(&resize_zone))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddDevice(ref config) => {
|
||||
let device_config = add_device_config(&config.device_config)?;
|
||||
simple_api_command(socket, "PUT", "add-device", Some(&device_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::RemoveDevice(ref config) => {
|
||||
let remove_device_data = remove_device_config(&config.device_config);
|
||||
simple_api_command(socket, "PUT", "remove-device", Some(&remove_device_data))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddDisk(ref config) => {
|
||||
let disk_config = add_disk_config(&config.disk_config)?;
|
||||
simple_api_command(socket, "PUT", "add-disk", Some(&disk_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddFs(ref config) => {
|
||||
let fs_config = add_fs_config(&config.fs_config)?;
|
||||
simple_api_command(socket, "PUT", "add-fs", Some(&fs_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddPmem(ref config) => {
|
||||
let pmem_config = add_pmem_config(&config.pmem_config)?;
|
||||
simple_api_command(socket, "PUT", "add-pmem", Some(&pmem_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddNet(ref config) => {
|
||||
let (net_config, fds) = add_net_config(&config.net_config)?;
|
||||
simple_api_command_with_fds(socket, "PUT", "add-net", Some(&net_config), fds)
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddUserDevice(ref config) => {
|
||||
let device_config = add_user_device_config(&config.device_config)?;
|
||||
simple_api_command(socket, "PUT", "add-user-device", Some(&device_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddVdpa(ref config) => {
|
||||
let vdpa_config = add_vdpa_config(&config.vdpa_config)?;
|
||||
simple_api_command(socket, "PUT", "add-vdpa", Some(&vdpa_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddVsock(ref config) => {
|
||||
let vsock_config = add_vsock_config(&config.vsock_config)?;
|
||||
simple_api_command(socket, "PUT", "add-vsock", Some(&vsock_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Snapshot(ref config) => {
|
||||
let snapshot_config = snapshot_api_config(&config.snapshot_config);
|
||||
simple_api_command(socket, "PUT", "snapshot", Some(&snapshot_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Restore(ref config) => {
|
||||
let restore_config = restore_config(&config.restore_config)?;
|
||||
simple_api_command(socket, "PUT", "restore", Some(&restore_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Coredump(ref config) => {
|
||||
let coredump_config = coredump_config(&config.coredump_config);
|
||||
simple_api_command(socket, "PUT", "coredump", Some(&coredump_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::SendMigration(ref config) => {
|
||||
let send_migration_data =
|
||||
send_migration_data(&config.send_migration_config, config.send_migration_local);
|
||||
simple_api_command(socket, "PUT", "send-migration", Some(&send_migration_data))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::ReceiveMigration(ref config) => {
|
||||
let receive_migration_data = receive_migration_data(&config.receive_migration_config);
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"receive-migration",
|
||||
Some(&receive_migration_data),
|
||||
)
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Create(ref config) => {
|
||||
let data = create_data(&config.vm_config)?;
|
||||
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Version(_) => {
|
||||
// Already handled outside of this function
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
fn dbus_api_do_command(toplevel: &TopLevel, proxy: &mut DBusApi1ProxyBlocking<'_>) -> ApiResult {
|
||||
match toplevel.command {
|
||||
SubCommandEnum::Boot(_) => proxy.api_vm_boot(),
|
||||
SubCommandEnum::Delete(_) => proxy.api_vm_delete(),
|
||||
SubCommandEnum::ShutdownVmm(_) => proxy.api_vmm_shutdown(),
|
||||
SubCommandEnum::Resume(_) => proxy.api_vm_resume(),
|
||||
SubCommandEnum::PowerButton(_) => proxy.api_vm_power_button(),
|
||||
SubCommandEnum::Reboot(_) => proxy.api_vm_reboot(),
|
||||
SubCommandEnum::Pause(_) => proxy.api_vm_pause(),
|
||||
SubCommandEnum::Info(_) => proxy.api_vm_info(),
|
||||
SubCommandEnum::Counters(_) => proxy.api_vm_counters(),
|
||||
SubCommandEnum::Ping(_) => proxy.api_vmm_ping(),
|
||||
SubCommandEnum::Shutdown(_) => proxy.api_vm_shutdown(),
|
||||
SubCommandEnum::Resize(ref config) => {
|
||||
let resize = resize_config(config.cpus, &config.memory, &config.balloon)?;
|
||||
proxy.api_vm_resize(&resize)
|
||||
}
|
||||
SubCommandEnum::ResizeZone(ref config) => {
|
||||
let resize_zone = resize_zone_config(&config.id, &config.size)?;
|
||||
proxy.api_vm_resize_zone(&resize_zone)
|
||||
}
|
||||
SubCommandEnum::AddDevice(ref config) => {
|
||||
let device_config = add_device_config(&config.device_config)?;
|
||||
proxy.api_vm_add_device(&device_config)
|
||||
}
|
||||
SubCommandEnum::RemoveDevice(ref config) => {
|
||||
let remove_device_data = remove_device_config(&config.device_config);
|
||||
proxy.api_vm_remove_device(&remove_device_data)
|
||||
}
|
||||
SubCommandEnum::AddDisk(ref config) => {
|
||||
let disk_config = add_disk_config(&config.disk_config)?;
|
||||
proxy.api_vm_add_disk(&disk_config)
|
||||
}
|
||||
SubCommandEnum::AddFs(ref config) => {
|
||||
let fs_config = add_fs_config(&config.fs_config)?;
|
||||
proxy.api_vm_add_fs(&fs_config)
|
||||
}
|
||||
SubCommandEnum::AddPmem(ref config) => {
|
||||
let pmem_config = add_pmem_config(&config.pmem_config)?;
|
||||
proxy.api_vm_add_pmem(&pmem_config)
|
||||
}
|
||||
SubCommandEnum::AddNet(ref config) => {
|
||||
let (net_config, _fds) = add_net_config(&config.net_config)?;
|
||||
proxy.api_vm_add_net(&net_config)
|
||||
}
|
||||
SubCommandEnum::AddUserDevice(ref config) => {
|
||||
let device_config = add_user_device_config(&config.device_config)?;
|
||||
proxy.api_vm_add_user_device(&device_config)
|
||||
}
|
||||
SubCommandEnum::AddVdpa(ref config) => {
|
||||
let vdpa_config = add_vdpa_config(&config.vdpa_config)?;
|
||||
proxy.api_vm_add_vdpa(&vdpa_config)
|
||||
}
|
||||
SubCommandEnum::AddVsock(ref config) => {
|
||||
let vsock_config = add_vsock_config(&config.vsock_config)?;
|
||||
proxy.api_vm_add_vsock(&vsock_config)
|
||||
}
|
||||
SubCommandEnum::Snapshot(ref config) => {
|
||||
let snapshot_config = snapshot_api_config(&config.snapshot_config);
|
||||
proxy.api_vm_snapshot(&snapshot_config)
|
||||
}
|
||||
SubCommandEnum::Restore(ref config) => {
|
||||
let restore_config = restore_config(&config.restore_config)?;
|
||||
proxy.api_vm_restore(&restore_config)
|
||||
}
|
||||
SubCommandEnum::Coredump(ref config) => {
|
||||
let coredump_config = coredump_config(&config.coredump_config);
|
||||
proxy.api_vm_coredump(&coredump_config)
|
||||
}
|
||||
SubCommandEnum::SendMigration(ref config) => {
|
||||
let send_migration_data =
|
||||
send_migration_data(&config.send_migration_config, config.send_migration_local);
|
||||
proxy.api_vm_send_migration(&send_migration_data)
|
||||
}
|
||||
SubCommandEnum::ReceiveMigration(ref config) => {
|
||||
let receive_migration_data = receive_migration_data(&config.receive_migration_config);
|
||||
proxy.api_vm_receive_migration(&receive_migration_data)
|
||||
}
|
||||
SubCommandEnum::Create(ref config) => {
|
||||
let data = create_data(&config.vm_config)?;
|
||||
proxy.api_vm_create(&data)
|
||||
}
|
||||
SubCommandEnum::Version(_) => {
|
||||
// Already handled outside of this function
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
fn resize_config(
|
||||
fn resize_api_command(
|
||||
socket: &mut UnixStream,
|
||||
desired_vcpus: Option<u8>,
|
||||
memory: &Option<String>,
|
||||
balloon: &Option<String>,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<(), Error> {
|
||||
let desired_ram: Option<u64> = if let Some(memory) = memory {
|
||||
Some(
|
||||
memory
|
||||
@@ -515,10 +90,16 @@ fn resize_config(
|
||||
desired_balloon,
|
||||
};
|
||||
|
||||
Ok(serde_json::to_string(&resize).unwrap())
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"resize",
|
||||
Some(&serde_json::to_string(&resize).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn resize_zone_config(id: &str, size: &str) -> Result<String, Error> {
|
||||
fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Result<(), Error> {
|
||||
let resize_zone = vmm::api::VmResizeZoneData {
|
||||
id: id.to_owned(),
|
||||
desired_ram: size
|
||||
@@ -527,52 +108,89 @@ fn resize_zone_config(id: &str, size: &str) -> Result<String, Error> {
|
||||
.0,
|
||||
};
|
||||
|
||||
Ok(serde_json::to_string(&resize_zone).unwrap())
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"resize-zone",
|
||||
Some(&serde_json::to_string(&resize_zone).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_device_config(config: &str) -> Result<String, Error> {
|
||||
fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let device_config = vmm::config::DeviceConfig::parse(config).map_err(Error::AddDeviceConfig)?;
|
||||
let device_config = serde_json::to_string(&device_config).unwrap();
|
||||
|
||||
Ok(device_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-device",
|
||||
Some(&serde_json::to_string(&device_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_user_device_config(config: &str) -> Result<String, Error> {
|
||||
fn add_user_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let device_config =
|
||||
vmm::config::UserDeviceConfig::parse(config).map_err(Error::AddUserDeviceConfig)?;
|
||||
let device_config = serde_json::to_string(&device_config).unwrap();
|
||||
|
||||
Ok(device_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-user-device",
|
||||
Some(&serde_json::to_string(&device_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn remove_device_config(id: &str) -> String {
|
||||
fn remove_device_api_command(socket: &mut UnixStream, id: &str) -> Result<(), Error> {
|
||||
let remove_device_data = vmm::api::VmRemoveDeviceData { id: id.to_owned() };
|
||||
|
||||
serde_json::to_string(&remove_device_data).unwrap()
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"remove-device",
|
||||
Some(&serde_json::to_string(&remove_device_data).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_disk_config(config: &str) -> Result<String, Error> {
|
||||
fn add_disk_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let disk_config = vmm::config::DiskConfig::parse(config).map_err(Error::AddDiskConfig)?;
|
||||
let disk_config = serde_json::to_string(&disk_config).unwrap();
|
||||
|
||||
Ok(disk_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-disk",
|
||||
Some(&serde_json::to_string(&disk_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_fs_config(config: &str) -> Result<String, Error> {
|
||||
fn add_fs_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let fs_config = vmm::config::FsConfig::parse(config).map_err(Error::AddFsConfig)?;
|
||||
let fs_config = serde_json::to_string(&fs_config).unwrap();
|
||||
|
||||
Ok(fs_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-fs",
|
||||
Some(&serde_json::to_string(&fs_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_pmem_config(config: &str) -> Result<String, Error> {
|
||||
fn add_pmem_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let pmem_config = vmm::config::PmemConfig::parse(config).map_err(Error::AddPmemConfig)?;
|
||||
let pmem_config = serde_json::to_string(&pmem_config).unwrap();
|
||||
|
||||
Ok(pmem_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-pmem",
|
||||
Some(&serde_json::to_string(&pmem_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_net_config(config: &str) -> Result<(String, Vec<i32>), Error> {
|
||||
fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let mut net_config = vmm::config::NetConfig::parse(config).map_err(Error::AddNetConfig)?;
|
||||
|
||||
// NetConfig is modified on purpose here by taking the list of file
|
||||
@@ -580,66 +198,113 @@ fn add_net_config(config: &str) -> Result<(String, Vec<i32>), Error> {
|
||||
// process would not make any sense since the file descriptor may be
|
||||
// represented with different values.
|
||||
let fds = net_config.fds.take().unwrap_or_default();
|
||||
let net_config = serde_json::to_string(&net_config).unwrap();
|
||||
|
||||
Ok((net_config, fds))
|
||||
simple_api_command_with_fds(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-net",
|
||||
Some(&serde_json::to_string(&net_config).unwrap()),
|
||||
fds,
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_vdpa_config(config: &str) -> Result<String, Error> {
|
||||
fn add_vdpa_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let vdpa_config = vmm::config::VdpaConfig::parse(config).map_err(Error::AddVdpaConfig)?;
|
||||
let vdpa_config = serde_json::to_string(&vdpa_config).unwrap();
|
||||
|
||||
Ok(vdpa_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-vdpa",
|
||||
Some(&serde_json::to_string(&vdpa_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_vsock_config(config: &str) -> Result<String, Error> {
|
||||
fn add_vsock_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let vsock_config = vmm::config::VsockConfig::parse(config).map_err(Error::AddVsockConfig)?;
|
||||
let vsock_config = serde_json::to_string(&vsock_config).unwrap();
|
||||
|
||||
Ok(vsock_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-vsock",
|
||||
Some(&serde_json::to_string(&vsock_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn snapshot_api_config(url: &str) -> String {
|
||||
fn snapshot_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||
let snapshot_config = vmm::api::VmSnapshotConfig {
|
||||
destination_url: String::from(url),
|
||||
};
|
||||
|
||||
serde_json::to_string(&snapshot_config).unwrap()
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"snapshot",
|
||||
Some(&serde_json::to_string(&snapshot_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn restore_config(config: &str) -> Result<String, Error> {
|
||||
fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let restore_config = vmm::config::RestoreConfig::parse(config).map_err(Error::Restore)?;
|
||||
let restore_config = serde_json::to_string(&restore_config).unwrap();
|
||||
|
||||
Ok(restore_config)
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"restore",
|
||||
Some(&serde_json::to_string(&restore_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn coredump_config(destination_url: &str) -> String {
|
||||
fn coredump_api_command(socket: &mut UnixStream, destination_url: &str) -> Result<(), Error> {
|
||||
let coredump_config = vmm::api::VmCoredumpData {
|
||||
destination_url: String::from(destination_url),
|
||||
};
|
||||
|
||||
serde_json::to_string(&coredump_config).unwrap()
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"coredump",
|
||||
Some(&serde_json::to_string(&coredump_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn receive_migration_data(url: &str) -> String {
|
||||
fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||
let receive_migration_data = vmm::api::VmReceiveMigrationData {
|
||||
receiver_url: url.to_owned(),
|
||||
};
|
||||
|
||||
serde_json::to_string(&receive_migration_data).unwrap()
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"receive-migration",
|
||||
Some(&serde_json::to_string(&receive_migration_data).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn send_migration_data(url: &str, local: bool) -> String {
|
||||
fn send_migration_api_command(
|
||||
socket: &mut UnixStream,
|
||||
url: &str,
|
||||
local: bool,
|
||||
) -> Result<(), Error> {
|
||||
let send_migration_data = vmm::api::VmSendMigrationData {
|
||||
destination_url: url.to_owned(),
|
||||
local,
|
||||
};
|
||||
|
||||
serde_json::to_string(&send_migration_data).unwrap()
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"send-migration",
|
||||
Some(&serde_json::to_string(&send_migration_data).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn create_data(path: &str) -> Result<String, Error> {
|
||||
fn create_api_command(socket: &mut UnixStream, path: &str) -> Result<(), Error> {
|
||||
let mut data = String::default();
|
||||
if path == "-" {
|
||||
std::io::stdin()
|
||||
@@ -649,7 +314,100 @@ fn create_data(path: &str) -> Result<String, Error> {
|
||||
data = std::fs::read_to_string(path).map_err(Error::ReadingFile)?;
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn do_command(toplevel: &TopLevel) -> Result<(), Error> {
|
||||
let mut socket =
|
||||
UnixStream::connect(toplevel.api_socket.as_deref().unwrap()).map_err(Error::Connect)?;
|
||||
|
||||
match toplevel.command {
|
||||
SubCommandEnum::Boot(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Delete(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "delete", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::ShutdownVmm(_) => {
|
||||
simple_api_full_command(&mut socket, "PUT", "vmm.shutdown", None)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Resume(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "resume", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::PowerButton(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "power-button", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Reboot(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "reboot", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Pause(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "pause", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Info(_) => {
|
||||
simple_api_command(&mut socket, "GET", "info", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Counters(_) => {
|
||||
simple_api_command(&mut socket, "GET", "counters", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Ping(_) => {
|
||||
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Shutdown(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "shutdown", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Resize(ref config) => {
|
||||
resize_api_command(&mut socket, config.cpus, &config.memory, &config.balloon)
|
||||
}
|
||||
SubCommandEnum::ResizeZone(ref config) => {
|
||||
resize_zone_api_command(&mut socket, &config.id, &config.size)
|
||||
}
|
||||
SubCommandEnum::AddDevice(ref config) => {
|
||||
add_device_api_command(&mut socket, &config.device_config)
|
||||
}
|
||||
SubCommandEnum::RemoveDevice(ref config) => {
|
||||
remove_device_api_command(&mut socket, &config.device_config)
|
||||
}
|
||||
SubCommandEnum::AddDisk(ref config) => {
|
||||
add_disk_api_command(&mut socket, &config.disk_config)
|
||||
}
|
||||
SubCommandEnum::AddFs(ref config) => add_fs_api_command(&mut socket, &config.fs_config),
|
||||
SubCommandEnum::AddPmem(ref config) => {
|
||||
add_pmem_api_command(&mut socket, &config.pmem_config)
|
||||
}
|
||||
SubCommandEnum::AddNet(ref config) => add_net_api_command(&mut socket, &config.net_config),
|
||||
SubCommandEnum::AddUserDevice(ref config) => {
|
||||
add_user_device_api_command(&mut socket, &config.device_config)
|
||||
}
|
||||
SubCommandEnum::AddVdpa(ref config) => {
|
||||
add_vdpa_api_command(&mut socket, &config.vdpa_config)
|
||||
}
|
||||
SubCommandEnum::AddVsock(ref config) => {
|
||||
add_vsock_api_command(&mut socket, &config.vsock_config)
|
||||
}
|
||||
SubCommandEnum::Snapshot(ref config) => {
|
||||
snapshot_api_command(&mut socket, &config.snapshot_config)
|
||||
}
|
||||
SubCommandEnum::Restore(ref config) => {
|
||||
restore_api_command(&mut socket, &config.restore_config)
|
||||
}
|
||||
SubCommandEnum::Coredump(ref config) => {
|
||||
coredump_api_command(&mut socket, &config.coredump_config)
|
||||
}
|
||||
SubCommandEnum::SendMigration(ref config) => send_migration_api_command(
|
||||
&mut socket,
|
||||
&config.send_migration_config,
|
||||
config.send_migration_local,
|
||||
),
|
||||
SubCommandEnum::ReceiveMigration(ref config) => {
|
||||
receive_migration_api_command(&mut socket, &config.receive_migration_config)
|
||||
}
|
||||
SubCommandEnum::Create(ref config) => create_api_command(&mut socket, &config.vm_config),
|
||||
SubCommandEnum::Version(_) => {
|
||||
// Already handled outside of this function
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
@@ -661,21 +419,6 @@ struct TopLevel {
|
||||
#[argh(option, long = "api-socket")]
|
||||
/// HTTP API socket path (UNIX domain socket)
|
||||
api_socket: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-service-name")]
|
||||
/// well known name of the dbus service
|
||||
dbus_name: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-object-path")]
|
||||
/// object path which the interface is being served at
|
||||
dbus_path: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(switch, long = "dbus-system-bus")]
|
||||
/// use the system bus instead of a session bus
|
||||
dbus_system_bus: bool,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
@@ -945,56 +688,16 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if matches!(toplevel.command, SubCommandEnum::Version(_)) {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
let mut target_api = match (
|
||||
&toplevel.api_socket,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
&toplevel.dbus_name,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
&toplevel.dbus_path,
|
||||
) {
|
||||
#[cfg(not(feature = "dbus_api"))]
|
||||
(Some(ref api_socket),) => TargetApi::HttpApi(
|
||||
UnixStream::connect(api_socket).unwrap_or_else(|e| {
|
||||
eprintln!("Error opening HTTP socket: {e}");
|
||||
process::exit(1)
|
||||
}),
|
||||
PhantomData,
|
||||
),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
(Some(ref api_socket), None, None) => TargetApi::HttpApi(
|
||||
UnixStream::connect(api_socket).unwrap_or_else(|e| {
|
||||
eprintln!("Error opening HTTP socket: {e}");
|
||||
process::exit(1)
|
||||
}),
|
||||
PhantomData,
|
||||
),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
(None, Some(ref dbus_name), Some(ref dbus_path)) => TargetApi::DBusApi(
|
||||
DBusApi1ProxyBlocking::new_connection(dbus_name, dbus_path, toplevel.dbus_system_bus)
|
||||
.map_err(Error::DBusApiClient)
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("Error creating D-Bus proxy: {e}");
|
||||
process::exit(1)
|
||||
}),
|
||||
),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
(Some(_), Some(_) | None, Some(_) | None) => {
|
||||
println!(
|
||||
"`api-socket` and (dbus-service-name or dbus-object-path) are mutually exclusive"
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
_ => {
|
||||
println!("Please either provide the api-socket option or dbus-service-name and dbus-object-path options");
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
if toplevel.api_socket.is_none() {
|
||||
println!("Please specify --api-socket");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
if let Err(e) = target_api.do_command(&toplevel) {
|
||||
if let Err(e) = do_command(&toplevel) {
|
||||
eprintln!("Error running command: {e}");
|
||||
process::exit(1)
|
||||
};
|
||||
|
||||
91
src/main.rs
91
src/main.rs
@@ -18,8 +18,6 @@ use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use vmm::api::dbus::{dbus_api_graceful_shutdown, DBusApiOptions};
|
||||
use vmm::config;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::block_signal;
|
||||
@@ -59,12 +57,6 @@ enum Error {
|
||||
ParsingApiSocket(std::num::ParseIntError),
|
||||
#[error("Error parsing --event-monitor: {0}")]
|
||||
ParsingEventMonitor(option_parser::OptionParserError),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("`--dbus-object-path` option isn't provided")]
|
||||
MissingDBusObjectPath,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("`--dbus-service-name` option isn't provided")]
|
||||
MissingDBusServiceName,
|
||||
#[error("Error parsing --event-monitor: path or fd required")]
|
||||
BareEventMonitor,
|
||||
#[error("Error doing event monitor I/O: {0}")]
|
||||
@@ -146,19 +138,19 @@ fn default_rng() -> String {
|
||||
/// Launch a cloud-hypervisor VMM.
|
||||
pub struct TopLevel {
|
||||
#[argh(option, long = "cpus", default = "default_vcpus()")]
|
||||
/// boot=<boot_vcpus>, max=<max_vcpus>, topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>, kvm_hyperv=on|off, max_phys_bits=<maximum_number_of_physical_bits>, affinity=<list_of_vcpus_with_their_associated_cpuset>, features=<list_of_features_to_enable>
|
||||
/// boot=<boot_vcpus>,max=<max_vcpus>,topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,affinity=<list_of_vcpus_with_their_associated_cpuset>,features=<list_of_features_to_enable>
|
||||
cpus: String,
|
||||
|
||||
#[argh(option, long = "platform")]
|
||||
/// num_pci_segments=<num_pci_segments>, iommu_segments=<list_of_segments>, serial_number=<dmi_device_serial_number>, uuid=<dmi_device_uuid>, oem_strings=<list_of_strings>
|
||||
/// num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>
|
||||
platform: Option<String>,
|
||||
|
||||
#[argh(option, long = "memory", default = "default_memory()")]
|
||||
/// size=<guest_memory_size>, mergeable=on|off, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, hotplug_method=acpi|virtio-mem, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off, thp=on|off
|
||||
/// size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off,thp=on|off
|
||||
memory: String,
|
||||
|
||||
#[argh(option, long = "memory-zone")]
|
||||
/// size=<guest_memory_region_size>, file=<backing_file>, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, host_numa_node=<node_id>, id=<zone_identifier>, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off
|
||||
/// size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off
|
||||
memory_zone: Vec<String>,
|
||||
|
||||
#[argh(option, long = "firmware")]
|
||||
@@ -178,27 +170,27 @@ pub struct TopLevel {
|
||||
cmdline: Option<String>,
|
||||
|
||||
#[argh(option, long = "disk")]
|
||||
/// path=<disk_image_path>, readonly=on|off, direct=on|off, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, vhost_user=on|off, socket=<vhost_user_socket_path>, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, id=<device_id>, pci_segment=<segment_id>
|
||||
/// path=<disk_image_path>,readonly=on|off,direct=on|off,iommu=on|off,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,vhost_user=on|off,socket=<vhost_user_socket_path>,bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,id=<device_id>,pci_segment=<segment_id>
|
||||
disk: Vec<String>,
|
||||
|
||||
#[argh(option, long = "net")]
|
||||
/// tap=<if_name>, ip=<ip_addr>, mask=<net_mask>, mac=<mac_addr>, fd=<fd1,fd2...>, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, vhost_user=<vhost_user_enable>, socket=<vhost_user_socket_path>, vhost_mode=client|server, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, pci_segment=<segment_id>offload_tso=on|off, offload_ufo=on|off, offload_csum=on|off
|
||||
/// tap=<if_name>,ip=<ip_addr>,mask=<net_mask>,mac=<mac_addr>,fd=<fd1,fd2...>,iommu=on|off,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,id=<device_id>,vhost_user=<vhost_user_enable>,socket=<vhost_user_socket_path>,vhost_mode=client|server,bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,pci_segment=<segment_id>offload_tso=on|off,offload_ufo=on|off,offload_csum=on|off
|
||||
net: Vec<String>,
|
||||
|
||||
#[argh(option, long = "rng", default = "default_rng()")]
|
||||
/// src=<entropy_source_path>, iommu=on|off
|
||||
/// src=<entropy_source_path>,iommu=on|off
|
||||
rng: String,
|
||||
|
||||
#[argh(option, long = "balloon")]
|
||||
/// size=<balloon_size>, deflate_on_oom=on|off, free_page_reporting=on|off
|
||||
/// size=<balloon_size>,deflate_on_oom=on|off,free_page_reporting=on|off
|
||||
balloon: Option<String>,
|
||||
|
||||
#[argh(option, long = "fs")]
|
||||
/// tag=<tag_name>, socket=<socket_path>, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, pci_segment=<segment_id>
|
||||
/// tag=<tag_name>,socket=<socket_path>,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,id=<device_id>,pci_segment=<segment_id>
|
||||
fs: Vec<String>,
|
||||
|
||||
#[argh(option, long = "pmem")]
|
||||
/// file=<backing_file_path>, size=<persistent_memory_size>, iommu=on|off, discard_writes=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
/// file=<backing_file_path>,size=<persistent_memory_size>,iommu=on|off,discard_writes=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
pmem: Vec<String>,
|
||||
|
||||
#[argh(option, long = "serial", default = "String::from(\"null\")")]
|
||||
@@ -206,27 +198,27 @@ pub struct TopLevel {
|
||||
serial: String,
|
||||
|
||||
#[argh(option, long = "console", default = "String::from(\"tty\")")]
|
||||
/// off|null|pty|tty|file=/path/to/a/file, iommu=on|off
|
||||
/// off|null|pty|tty|file=/path/to/a/file,iommu=on|off
|
||||
console: String,
|
||||
|
||||
#[argh(option, long = "device")]
|
||||
/// path=<device_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
/// path=<device_path>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
device: Vec<String>,
|
||||
|
||||
#[argh(option, long = "user-device")]
|
||||
/// socket=<socket_path>, id=<device_id>, pci_segment=<segment_id>
|
||||
/// socket=<socket_path>,id=<device_id>,pci_segment=<segment_id>
|
||||
user_device: Vec<String>,
|
||||
|
||||
#[argh(option, long = "vdpa")]
|
||||
/// path=<device_path>, num_queues=<number_of_queues>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
/// path=<device_path>,num_queues=<number_of_queues>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
vdpa: Vec<String>,
|
||||
|
||||
#[argh(option, long = "vsock")]
|
||||
/// cid=<context_id>, socket=<socket_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
/// cid=<context_id>,socket=<socket_path>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
vsock: Option<String>,
|
||||
|
||||
#[argh(option, long = "numa")]
|
||||
/// guest_numa_id=<node_id>, cpus=<cpus_id>, distances=<list_of_distances_to_destination_nodes>, memory_zones=<list_of_memory_zones>, sgx_epc_sections=<list_of_sgx_epc_sections>
|
||||
/// guest_numa_id=<node_id>,cpus=<cpus_id>,distances=<list_of_distances_to_destination_nodes>,memory_zones=<list_of_memory_zones>,sgx_epc_sections=<list_of_sgx_epc_sections>
|
||||
numa: Vec<String>,
|
||||
|
||||
#[argh(switch, long = "watchdog")]
|
||||
@@ -245,27 +237,12 @@ pub struct TopLevel {
|
||||
/// path=<path/to/a/file>|fd=<fd>
|
||||
api_socket: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-service-name")]
|
||||
/// well known name of the service
|
||||
dbus_name: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-object-path")]
|
||||
/// object path to serve the dbus interface
|
||||
dbus_path: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(switch, long = "dbus-system-bus")]
|
||||
/// use the system bus instead of a session bus
|
||||
dbus_system_bus: bool,
|
||||
|
||||
#[argh(option, long = "event-monitor")]
|
||||
/// path=<path/to/a/file>|fd=<fd>
|
||||
event_monitor: Option<String>,
|
||||
|
||||
#[argh(option, long = "restore")]
|
||||
/// source_url=<source_url>, prefault=on|off
|
||||
/// source_url=<source_url>,prefault=on|off
|
||||
restore: Option<String>,
|
||||
|
||||
#[argh(option, long = "seccomp", default = "String::from(\"true\")")]
|
||||
@@ -278,7 +255,7 @@ pub struct TopLevel {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[argh(option, long = "sgx-epc")]
|
||||
/// id=<epc_section_identifier>, size=<epc_section_size>, prefault=on|off
|
||||
/// id=<epc_section_identifier>,size=<epc_section_size>,prefault=on|off
|
||||
sgx_epc: Vec<String>,
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
@@ -439,18 +416,6 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
let dbus_options = match (&toplevel.dbus_name, &toplevel.dbus_path) {
|
||||
(Some(ref name), Some(ref path)) => Ok(Some(DBusApiOptions {
|
||||
service_name: name.to_owned(),
|
||||
object_path: path.to_owned(),
|
||||
system_bus: toplevel.dbus_system_bus,
|
||||
})),
|
||||
(Some(_), None) => Err(Error::MissingDBusObjectPath),
|
||||
(None, Some(_)) => Err(Error::MissingDBusServiceName),
|
||||
(None, None) => Ok(None),
|
||||
}?;
|
||||
|
||||
if let Some(ref monitor_config) = toplevel.event_monitor {
|
||||
let mut parser = OptionParser::new();
|
||||
parser.add("path").add("fd");
|
||||
@@ -480,7 +445,7 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
let (api_request_sender, api_request_receiver) = channel();
|
||||
let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?;
|
||||
|
||||
let api_request_sender_clone = api_request_sender.clone();
|
||||
let http_sender = api_request_sender.clone();
|
||||
let seccomp_action = match &toplevel.seccomp as &str {
|
||||
"true" => SeccompAction::Trap,
|
||||
"false" => SeccompAction::Allow,
|
||||
@@ -548,14 +513,12 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
|
||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
|
||||
|
||||
let vmm_thread_handle = vmm::start_vmm_thread(
|
||||
vmm::VmmVersionInfo::new(env!("BUILD_VERSION"), env!("CARGO_PKG_VERSION")),
|
||||
let vmm_thread = vmm::start_vmm_thread(
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
&api_socket_path,
|
||||
api_socket_fd,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
dbus_options,
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender_clone,
|
||||
http_sender,
|
||||
api_request_receiver,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
gdb_socket_path,
|
||||
@@ -605,17 +568,11 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
vmm_thread_handle
|
||||
.thread_handle
|
||||
vmm_thread
|
||||
.join()
|
||||
.map_err(Error::ThreadJoin)?
|
||||
.map_err(Error::VmmThread)?;
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
if let Some(chs) = vmm_thread_handle.dbus_shutdown_chs {
|
||||
dbus_api_graceful_shutdown(chs);
|
||||
}
|
||||
|
||||
r.map(|_| api_socket_path)
|
||||
}
|
||||
|
||||
@@ -630,7 +587,7 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
instance-id: cloud
|
||||
local-hostname: cloud
|
||||
@@ -1,7 +0,0 @@
|
||||
version: 2
|
||||
ethernets:
|
||||
ens4:
|
||||
match:
|
||||
macaddress: 12:34:56:78:90:ab
|
||||
addresses: [192.168.249.2/24]
|
||||
gateway4: 192.168.249.1
|
||||
@@ -1,10 +0,0 @@
|
||||
#cloud-config
|
||||
users:
|
||||
- name: cloud
|
||||
passwd: $6$7125787751a8d18a$sHwGySomUA1PawiNFWVCKYQN.Ec.Wzz0JtPPL1MvzFrkwmop2dq7.4CYf03A5oemPQ4pOFCCrtCelvFBEle/K.
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
lock_passwd: False
|
||||
inactive: False
|
||||
shell: /bin/bash
|
||||
|
||||
ssh_pwauth: True
|
||||
@@ -5,12 +5,12 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
dirs = "5.0.0"
|
||||
dirs = "4.0.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.139"
|
||||
once_cell = "1.17.1"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.95"
|
||||
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
|
||||
vmm-sys-util = "0.11.0"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -249,8 +249,7 @@ impl DiskConfig for UbuntuDiskConfig {
|
||||
.unwrap()
|
||||
.join("test_data")
|
||||
.join("cloud-init")
|
||||
.join("ubuntu")
|
||||
.join("ci");
|
||||
.join("ubuntu");
|
||||
|
||||
vec!["meta-data"].iter().for_each(|x| {
|
||||
rate_limited_copy(source_file_dir.join(x), cloud_init_directory.join(x))
|
||||
@@ -869,6 +868,14 @@ impl Guest {
|
||||
.map_err(Error::Parsing)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn get_initial_apicid(&self) -> Result<u32, Error> {
|
||||
self.ssh_command("grep \"initial apicid\" /proc/cpuinfo | grep -o \"[0-9]*\"")?
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(Error::Parsing)
|
||||
}
|
||||
|
||||
pub fn get_total_memory(&self) -> Result<u32, Error> {
|
||||
self.ssh_command("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")?
|
||||
.trim()
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
extern crate test_infra;
|
||||
|
||||
use api_client::simple_api_command;
|
||||
use api_client::simple_api_full_command;
|
||||
use net_util::MacAddr;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
@@ -30,9 +32,6 @@ use test_infra::*;
|
||||
use vmm_sys_util::{tempdir::TempDir, tempfile::TempFile};
|
||||
use wait_timeout::ChildExt;
|
||||
|
||||
// Constant taken from the VMM crate.
|
||||
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod x86_64 {
|
||||
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw";
|
||||
@@ -73,324 +72,6 @@ const DIRECT_KERNEL_BOOT_CMDLINE: &str =
|
||||
|
||||
const CONSOLE_TEST_STRING: &str = "Started OpenBSD Secure Shell server";
|
||||
|
||||
// This enum exists to make it more convenient to
|
||||
// implement test for both D-Bus and REST APIs.
|
||||
enum TargetApi {
|
||||
// API socket
|
||||
HttpApi(String),
|
||||
// well known service name, object path
|
||||
DBusApi(String, String),
|
||||
}
|
||||
|
||||
impl TargetApi {
|
||||
fn new_http_api(tmp_dir: &TempDir) -> Self {
|
||||
Self::HttpApi(temp_api_path(tmp_dir))
|
||||
}
|
||||
|
||||
fn new_dbus_api(tmp_dir: &TempDir) -> Self {
|
||||
// `tmp_dir` is in the form of "/tmp/chXXXXXX"
|
||||
// and we take the `chXXXXXX` part as a unique identifier for the guest
|
||||
let id = tmp_dir.as_path().file_name().unwrap().to_str().unwrap();
|
||||
|
||||
Self::DBusApi(
|
||||
format!("org.cloudhypervisor.{id}"),
|
||||
format!("/org/cloudhypervisor/{id}"),
|
||||
)
|
||||
}
|
||||
|
||||
fn guest_args(&self) -> Vec<&str> {
|
||||
match self {
|
||||
TargetApi::HttpApi(api_socket) => {
|
||||
vec!["--api-socket", api_socket.as_str()]
|
||||
}
|
||||
TargetApi::DBusApi(service_name, object_path) => {
|
||||
vec![
|
||||
"--dbus-service-name",
|
||||
service_name.as_str(),
|
||||
"--dbus-object-path",
|
||||
object_path.as_str(),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remote_args(&self) -> Vec<&str> {
|
||||
// `guest_args` and `remote_args` are consistent with each other
|
||||
self.guest_args()
|
||||
}
|
||||
|
||||
fn remote_command(&self, command: &str, arg: Option<&str>) -> bool {
|
||||
let mut cmd = Command::new(clh_command("ch-remote"));
|
||||
cmd.args(self.remote_args());
|
||||
cmd.arg(command);
|
||||
|
||||
if let Some(arg) = arg {
|
||||
cmd.arg(arg);
|
||||
}
|
||||
|
||||
let output = cmd.output().unwrap();
|
||||
if output.status.success() {
|
||||
true
|
||||
} else {
|
||||
eprintln!("Error running ch-remote command: {:?}", &cmd);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
eprintln!("stderr: {stderr}");
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
fn _test_api_create_boot(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
assert!(target_api.remote_command("create", Some(create_config),));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be shutdown and then
|
||||
// booted again
|
||||
fn _test_api_shutdown(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then shut it down
|
||||
assert!(target_api.remote_command("shutdown", None));
|
||||
|
||||
// Then boot it again
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be deleted and then recreated
|
||||
// booted again.
|
||||
fn _test_api_delete(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then delete it
|
||||
assert!(target_api.remote_command("delete", None));
|
||||
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it again
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
// Then we pause the VM, check that it's no longer available.
|
||||
// Finally we resume the VM and check that it's available.
|
||||
fn _test_api_pause_resume(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// We now pause the VM
|
||||
assert!(target_api.remote_command("pause", None));
|
||||
|
||||
// Check pausing again fails
|
||||
assert!(!target_api.remote_command("pause", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// SSH into the VM should fail
|
||||
assert!(ssh_command_ip(
|
||||
"grep -c processor /proc/cpuinfo",
|
||||
&guest.network.guest_ip,
|
||||
2,
|
||||
5
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// Resume the VM
|
||||
assert!(target_api.remote_command("resume", None));
|
||||
|
||||
// Check resuming again fails
|
||||
assert!(!target_api.remote_command("resume", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// Now we should be able to SSH back in and get the right number of CPUs
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
fn prepare_virtiofsd(tmp_dir: &TempDir, shared_dir: &str) -> (std::process::Child, String) {
|
||||
let mut workload_path = dirs::home_dir().unwrap();
|
||||
workload_path.push("workloads");
|
||||
@@ -1525,10 +1206,7 @@ fn _test_virtio_fs(
|
||||
.default_net()
|
||||
.args(["--api-socket", &api_socket]);
|
||||
if pci_segment.is_some() {
|
||||
guest_command.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
]);
|
||||
guest_command.args(["--platform", "num_pci_segments=16"]);
|
||||
}
|
||||
|
||||
let fs_params = format!(
|
||||
@@ -2226,7 +1904,7 @@ fn enable_guest_watchdog(guest: &Guest, watchdog_sec: u32) {
|
||||
}
|
||||
|
||||
mod common_parallel {
|
||||
use std::{fs::OpenOptions, io::SeekFrom};
|
||||
use std::{fs::OpenOptions, io::SeekFrom, os::unix::net::UnixStream};
|
||||
|
||||
use crate::*;
|
||||
|
||||
@@ -2264,6 +1942,7 @@ mod common_parallel {
|
||||
guest.wait_vm_boot(Some(120)).unwrap();
|
||||
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
|
||||
assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
|
||||
|
||||
@@ -2637,10 +2316,7 @@ mod common_parallel {
|
||||
.args(["--memory", "size=512M"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS},iommu_segments=[1]"),
|
||||
])
|
||||
.args(["--platform", "num_pci_segments=16,iommu_segments=[1]"])
|
||||
.default_disks()
|
||||
.capture_output()
|
||||
.default_net();
|
||||
@@ -2796,10 +2472,7 @@ mod common_parallel {
|
||||
.args(["--memory", "size=512M"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
])
|
||||
.args(["--platform", "num_pci_segments=16"])
|
||||
.args([
|
||||
"--disk",
|
||||
format!(
|
||||
@@ -2826,15 +2499,15 @@ mod common_parallel {
|
||||
let grep_cmd = "lspci | grep \"Host bridge\" | wc -l";
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// There should be MAX_NUM_PCI_SEGMENTS PCI host bridges in the guest.
|
||||
// There should be 16 PCI host bridges in the guest.
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command(grep_cmd)
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u16>()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
MAX_NUM_PCI_SEGMENTS
|
||||
16
|
||||
);
|
||||
|
||||
// Check both if /dev/vdc exists and if the block size is 4M.
|
||||
@@ -4295,7 +3968,7 @@ mod common_parallel {
|
||||
.ssh_command_l1(
|
||||
"sudo /mnt/ch-remote \
|
||||
--api-socket /tmp/ch_api.sock \
|
||||
resize --memory 1073741824",
|
||||
resize --memory=1073741824",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000);
|
||||
@@ -4354,35 +4027,279 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_http_shutdown() {
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
fn test_api_create_boot() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_shutdown(TargetApi::new_http_api(&guest.tmp_dir), guest)
|
||||
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
let mut socket = UnixStream::connect(&api_socket).unwrap();
|
||||
// Verify API server is running
|
||||
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, http_body).unwrap();
|
||||
|
||||
remote_command(
|
||||
&api_socket,
|
||||
"create",
|
||||
Some(temp_config_path.as_os_str().to_str().unwrap()),
|
||||
);
|
||||
|
||||
// Then boot it
|
||||
remote_command(&api_socket, "boot", None);
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_http_delete() {
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be shutdown and then
|
||||
// booted again
|
||||
fn test_api_shutdown() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_delete(TargetApi::new_http_api(&guest.tmp_dir), guest);
|
||||
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
let mut socket = UnixStream::connect(&api_socket).unwrap();
|
||||
// Verify API server is running
|
||||
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// socket has to be created again inside catch_unwind block to avoid errors
|
||||
let mut socket = UnixStream::connect(&api_socket).unwrap();
|
||||
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
|
||||
|
||||
// Then boot it
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then shut it down
|
||||
simple_api_command(&mut socket, "PUT", "shutdown", None).unwrap();
|
||||
|
||||
// Then boot it again
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_http_pause_resume() {
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be deleted and then recreated
|
||||
// booted again.
|
||||
fn test_api_delete() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_pause_resume(TargetApi::new_http_api(&guest.tmp_dir), guest)
|
||||
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
let mut socket = UnixStream::connect(&api_socket).unwrap();
|
||||
// Verify API server is running
|
||||
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// socket has to be created again inside catch_unwind block to avoid errors
|
||||
let mut socket = UnixStream::connect(&api_socket).unwrap();
|
||||
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
|
||||
|
||||
// Then boot it
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then delete it
|
||||
simple_api_command(&mut socket, "PUT", "delete", None).unwrap();
|
||||
|
||||
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
|
||||
|
||||
// Then boot it again
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_http_create_boot() {
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
// Then we pause the VM, check that it's no longer available.
|
||||
// Finally we resume the VM and check that it's available.
|
||||
fn test_api_pause_resume() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_create_boot(TargetApi::new_http_api(&guest.tmp_dir), guest)
|
||||
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
let mut socket = UnixStream::connect(&api_socket).unwrap();
|
||||
// Verify API server is running
|
||||
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).unwrap();
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
simple_api_command(&mut socket, "PUT", "create", Some(&http_body)).unwrap();
|
||||
|
||||
// Then boot it
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// We now pause the VM
|
||||
assert!(remote_command(&api_socket, "pause", None));
|
||||
|
||||
// Check pausing again fails
|
||||
assert!(!remote_command(&api_socket, "pause", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// SSH into the VM should fail
|
||||
assert!(ssh_command_ip(
|
||||
"grep -c processor /proc/cpuinfo",
|
||||
&guest.network.guest_ip,
|
||||
2,
|
||||
5
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// Resume the VM
|
||||
assert!(remote_command(&api_socket, "resume", None));
|
||||
|
||||
// Check resuming again fails
|
||||
assert!(!remote_command(&api_socket, "resume", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// Now we should be able to SSH back in and get the right number of CPUs
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -4996,6 +4913,7 @@ mod common_parallel {
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)]
|
||||
fn create_loop_device(backing_file_path: &str, block_size: u32, num_retries: usize) -> String {
|
||||
const LOOP_CONFIGURE: u64 = 0x4c0a;
|
||||
const LOOP_CTL_GET_FREE: u64 = 0x4c82;
|
||||
@@ -5056,9 +4974,12 @@ mod common_parallel {
|
||||
.unwrap();
|
||||
|
||||
// Request a free loop device
|
||||
let loop_device_number =
|
||||
unsafe { libc::ioctl(loop_ctl_file.as_raw_fd(), LOOP_CTL_GET_FREE as _) };
|
||||
|
||||
let loop_device_number = unsafe {
|
||||
libc::ioctl(
|
||||
loop_ctl_file.as_raw_fd(),
|
||||
LOOP_CTL_GET_FREE.try_into().unwrap(),
|
||||
)
|
||||
};
|
||||
if loop_device_number < 0 {
|
||||
panic!("Couldn't find a free loop device");
|
||||
}
|
||||
@@ -5090,7 +5011,7 @@ mod common_parallel {
|
||||
let ret = unsafe {
|
||||
libc::ioctl(
|
||||
loop_device_file.as_raw_fd(),
|
||||
LOOP_CONFIGURE as _,
|
||||
LOOP_CONFIGURE.try_into().unwrap(),
|
||||
&loop_config,
|
||||
)
|
||||
};
|
||||
@@ -5375,10 +5296,7 @@ mod common_parallel {
|
||||
.capture_output();
|
||||
|
||||
if pci_segment.is_some() {
|
||||
cmd.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
]);
|
||||
cmd.args(["--platform", "num_pci_segments=16"]);
|
||||
}
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
@@ -5514,10 +5432,7 @@ mod common_parallel {
|
||||
.capture_output();
|
||||
|
||||
if pci_segment.is_some() {
|
||||
cmd.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
]);
|
||||
cmd.args(["--platform", "num_pci_segments=16"]);
|
||||
}
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
@@ -6345,13 +6260,11 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
|
||||
fn test_macvtap() {
|
||||
_test_macvtap(false, "guestmacvtap0", "hostmacvtap0")
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
|
||||
fn test_macvtap_hotplug() {
|
||||
_test_macvtap(true, "guestmacvtap1", "hostmacvtap1")
|
||||
}
|
||||
@@ -6861,116 +6774,6 @@ mod common_parallel {
|
||||
}
|
||||
}
|
||||
|
||||
mod dbus_api {
|
||||
use crate::*;
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, running both the HTTP
|
||||
// and DBus APIs. Alternate calls to the external APIs (HTTP and DBus)
|
||||
// to create a VM, boot it, and verify that it can be shut down and then
|
||||
// booted again.
|
||||
#[test]
|
||||
fn test_api_dbus_and_http_interleaved() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
let dbus_api = TargetApi::new_dbus_api(&guest.tmp_dir);
|
||||
let http_api = TargetApi::new_http_api(&guest.tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(dbus_api.guest_args())
|
||||
.args(http_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API servers are running
|
||||
assert!(dbus_api.remote_command("ping", None));
|
||||
assert!(http_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Create the VM
|
||||
assert!(dbus_api.remote_command("create", Some(create_config),));
|
||||
|
||||
// Then boot it
|
||||
assert!(http_api.remote_command("boot", None));
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then shutdown the VM
|
||||
assert!(dbus_api.remote_command("shutdown", None));
|
||||
|
||||
// Then boot it again
|
||||
assert!(http_api.remote_command("boot", None));
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_create_boot() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_create_boot(TargetApi::new_dbus_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_shutdown() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_shutdown(TargetApi::new_dbus_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_delete() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_delete(TargetApi::new_dbus_api(&guest.tmp_dir), guest);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_pause_resume() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_pause_resume(TargetApi::new_dbus_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
}
|
||||
|
||||
mod common_sequential {
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
use crate::*;
|
||||
@@ -8282,7 +8085,7 @@ mod vfio {
|
||||
.ssh_command_l1(
|
||||
"sudo /mnt/ch-remote \
|
||||
--api-socket /tmp/ch_api.sock \
|
||||
resize --memory 1073741824",
|
||||
resize --memory=1073741824",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000);
|
||||
|
||||
@@ -8,8 +8,8 @@ edition = "2021"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
once_cell = "1.17.1"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.95"
|
||||
|
||||
[features]
|
||||
tracing = []
|
||||
|
||||
@@ -11,5 +11,5 @@ crc32c = "0.6.3"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
remain = "0.2.6"
|
||||
thiserror = "1.0.40"
|
||||
uuid = { version = "1.3.4", features = ["v4"] }
|
||||
thiserror = "1.0.39"
|
||||
uuid = { version = "1.3.0", features = ["v4"] }
|
||||
|
||||
@@ -14,10 +14,10 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
option_parser = { path = "../option_parser" }
|
||||
qcow = { path = "../qcow" }
|
||||
vhost = { version = "0.7.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.9.0"
|
||||
vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.8.0"
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = "0.11.0"
|
||||
virtio-queue = "0.7.1"
|
||||
vm-memory = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
net_util = { path = "../net_util" }
|
||||
option_parser = { path = "../option_parser" }
|
||||
vhost = { version = "0.7.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.9.0"
|
||||
vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.8.0"
|
||||
virtio-bindings = "0.2.0"
|
||||
vm-memory = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ edition = "2021"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
arc-swap = "1.5.1"
|
||||
block_util = { path = "../block_util" }
|
||||
byteorder = "1.4.3"
|
||||
@@ -22,18 +22,18 @@ net_util = { path = "../net_util" }
|
||||
pci = { path = "../pci" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
seccompiler = "0.3.0"
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
serde_json = "1.0.96"
|
||||
serde = { version = "1.0.151", features = ["derive"] }
|
||||
serde_json = "1.0.95"
|
||||
serial_buffer = { path = "../serial_buffer" }
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vhost = { version = "0.7.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
|
||||
vhost = { version = "0.6.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.8.0"
|
||||
virtio-queue = "0.7.1"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -91,8 +91,8 @@ pub enum ActivateError {
|
||||
ThreadSpawn(std::io::Error),
|
||||
#[error("Failed to setup vhost-user-fs daemon: {0}")]
|
||||
VhostUserFsSetup(vhost_user::Error),
|
||||
#[error("Failed to setup vhost-user daemon: {0}")]
|
||||
VhostUserSetup(vhost_user::Error),
|
||||
#[error("Failed to setup vhost-user-blk daemon: {0}")]
|
||||
VhostUserBlkSetup(vhost_user::Error),
|
||||
#[error("Failed to create seccomp filter: {0}")]
|
||||
CreateSeccompFilter(seccompiler::Error),
|
||||
#[error("Failed to create rate limiter: {0}")]
|
||||
|
||||
@@ -48,13 +48,14 @@ use super::pci_common_config::VirtioPciCommonConfigState;
|
||||
/// Vector value used to disable MSI for a queue.
|
||||
const VIRTQ_MSI_NO_VECTOR: u16 = 0xffff;
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum PciCapabilityType {
|
||||
Common = 1,
|
||||
Notify = 2,
|
||||
Isr = 3,
|
||||
Device = 4,
|
||||
Pci = 5,
|
||||
SharedMemory = 8,
|
||||
CommonConfig = 1,
|
||||
NotifyConfig = 2,
|
||||
IsrConfig = 3,
|
||||
DeviceConfig = 4,
|
||||
PciConfig = 5,
|
||||
SharedMemoryConfig = 8,
|
||||
}
|
||||
|
||||
// This offset represents the 2 bytes omitted from the VirtioPciCap structure
|
||||
@@ -209,7 +210,7 @@ impl PciCapability for VirtioPciCfgCap {
|
||||
impl VirtioPciCfgCap {
|
||||
fn new() -> Self {
|
||||
VirtioPciCfgCap {
|
||||
cap: VirtioPciCap::new(PciCapabilityType::Pci, 0, 0, 0),
|
||||
cap: VirtioPciCap::new(PciCapabilityType::PciConfig, 0, 0, 0),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -666,7 +667,7 @@ impl VirtioPciDevice {
|
||||
) -> std::result::Result<(), PciDeviceError> {
|
||||
// Add pointers to the different configuration structures from the PCI capabilities.
|
||||
let common_cap = VirtioPciCap::new(
|
||||
PciCapabilityType::Common,
|
||||
PciCapabilityType::CommonConfig,
|
||||
settings_bar,
|
||||
COMMON_CONFIG_BAR_OFFSET as u32,
|
||||
COMMON_CONFIG_SIZE as u32,
|
||||
@@ -676,7 +677,7 @@ impl VirtioPciDevice {
|
||||
.map_err(PciDeviceError::CapabilitiesSetup)?;
|
||||
|
||||
let isr_cap = VirtioPciCap::new(
|
||||
PciCapabilityType::Isr,
|
||||
PciCapabilityType::IsrConfig,
|
||||
settings_bar,
|
||||
ISR_CONFIG_BAR_OFFSET as u32,
|
||||
ISR_CONFIG_SIZE as u32,
|
||||
@@ -687,7 +688,7 @@ impl VirtioPciDevice {
|
||||
|
||||
// TODO(dgreid) - set based on device's configuration size?
|
||||
let device_cap = VirtioPciCap::new(
|
||||
PciCapabilityType::Device,
|
||||
PciCapabilityType::DeviceConfig,
|
||||
settings_bar,
|
||||
DEVICE_CONFIG_BAR_OFFSET as u32,
|
||||
DEVICE_CONFIG_SIZE as u32,
|
||||
@@ -697,7 +698,7 @@ impl VirtioPciDevice {
|
||||
.map_err(PciDeviceError::CapabilitiesSetup)?;
|
||||
|
||||
let notify_cap = VirtioPciNotifyCap::new(
|
||||
PciCapabilityType::Notify,
|
||||
PciCapabilityType::NotifyConfig,
|
||||
settings_bar,
|
||||
NOTIFICATION_BAR_OFFSET as u32,
|
||||
NOTIFICATION_SIZE as u32,
|
||||
@@ -1056,7 +1057,7 @@ impl PciDevice for VirtioPciDevice {
|
||||
|
||||
for (idx, shm) in shm_list.region_list.iter().enumerate() {
|
||||
let shm_cap = VirtioPciCap64::new(
|
||||
PciCapabilityType::SharedMemory,
|
||||
PciCapabilityType::SharedMemoryConfig,
|
||||
VIRTIO_SHM_BAR_INDEX as u8,
|
||||
idx as u8,
|
||||
shm.offset,
|
||||
|
||||
@@ -237,7 +237,7 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
|
||||
.map_err(|e| {
|
||||
EpollHelperError::IoError(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("failed reconnecting vhost-user backend: {e:?}"),
|
||||
format!("failed reconnecting vhost-user backend{e:?}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
@@ -340,7 +340,7 @@ impl VhostUserCommon {
|
||||
&slave_req_handler,
|
||||
inflight.as_mut(),
|
||||
)
|
||||
.map_err(ActivateError::VhostUserSetup)?;
|
||||
.map_err(ActivateError::VhostUserBlkSetup)?;
|
||||
|
||||
Ok(VhostUserEpollHandler {
|
||||
vu: vu.clone(),
|
||||
@@ -413,7 +413,7 @@ impl VhostUserCommon {
|
||||
pub fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
if let Some(vu) = &self.vu {
|
||||
vu.lock().unwrap().pause_vhost_user().map_err(|e| {
|
||||
MigratableError::Pause(anyhow!("Error pausing vhost-user backend: {:?}", e))
|
||||
MigratableError::Pause(anyhow!("Error pausing vhost-user-blk backend: {:?}", e))
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -423,7 +423,7 @@ impl VhostUserCommon {
|
||||
pub fn resume(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
if let Some(vu) = &self.vu {
|
||||
vu.lock().unwrap().resume_vhost_user().map_err(|e| {
|
||||
MigratableError::Resume(anyhow!("Error resuming vhost-user backend: {:?}", e))
|
||||
MigratableError::Resume(anyhow!("Error resuming vhost-user-blk backend: {:?}", e))
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
|
||||
@@ -436,6 +436,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_tx_packet_assembly() {
|
||||
// Test case: successful TX packet assembly.
|
||||
{
|
||||
@@ -580,6 +581,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_packet_hdr_accessors() {
|
||||
const SRC_CID: u64 = 1;
|
||||
const DST_CID: u64 = 2;
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.139"
|
||||
vm-memory = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
arch = { path = "../arch" }
|
||||
|
||||
@@ -63,6 +63,7 @@ impl GsiAllocator {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(clippy::new_without_default)]
|
||||
/// New GSI allocator
|
||||
pub fn new() -> Self {
|
||||
GsiAllocator {
|
||||
@@ -105,10 +106,3 @@ impl GsiAllocator {
|
||||
Ok(irq)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
impl Default for GsiAllocator {
|
||||
fn default() -> Self {
|
||||
GsiAllocator::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
thiserror = "1.0.40"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.39"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap"] }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
thiserror = "1.0.40"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
anyhow = "1.0.69"
|
||||
thiserror = "1.0.39"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.95"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
|
||||
@@ -12,8 +12,8 @@ use versionize::{VersionMap, Versionize};
|
||||
pub mod protocol;
|
||||
|
||||
/// Global VMM version for versioning
|
||||
const MAJOR_VERSION: u16 = 33;
|
||||
const MINOR_VERSION: u16 = 0;
|
||||
const MAJOR_VERSION: u16 = 31;
|
||||
const MINOR_VERSION: u16 = 2;
|
||||
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;
|
||||
|
||||
pub trait VersionMapped {
|
||||
|
||||
@@ -9,5 +9,5 @@ default = []
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.17"
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.7.1"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
|
||||
@@ -6,7 +6,6 @@ edition = "2021"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
dbus_api = ["blocking", "futures", "zbus"]
|
||||
guest_debug = ["kvm", "gdbstub", "gdbstub_arch"]
|
||||
kvm = ["hypervisor/kvm", "vfio-ioctls/kvm", "vm-device/kvm", "pci/kvm"]
|
||||
mshv = ["hypervisor/mshv", "vfio-ioctls/mshv", "vm-device/mshv", "pci/mshv"]
|
||||
@@ -15,21 +14,19 @@ tracing = ["tracer/tracing"]
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.69"
|
||||
arc-swap = "1.5.1"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "2.3.3"
|
||||
bitflags = "1.3.2"
|
||||
block_util = { path = "../block_util" }
|
||||
blocking = { version = "1.3.0", optional = true }
|
||||
devices = { path = "../devices" }
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
futures = { version = "0.3.27", optional = true }
|
||||
gdbstub = { version = "0.6.4", optional = true }
|
||||
gdbstub_arch = { version = "0.2.4", optional = true }
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
linux-loader = { version = "0.9.0", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.17"
|
||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||
net_util = { path = "../net_util" }
|
||||
@@ -38,25 +35,24 @@ option_parser = { path = "../option_parser" }
|
||||
pci = { path = "../pci" }
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = "0.3.0"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.95"
|
||||
serial_buffer = { path = "../serial_buffer" }
|
||||
signal-hook = "0.3.15"
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.39"
|
||||
tracer = { path = "../tracer" }
|
||||
uuid = "1.3.4"
|
||||
uuid = "1.3.0"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = "0.8.0"
|
||||
virtio-queue = "0.7.1"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
zbus = { version = "3.11.1", optional = true }
|
||||
zerocopy = "0.6.1"
|
||||
zerocopy = "0.6.1"
|
||||
@@ -41,7 +41,7 @@ pub const ACPI_APIC_GENERIC_TRANSLATOR: u8 = 15;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct PciRangeEntry {
|
||||
pub base_address: u64,
|
||||
pub segment: u16,
|
||||
@@ -52,7 +52,7 @@ struct PciRangeEntry {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct MemoryAffinity {
|
||||
pub type_: u8,
|
||||
pub length: u8,
|
||||
@@ -69,7 +69,7 @@ struct MemoryAffinity {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct ProcessorLocalX2ApicAffinity {
|
||||
pub type_: u8,
|
||||
pub length: u8,
|
||||
@@ -83,7 +83,7 @@ struct ProcessorLocalX2ApicAffinity {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct ProcessorGiccAffinity {
|
||||
pub type_: u8,
|
||||
pub length: u8,
|
||||
@@ -143,7 +143,7 @@ impl MemoryAffinity {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct ViotVirtioPciNode {
|
||||
pub type_: u8,
|
||||
_reserved: u8,
|
||||
@@ -155,7 +155,7 @@ struct ViotVirtioPciNode {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct ViotPciRangeNode {
|
||||
pub type_: u8,
|
||||
_reserved: u8,
|
||||
@@ -239,7 +239,7 @@ fn create_facp_table(dsdt_offset: GuestAddress, device_manager: &Arc<Mutex<Devic
|
||||
// X_DSDT
|
||||
facp.write(140, dsdt_offset.0);
|
||||
// Hypervisor Vendor Identity
|
||||
facp.write_bytes(268, b"CLOUDHYP");
|
||||
facp.write(268, b"CLOUDHYP");
|
||||
|
||||
facp.update_checksum();
|
||||
|
||||
|
||||
@@ -1,377 +0,0 @@
|
||||
// Copyright © 2023 Sartura Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
use super::{ApiRequest, VmAction};
|
||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::{Error as VmmError, Result as VmmResult};
|
||||
use crate::{NetConfig, VmConfig};
|
||||
use futures::channel::oneshot;
|
||||
use futures::{executor, FutureExt};
|
||||
use hypervisor::HypervisorType;
|
||||
use seccompiler::{apply_filter, SeccompAction};
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use zbus::fdo::{self, Result};
|
||||
use zbus::zvariant::Optional;
|
||||
use zbus::{dbus_interface, ConnectionBuilder};
|
||||
|
||||
pub type DBusApiShutdownChannels = (oneshot::Sender<()>, oneshot::Receiver<()>);
|
||||
|
||||
pub struct DBusApiOptions {
|
||||
pub service_name: String,
|
||||
pub object_path: String,
|
||||
pub system_bus: bool,
|
||||
}
|
||||
|
||||
pub struct DBusApi {
|
||||
api_notifier: EventFd,
|
||||
api_sender: futures::lock::Mutex<Sender<ApiRequest>>,
|
||||
}
|
||||
|
||||
fn api_error(error: impl std::fmt::Debug) -> fdo::Error {
|
||||
fdo::Error::Failed(format!("{error:?}"))
|
||||
}
|
||||
|
||||
// This method is intended to ensure that the DBusApi thread has enough time to
|
||||
// send a response to the VmmShutdown method call before it is terminated. If
|
||||
// this step is omitted, the thread may be terminated before it can send a
|
||||
// response, resulting in an error message stating that the message recipient
|
||||
// disconnected from the message bus without providing a reply.
|
||||
pub fn dbus_api_graceful_shutdown(ch: DBusApiShutdownChannels) {
|
||||
let (send_shutdown, mut recv_done) = ch;
|
||||
|
||||
// send the shutdown signal and return
|
||||
// if it errors out
|
||||
if send_shutdown.send(()).is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
// loop until `recv_err` errors out
|
||||
// or as long as the return value indicates
|
||||
// "immediately stale" (None)
|
||||
while let Ok(None) = recv_done.try_recv() {}
|
||||
}
|
||||
|
||||
impl DBusApi {
|
||||
pub fn new(api_notifier: EventFd, api_sender: Sender<ApiRequest>) -> Self {
|
||||
Self {
|
||||
api_notifier,
|
||||
api_sender: futures::lock::Mutex::new(api_sender),
|
||||
}
|
||||
}
|
||||
|
||||
async fn clone_api_sender(&self) -> Sender<ApiRequest> {
|
||||
// lock the async mutex, clone the `Sender` and then immediately
|
||||
// drop the MutexGuard so that other tasks can clone the
|
||||
// `Sender` as well
|
||||
self.api_sender.lock().await.clone()
|
||||
}
|
||||
|
||||
fn clone_api_notifier(&self) -> Result<EventFd> {
|
||||
self.api_notifier
|
||||
.try_clone()
|
||||
.map_err(|err| fdo::Error::IOError(format!("{err:?}")))
|
||||
}
|
||||
|
||||
async fn vm_action(&self, action: VmAction) -> Result<Optional<String>> {
|
||||
let api_sender = self.clone_api_sender().await;
|
||||
let api_notifier = self.clone_api_notifier()?;
|
||||
|
||||
let result = blocking::unblock(move || super::vm_action(api_notifier, api_sender, action))
|
||||
.await
|
||||
.map_err(api_error)?
|
||||
// We're using `from_utf8_lossy` here to not deal with the
|
||||
// error case of `from_utf8` as we know that `b.body` is valid JSON.
|
||||
.map(|b| String::from_utf8_lossy(&b.body).to_string());
|
||||
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.cloudhypervisor.DBusApi1")]
|
||||
impl DBusApi {
|
||||
async fn vmm_ping(&self) -> Result<String> {
|
||||
let api_sender = self.clone_api_sender().await;
|
||||
let api_notifier = self.clone_api_notifier()?;
|
||||
|
||||
let result = blocking::unblock(move || super::vmm_ping(api_notifier, api_sender))
|
||||
.await
|
||||
.map_err(api_error)?;
|
||||
serde_json::to_string(&result).map_err(api_error)
|
||||
}
|
||||
|
||||
async fn vmm_shutdown(&self) -> Result<()> {
|
||||
let api_sender = self.clone_api_sender().await;
|
||||
let api_notifier = self.clone_api_notifier()?;
|
||||
|
||||
blocking::unblock(move || super::vmm_shutdown(api_notifier, api_sender))
|
||||
.await
|
||||
.map_err(api_error)
|
||||
}
|
||||
|
||||
async fn vm_add_device(&self, device_config: String) -> Result<Optional<String>> {
|
||||
let device_config = serde_json::from_str(&device_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddDevice(Arc::new(device_config)))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vm_add_disk(&self, disk_config: String) -> Result<Optional<String>> {
|
||||
let disk_config = serde_json::from_str(&disk_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddDisk(Arc::new(disk_config)))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vm_add_fs(&self, fs_config: String) -> Result<Optional<String>> {
|
||||
let fs_config = serde_json::from_str(&fs_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddFs(Arc::new(fs_config))).await
|
||||
}
|
||||
|
||||
async fn vm_add_net(&self, net_config: String) -> Result<Optional<String>> {
|
||||
let mut net_config: NetConfig = serde_json::from_str(&net_config).map_err(api_error)?;
|
||||
if net_config.fds.is_some() {
|
||||
warn!("Ignoring FDs sent via the D-Bus request body");
|
||||
net_config.fds = None;
|
||||
}
|
||||
self.vm_action(VmAction::AddNet(Arc::new(net_config))).await
|
||||
}
|
||||
|
||||
async fn vm_add_pmem(&self, pmem_config: String) -> Result<Optional<String>> {
|
||||
let pmem_config = serde_json::from_str(&pmem_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddPmem(Arc::new(pmem_config)))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vm_add_user_device(&self, vm_add_user_device: String) -> Result<Optional<String>> {
|
||||
let vm_add_user_device = serde_json::from_str(&vm_add_user_device).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddUserDevice(Arc::new(vm_add_user_device)))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vm_add_vdpa(&self, vdpa_config: String) -> Result<Optional<String>> {
|
||||
let vdpa_config = serde_json::from_str(&vdpa_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddVdpa(Arc::new(vdpa_config)))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vm_add_vsock(&self, vsock_config: String) -> Result<Optional<String>> {
|
||||
let vsock_config = serde_json::from_str(&vsock_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::AddVsock(Arc::new(vsock_config)))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vm_boot(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::Boot).await.map(|_| ())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
// zbus doesn't support cfg attributes on interface methods
|
||||
// as a workaround, we make the *call to the internal API* conditionally
|
||||
// compile and return an error on unsupported platforms.
|
||||
async fn vm_coredump(&self, vm_coredump_data: String) -> Result<()> {
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
{
|
||||
let vm_coredump_data = serde_json::from_str(&vm_coredump_data).map_err(api_error)?;
|
||||
self.vm_action(VmAction::Coredump(Arc::new(vm_coredump_data)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "x86_64", feature = "guest_debug")))]
|
||||
Err(api_error(
|
||||
"VmCoredump only works on x86_64 with the `guest_debug` feature enabled",
|
||||
))
|
||||
}
|
||||
|
||||
async fn vm_counters(&self) -> Result<Optional<String>> {
|
||||
self.vm_action(VmAction::Counters).await
|
||||
}
|
||||
|
||||
async fn vm_create(&self, vm_config: String) -> Result<()> {
|
||||
let api_sender = self.clone_api_sender().await;
|
||||
let api_notifier = self.clone_api_notifier()?;
|
||||
|
||||
let mut vm_config: VmConfig = serde_json::from_str(&vm_config).map_err(api_error)?;
|
||||
|
||||
if let Some(ref mut nets) = vm_config.net {
|
||||
if nets.iter().any(|net| net.fds.is_some()) {
|
||||
warn!("Ignoring FDs sent via the D-Bus request body");
|
||||
}
|
||||
for net in nets {
|
||||
net.fds = None;
|
||||
}
|
||||
}
|
||||
|
||||
blocking::unblock(move || {
|
||||
super::vm_create(api_notifier, api_sender, Arc::new(Mutex::new(vm_config)))
|
||||
})
|
||||
.await
|
||||
.map_err(api_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn vm_delete(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::Delete).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_info(&self) -> Result<String> {
|
||||
let api_sender = self.clone_api_sender().await;
|
||||
let api_notifier = self.clone_api_notifier()?;
|
||||
|
||||
let result = blocking::unblock(move || super::vm_info(api_notifier, api_sender))
|
||||
.await
|
||||
.map_err(api_error)?;
|
||||
serde_json::to_string(&result).map_err(api_error)
|
||||
}
|
||||
|
||||
async fn vm_pause(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::Pause).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_power_button(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::PowerButton).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_reboot(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::Reboot).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_remove_device(&self, vm_remove_device: String) -> Result<()> {
|
||||
let vm_remove_device = serde_json::from_str(&vm_remove_device).map_err(api_error)?;
|
||||
self.vm_action(VmAction::RemoveDevice(Arc::new(vm_remove_device)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_resize(&self, vm_resize: String) -> Result<()> {
|
||||
let vm_resize = serde_json::from_str(&vm_resize).map_err(api_error)?;
|
||||
self.vm_action(VmAction::Resize(Arc::new(vm_resize)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_resize_zone(&self, vm_resize_zone: String) -> Result<()> {
|
||||
let vm_resize_zone = serde_json::from_str(&vm_resize_zone).map_err(api_error)?;
|
||||
self.vm_action(VmAction::ResizeZone(Arc::new(vm_resize_zone)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_restore(&self, restore_config: String) -> Result<()> {
|
||||
let restore_config = serde_json::from_str(&restore_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::Restore(Arc::new(restore_config)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_receive_migration(&self, receive_migration_data: String) -> Result<()> {
|
||||
let receive_migration_data =
|
||||
serde_json::from_str(&receive_migration_data).map_err(api_error)?;
|
||||
self.vm_action(VmAction::ReceiveMigration(Arc::new(receive_migration_data)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_send_migration(&self, send_migration_data: String) -> Result<()> {
|
||||
let send_migration_data = serde_json::from_str(&send_migration_data).map_err(api_error)?;
|
||||
self.vm_action(VmAction::SendMigration(Arc::new(send_migration_data)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_resume(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::Resume).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_shutdown(&self) -> Result<()> {
|
||||
self.vm_action(VmAction::Shutdown).await.map(|_| ())
|
||||
}
|
||||
|
||||
async fn vm_snapshot(&self, vm_snapshot_config: String) -> Result<()> {
|
||||
let vm_snapshot_config = serde_json::from_str(&vm_snapshot_config).map_err(api_error)?;
|
||||
self.vm_action(VmAction::Snapshot(Arc::new(vm_snapshot_config)))
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_dbus_thread(
|
||||
dbus_options: DBusApiOptions,
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
seccomp_action: &SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
hypervisor_type: HypervisorType,
|
||||
) -> VmmResult<(thread::JoinHandle<VmmResult<()>>, DBusApiShutdownChannels)> {
|
||||
let dbus_iface = DBusApi::new(api_notifier, api_sender);
|
||||
let connection = executor::block_on(async move {
|
||||
let conn_builder = if dbus_options.system_bus {
|
||||
ConnectionBuilder::system()?
|
||||
} else {
|
||||
ConnectionBuilder::session()?
|
||||
};
|
||||
|
||||
conn_builder
|
||||
.internal_executor(false)
|
||||
.name(dbus_options.service_name)?
|
||||
.serve_at(dbus_options.object_path, dbus_iface)?
|
||||
.build()
|
||||
.await
|
||||
})
|
||||
.map_err(VmmError::CreateDBusSession)?;
|
||||
|
||||
let (send_shutdown, recv_shutdown) = oneshot::channel::<()>();
|
||||
let (send_done, recv_done) = oneshot::channel::<()>();
|
||||
|
||||
// Retrieve seccomp filter for API thread
|
||||
let api_seccomp_filter = get_seccomp_filter(seccomp_action, Thread::DBusApi, hypervisor_type)
|
||||
.map_err(VmmError::CreateSeccompFilter)?;
|
||||
|
||||
let thread_join_handle = thread::Builder::new()
|
||||
.name("dbus-thread".to_string())
|
||||
.spawn(move || {
|
||||
// Apply seccomp filter for API thread.
|
||||
if !api_seccomp_filter.is_empty() {
|
||||
apply_filter(&api_seccomp_filter)
|
||||
.map_err(VmmError::ApplySeccompFilter)
|
||||
.map_err(|e| {
|
||||
error!("Error applying seccomp filter: {:?}", e);
|
||||
exit_evt.write(1).ok();
|
||||
e
|
||||
})?;
|
||||
}
|
||||
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
executor::block_on(async move {
|
||||
let recv_shutdown = recv_shutdown.fuse();
|
||||
let executor_tick = futures::future::Fuse::terminated();
|
||||
futures::pin_mut!(recv_shutdown, executor_tick);
|
||||
executor_tick.set(connection.executor().tick().fuse());
|
||||
|
||||
loop {
|
||||
futures::select! {
|
||||
_ = executor_tick => executor_tick.set(connection.executor().tick().fuse()),
|
||||
_ = recv_shutdown => {
|
||||
send_done.send(()).ok();
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
}))
|
||||
.map_err(|_| {
|
||||
error!("dbus-api thread panicked");
|
||||
exit_evt.write(1).ok()
|
||||
})
|
||||
.ok();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(VmmError::DBusThreadSpawn)?;
|
||||
|
||||
Ok((thread_join_handle, (send_shutdown, recv_done)))
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use self::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdown};
|
||||
use crate::api::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdown};
|
||||
use crate::api::{ApiError, ApiRequest, VmAction};
|
||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::{Error as VmmError, Result};
|
||||
@@ -23,8 +23,6 @@ use std::sync::Arc;
|
||||
use std::thread;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub mod http_endpoint;
|
||||
|
||||
/// Errors associated with VMM management
|
||||
#[derive(Debug)]
|
||||
pub enum HttpError {
|
||||
@@ -284,7 +282,7 @@ fn start_http_thread(
|
||||
hypervisor_type: HypervisorType,
|
||||
) -> Result<thread::JoinHandle<Result<()>>> {
|
||||
// Retrieve seccomp filter for API thread
|
||||
let api_seccomp_filter = get_seccomp_filter(seccomp_action, Thread::HttpApi, hypervisor_type)
|
||||
let api_seccomp_filter = get_seccomp_filter(seccomp_action, Thread::Api, hypervisor_type)
|
||||
.map_err(VmmError::CreateSeccompFilter)?;
|
||||
|
||||
thread::Builder::new()
|
||||
@@ -28,15 +28,12 @@
|
||||
//! response channel Receiver.
|
||||
//! 5. The thread handles the response and forwards potential errors.
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
pub mod dbus;
|
||||
pub mod http;
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
pub use self::dbus::start_dbus_thread;
|
||||
pub use self::http::start_http_fd_thread;
|
||||
pub use self::http::start_http_path_thread;
|
||||
|
||||
pub mod http;
|
||||
pub mod http_endpoint;
|
||||
|
||||
use crate::config::{
|
||||
DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, UserDeviceConfig,
|
||||
VdpaConfig, VmConfig, VsockConfig,
|
||||
@@ -168,9 +165,7 @@ pub struct VmInfo {
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct VmmPingResponse {
|
||||
pub build_version: String,
|
||||
pub version: String,
|
||||
pub pid: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize, Default, Debug)]
|
||||
@@ -235,6 +230,7 @@ pub enum ApiResponsePayload {
|
||||
/// This is the response sent by the VMM API server through the mpsc channel.
|
||||
pub type ApiResponse = std::result::Result<ApiResponsePayload, ApiError>;
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug)]
|
||||
pub enum ApiRequest {
|
||||
/// Create the virtual machine. This request payload is a VM configuration
|
||||
|
||||
@@ -438,13 +438,8 @@ components:
|
||||
- version
|
||||
type: object
|
||||
properties:
|
||||
build_version:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
pid:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Virtual Machine Monitor information
|
||||
|
||||
VmInfo:
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
use virtio_devices::{RateLimiterConfig, TokenBucketConfig};
|
||||
|
||||
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
|
||||
const MAX_NUM_PCI_SEGMENTS: u16 = 16;
|
||||
|
||||
/// Errors associated with VM configuration parameters.
|
||||
#[derive(Debug, Error)]
|
||||
@@ -2947,26 +2947,24 @@ mod tests {
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
..Default::default()
|
||||
});
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS + 1,
|
||||
num_pci_segments: 17,
|
||||
..Default::default()
|
||||
});
|
||||
assert_eq!(
|
||||
invalid_config.validate(),
|
||||
Err(ValidationError::InvalidNumPciSegments(
|
||||
MAX_NUM_PCI_SEGMENTS + 1
|
||||
))
|
||||
Err(ValidationError::InvalidNumPciSegments(17))
|
||||
);
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -2974,18 +2972,18 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
iommu_segments: Some(vec![MAX_NUM_PCI_SEGMENTS + 1, MAX_NUM_PCI_SEGMENTS + 2]),
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![17, 18]),
|
||||
..Default::default()
|
||||
});
|
||||
assert_eq!(
|
||||
invalid_config.validate(),
|
||||
Err(ValidationError::InvalidPciSegment(MAX_NUM_PCI_SEGMENTS + 1))
|
||||
Err(ValidationError::InvalidPciSegment(17))
|
||||
);
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -2998,7 +2996,7 @@ mod tests {
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3011,7 +3009,7 @@ mod tests {
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3024,7 +3022,7 @@ mod tests {
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3037,7 +3035,7 @@ mod tests {
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3050,7 +3048,7 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3066,7 +3064,7 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3082,7 +3080,7 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3098,7 +3096,7 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3114,7 +3112,7 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3131,7 +3129,7 @@ mod tests {
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.memory.shared = true;
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3146,7 +3144,7 @@ mod tests {
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
@@ -3162,7 +3160,7 @@ mod tests {
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.memory.shared = true;
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
@@ -84,7 +84,6 @@ use vm_migration::{
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::{register_signal_handler, SIGRTMIN};
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
#[cfg(all(target_arch = "aarch64", feature = "guest_debug"))]
|
||||
/// Extract the specified bits of a 64-bit integer.
|
||||
@@ -98,13 +97,6 @@ macro_rules! extract_bits_64 {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "aarch64", feature = "guest_debug"))]
|
||||
macro_rules! extract_bits_64_without_offset {
|
||||
($value: tt, $length: tt) => {
|
||||
$value & (!0u64 >> (64 - $length))
|
||||
};
|
||||
}
|
||||
|
||||
pub const CPU_MANAGER_ACPI_SIZE: usize = 0xc;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -184,7 +176,6 @@ pub type Result<T> = result::Result<T, Error>;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(AsBytes)]
|
||||
struct LocalApic {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -195,7 +186,7 @@ struct LocalApic {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct Ioapic {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -208,7 +199,6 @@ struct Ioapic {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(AsBytes)]
|
||||
struct GicC {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -233,7 +223,6 @@ struct GicC {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(AsBytes)]
|
||||
struct GicD {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -248,7 +237,6 @@ struct GicD {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(AsBytes)]
|
||||
struct GicR {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -260,7 +248,6 @@ struct GicR {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(AsBytes)]
|
||||
struct GicIts {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -273,7 +260,6 @@ struct GicIts {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(AsBytes)]
|
||||
struct ProcessorHierarchyNode {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -286,7 +272,7 @@ struct ProcessorHierarchyNode {
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
#[derive(Default, AsBytes)]
|
||||
#[derive(Default)]
|
||||
struct InterruptSourceOverride {
|
||||
pub r#type: u8,
|
||||
pub length: u8,
|
||||
@@ -723,7 +709,7 @@ impl CpuManager {
|
||||
);
|
||||
|
||||
self.cpuid = {
|
||||
let phys_bits = physical_bits(hypervisor, self.config.max_phys_bits);
|
||||
let phys_bits = physical_bits(self.config.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
hypervisor,
|
||||
topology,
|
||||
@@ -1290,7 +1276,7 @@ impl CpuManager {
|
||||
let mut madt = Sdt::new(*b"APIC", 44, 5, *b"CLOUDH", *b"CHMADT ", 1);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
madt.write(36, arch::layout::APIC_START.0);
|
||||
madt.write(36, arch::layout::APIC_START);
|
||||
|
||||
for cpu in 0..self.config.max_vcpus {
|
||||
let lapic = LocalApic {
|
||||
@@ -1618,7 +1604,8 @@ impl CpuManager {
|
||||
|
||||
// PA or IPA size is determined
|
||||
let tcr_ips = extract_bits_64!(tcr_el1, 32, 3);
|
||||
let pa_range = extract_bits_64_without_offset!(id_aa64mmfr0_el1, 4);
|
||||
#[allow(clippy::identity_op)]
|
||||
let pa_range = extract_bits_64!(id_aa64mmfr0_el1, 0, 4);
|
||||
// The IPA size in TCR_BL1 and PA Range in ID_AA64MMFR0_EL1 should match.
|
||||
// To be safe, we use the minimum value if they are different.
|
||||
let pa_range = std::cmp::min(tcr_ips, pa_range);
|
||||
@@ -1651,7 +1638,8 @@ impl CpuManager {
|
||||
let descaddrmask = descaddrmask & !indexmask_grainsize;
|
||||
|
||||
// Translation table base address
|
||||
let mut descaddr: u64 = extract_bits_64_without_offset!(ttbr1_el1, 48);
|
||||
#[allow(clippy::identity_op)]
|
||||
let mut descaddr: u64 = extract_bits_64!(ttbr1_el1, 0, 48);
|
||||
// In the case of FEAT_LPA and FEAT_LPA2, the initial translation table
|
||||
// addresss bits [48:51] comes from TTBR1_EL1 bits [2:5].
|
||||
if pa_size == 52 {
|
||||
@@ -1992,7 +1980,6 @@ impl Aml for CpuManager {
|
||||
true,
|
||||
acpi_address.0,
|
||||
acpi_address.0 + CPU_MANAGER_ACPI_SIZE as u64 - 1,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
// OpRegion and Fields map MMIO range into individual field values
|
||||
|
||||
@@ -4278,7 +4278,7 @@ impl Aml for DeviceManager {
|
||||
let mut pci_scan_methods = Vec::new();
|
||||
for i in 0..self.pci_segments.len() {
|
||||
pci_scan_methods.push(aml::MethodCall::new(
|
||||
format!("\\_SB_.PC{i:02X}.PCNT").as_str().into(),
|
||||
format!("\\_SB_.PCI{i:X}.PCNT").as_str().into(),
|
||||
vec![],
|
||||
));
|
||||
}
|
||||
@@ -4302,7 +4302,6 @@ impl Aml for DeviceManager {
|
||||
true,
|
||||
self.acpi_address.0,
|
||||
self.acpi_address.0 + DEVICE_MANAGER_ACPI_SIZE as u64 - 1,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
// OpRegion and Fields map MMIO range into individual field values
|
||||
|
||||
@@ -109,8 +109,7 @@ pub struct BftIter<'a> {
|
||||
|
||||
impl<'a> BftIter<'a> {
|
||||
fn new(hash_map: &'a HashMap<String, DeviceNode>) -> Self {
|
||||
let mut nodes = Vec::with_capacity(hash_map.len());
|
||||
let mut i = 0;
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
for (_, node) in hash_map.iter() {
|
||||
if node.parent.is_none() {
|
||||
@@ -118,13 +117,26 @@ impl<'a> BftIter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
while i < nodes.len() {
|
||||
for child_node_id in nodes[i].children.iter() {
|
||||
if let Some(child_node) = hash_map.get(child_node_id) {
|
||||
nodes.push(child_node);
|
||||
let mut node_layer = nodes.as_slice();
|
||||
loop {
|
||||
let mut next_node_layer = Vec::new();
|
||||
|
||||
for node in node_layer.iter() {
|
||||
for child_node_id in node.children.iter() {
|
||||
if let Some(child_node) = hash_map.get(child_node_id) {
|
||||
next_node_layer.push(child_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
|
||||
if next_node_layer.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let pos = nodes.len();
|
||||
nodes.extend(next_node_layer);
|
||||
|
||||
node_layer = &nodes[pos..];
|
||||
}
|
||||
|
||||
BftIter { nodes }
|
||||
|
||||
@@ -435,6 +435,7 @@ impl run_blocking::BlockingEventLoop for GdbEventLoop {
|
||||
type Connection = Box<dyn ConnectionExt<Error = std::io::Error>>;
|
||||
type StopReason = MultiThreadStopReason<ArchUsize>;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn wait_for_stop_reason(
|
||||
target: &mut Self::Target,
|
||||
conn: &mut Self::Connection,
|
||||
|
||||
@@ -25,8 +25,6 @@ use crate::migration::{recv_vm_config, recv_vm_state};
|
||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::vm::{Error as VmError, Vm, VmState};
|
||||
use anyhow::anyhow;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use api::dbus::{DBusApiOptions, DBusApiShutdownChannels};
|
||||
use libc::{tcsetattr, termios, EFD_NONBLOCK, SIGINT, SIGTERM, TCSANOW};
|
||||
use memory_manager::MemoryManagerSnapshotData;
|
||||
use pci::PciBdf;
|
||||
@@ -82,6 +80,7 @@ type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
|
||||
|
||||
/// Errors associated with VMM management
|
||||
#[derive(Debug, Error)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum Error {
|
||||
/// API request receive error
|
||||
#[error("Error receiving API request: {0}")]
|
||||
@@ -115,16 +114,6 @@ pub enum Error {
|
||||
#[error("Error spawning HTTP thread: {0}")]
|
||||
HttpThreadSpawn(#[source] io::Error),
|
||||
|
||||
/// Cannot create D-Bus thread
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("Error spawning D-Bus thread: {0}")]
|
||||
DBusThreadSpawn(#[source] io::Error),
|
||||
|
||||
/// Cannot start D-Bus session
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("Error starting D-Bus session: {0}")]
|
||||
CreateDBusSession(#[source] zbus::Error),
|
||||
|
||||
/// Cannot handle the VM STDIN stream
|
||||
#[error("Error handling VM stdin: {0:?}")]
|
||||
Stdin(VmError),
|
||||
@@ -291,10 +280,9 @@ impl Serialize for PciDeviceInfo {
|
||||
#[allow(unused_variables)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn start_vmm_thread(
|
||||
vmm_version: VmmVersionInfo,
|
||||
vmm_version: String,
|
||||
http_path: &Option<String>,
|
||||
http_fd: Option<RawFd>,
|
||||
#[cfg(feature = "dbus_api")] dbus_options: Option<DBusApiOptions>,
|
||||
api_event: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
api_receiver: Receiver<ApiRequest>,
|
||||
@@ -304,7 +292,7 @@ pub fn start_vmm_thread(
|
||||
exit_event: EventFd,
|
||||
seccomp_action: &SeccompAction,
|
||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||
) -> Result<VmmThreadHandle> {
|
||||
) -> Result<thread::JoinHandle<Result<()>>> {
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let gdb_hw_breakpoints = hypervisor.get_guest_debug_hw_bps();
|
||||
#[cfg(feature = "guest_debug")]
|
||||
@@ -314,7 +302,7 @@ pub fn start_vmm_thread(
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let gdb_vm_debug_event = vm_debug_event.try_clone().map_err(Error::EventFdClone)?;
|
||||
|
||||
let api_event_clone = api_event.try_clone().map_err(Error::EventFdClone)?;
|
||||
let http_api_event = api_event.try_clone().map_err(Error::EventFdClone)?;
|
||||
let hypervisor_type = hypervisor.hypervisor_type();
|
||||
|
||||
// Retrieve seccomp filter
|
||||
@@ -333,7 +321,7 @@ pub fn start_vmm_thread(
|
||||
}
|
||||
|
||||
let mut vmm = Vmm::new(
|
||||
vmm_version,
|
||||
vmm_version.to_string(),
|
||||
api_event,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
debug_event,
|
||||
@@ -355,28 +343,11 @@ pub fn start_vmm_thread(
|
||||
.map_err(Error::VmmThreadSpawn)?
|
||||
};
|
||||
|
||||
// The VMM thread is started, we can start the dbus thread
|
||||
// and start serving HTTP requests
|
||||
#[cfg(feature = "dbus_api")]
|
||||
let dbus_shutdown_chs = match dbus_options {
|
||||
Some(opts) => {
|
||||
let (_, chs) = api::start_dbus_thread(
|
||||
opts,
|
||||
api_event_clone.try_clone().map_err(Error::EventFdClone)?,
|
||||
api_sender.clone(),
|
||||
seccomp_action,
|
||||
exit_event.try_clone().map_err(Error::EventFdClone)?,
|
||||
hypervisor_type,
|
||||
)?;
|
||||
Some(chs)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
// The VMM thread is started, we can start serving HTTP requests
|
||||
if let Some(http_path) = http_path {
|
||||
api::start_http_path_thread(
|
||||
http_path,
|
||||
api_event_clone,
|
||||
http_api_event,
|
||||
api_sender,
|
||||
seccomp_action,
|
||||
exit_event,
|
||||
@@ -385,7 +356,7 @@ pub fn start_vmm_thread(
|
||||
} else if let Some(http_fd) = http_fd {
|
||||
api::start_http_fd_thread(
|
||||
http_fd,
|
||||
api_event_clone,
|
||||
http_api_event,
|
||||
api_sender,
|
||||
seccomp_action,
|
||||
exit_event,
|
||||
@@ -407,11 +378,7 @@ pub fn start_vmm_thread(
|
||||
.map_err(Error::GdbThreadSpawn)?;
|
||||
}
|
||||
|
||||
Ok(VmmThreadHandle {
|
||||
thread_handle: thread,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
dbus_shutdown_chs,
|
||||
})
|
||||
Ok(thread)
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
@@ -422,27 +389,6 @@ struct VmMigrationConfig {
|
||||
memory_manager_data: MemoryManagerSnapshotData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VmmVersionInfo {
|
||||
pub build_version: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl VmmVersionInfo {
|
||||
pub fn new(build_version: &str, version: &str) -> Self {
|
||||
Self {
|
||||
build_version: build_version.to_owned(),
|
||||
version: version.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VmmThreadHandle {
|
||||
pub thread_handle: thread::JoinHandle<Result<()>>,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
pub dbus_shutdown_chs: Option<DBusApiShutdownChannels>,
|
||||
}
|
||||
|
||||
pub struct Vmm {
|
||||
epoll: EpollContext,
|
||||
exit_evt: EventFd,
|
||||
@@ -452,7 +398,7 @@ pub struct Vmm {
|
||||
debug_evt: EventFd,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
vm_debug_evt: EventFd,
|
||||
version: VmmVersionInfo,
|
||||
version: String,
|
||||
vm: Option<Vm>,
|
||||
vm_config: Option<Arc<Mutex<VmConfig>>>,
|
||||
seccomp_action: SeccompAction,
|
||||
@@ -544,7 +490,7 @@ impl Vmm {
|
||||
}
|
||||
|
||||
fn new(
|
||||
vmm_version: VmmVersionInfo,
|
||||
vmm_version: String,
|
||||
api_evt: EventFd,
|
||||
#[cfg(feature = "guest_debug")] debug_evt: EventFd,
|
||||
#[cfg(feature = "guest_debug")] vm_debug_evt: EventFd,
|
||||
@@ -868,15 +814,8 @@ impl Vmm {
|
||||
}
|
||||
|
||||
fn vmm_ping(&self) -> VmmPingResponse {
|
||||
let VmmVersionInfo {
|
||||
build_version,
|
||||
version,
|
||||
} = self.version.clone();
|
||||
|
||||
VmmPingResponse {
|
||||
build_version,
|
||||
version,
|
||||
pid: std::process::id() as i64,
|
||||
version: self.version.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1259,8 +1198,7 @@ impl Vmm {
|
||||
))
|
||||
})?;
|
||||
|
||||
let phys_bits =
|
||||
vm::physical_bits(&self.hypervisor, config.lock().unwrap().cpus.max_phys_bits);
|
||||
let phys_bits = vm::physical_bits(config.lock().unwrap().cpus.max_phys_bits);
|
||||
|
||||
let memory_manager = MemoryManager::new(
|
||||
vm,
|
||||
@@ -1576,8 +1514,7 @@ impl Vmm {
|
||||
let vm_config = vm.get_config();
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
let common_cpuid = {
|
||||
let phys_bits =
|
||||
vm::physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits);
|
||||
let phys_bits = vm::physical_bits(vm_config.lock().unwrap().cpus.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
&hypervisor,
|
||||
None,
|
||||
@@ -1767,7 +1704,7 @@ impl Vmm {
|
||||
let dest_cpuid = &{
|
||||
let vm_config = &src_vm_config.lock().unwrap();
|
||||
|
||||
let phys_bits = vm::physical_bits(&self.hypervisor, vm_config.cpus.max_phys_bits);
|
||||
let phys_bits = vm::physical_bits(vm_config.cpus.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
&self.hypervisor.clone(),
|
||||
None,
|
||||
@@ -2133,7 +2070,7 @@ mod unit_tests {
|
||||
|
||||
fn create_dummy_vmm() -> Vmm {
|
||||
Vmm::new(
|
||||
VmmVersionInfo::new("dummy", "dummy"),
|
||||
"dummy".to_string(),
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
#[cfg(feature = "guest_debug")]
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
|
||||
@@ -2334,7 +2334,6 @@ impl Aml for MemoryMethods {
|
||||
true,
|
||||
0x0000_0000_0000_0000u64,
|
||||
0xFFFF_FFFF_FFFF_FFFEu64,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
&aml::CreateQWordField::new(
|
||||
@@ -2417,7 +2416,6 @@ impl Aml for MemoryManager {
|
||||
true,
|
||||
acpi_address.0,
|
||||
acpi_address.0 + MEMORY_MANAGER_ACPI_SIZE as u64 - 1,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
// OpRegion and Fields map MMIO range into individual field values
|
||||
@@ -2513,7 +2511,6 @@ impl Aml for MemoryManager {
|
||||
true,
|
||||
min,
|
||||
max,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
&aml::Method::new("_STA".into(), 0, false, vec![&aml::Return::new(&0xfu8)]),
|
||||
|
||||
@@ -353,19 +353,17 @@ impl Aml for PciSegment {
|
||||
layout::MEM_32BIT_DEVICES_START.0 as u32,
|
||||
(layout::MEM_32BIT_DEVICES_START.0 + layout::MEM_32BIT_DEVICES_SIZE - 1)
|
||||
as u32,
|
||||
None,
|
||||
),
|
||||
&aml::AddressSpace::new_memory(
|
||||
aml::AddressSpaceCachable::NotCacheable,
|
||||
true,
|
||||
self.start_of_device_area,
|
||||
self.end_of_device_area,
|
||||
None,
|
||||
),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
&aml::AddressSpace::new_io(0u16, 0x0cf7u16, None),
|
||||
&aml::AddressSpace::new_io(0u16, 0x0cf7u16),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
&aml::AddressSpace::new_io(0x0d00u16, 0xffffu16, None),
|
||||
&aml::AddressSpace::new_io(0x0d00u16, 0xffffu16),
|
||||
]),
|
||||
)
|
||||
} else {
|
||||
@@ -383,7 +381,6 @@ impl Aml for PciSegment {
|
||||
true,
|
||||
self.start_of_device_area,
|
||||
self.end_of_device_area,
|
||||
None,
|
||||
),
|
||||
]),
|
||||
)
|
||||
@@ -421,7 +418,7 @@ impl Aml for PciSegment {
|
||||
pci_dsdt_inner_data.push(&prt);
|
||||
|
||||
aml::Device::new(
|
||||
format!("_SB_.PC{:02X}", self.id).as_str().into(),
|
||||
format!("_SB_.PCI{:X}", self.id).as_str().into(),
|
||||
pci_dsdt_inner_data,
|
||||
)
|
||||
.to_aml_bytes(sink)
|
||||
|
||||
@@ -12,9 +12,7 @@ use seccompiler::{
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub enum Thread {
|
||||
HttpApi,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApi,
|
||||
Api,
|
||||
SignalHandler,
|
||||
Vcpu,
|
||||
Vmm,
|
||||
@@ -748,9 +746,9 @@ fn vcpu_thread_rules(
|
||||
])
|
||||
}
|
||||
|
||||
// The filter containing the white listed syscall rules required by the HTTP API to
|
||||
// The filter containing the white listed syscall rules required by the API to
|
||||
// function.
|
||||
fn http_api_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
fn api_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
Ok(vec![
|
||||
(libc::SYS_accept4, vec![]),
|
||||
(libc::SYS_brk, vec![]),
|
||||
@@ -777,50 +775,12 @@ fn http_api_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError>
|
||||
])
|
||||
}
|
||||
|
||||
// The filter containing the white listed syscall rules required by the D-Bus API
|
||||
// to function.
|
||||
#[cfg(feature = "dbus_api")]
|
||||
fn dbus_api_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
Ok(vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_clone, vec![]),
|
||||
(libc::SYS_clone3, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_getrandom, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_recvmsg, vec![]),
|
||||
// musl is missing this constant
|
||||
// (libc::SYS_rseq, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(334, vec![]),
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
(293, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sched_getaffinity, vec![]),
|
||||
(libc::SYS_sendmsg, vec![]),
|
||||
(libc::SYS_set_robust_list, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_seccomp_rules(
|
||||
thread_type: Thread,
|
||||
hypervisor_type: HypervisorType,
|
||||
) -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
match thread_type {
|
||||
Thread::HttpApi => Ok(http_api_thread_rules()?),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
Thread::DBusApi => Ok(dbus_api_thread_rules()?),
|
||||
Thread::Api => Ok(api_thread_rules()?),
|
||||
Thread::SignalHandler => Ok(signal_handler_thread_rules()?),
|
||||
Thread::Vcpu => Ok(vcpu_thread_rules(hypervisor_type)?),
|
||||
Thread::Vmm => Ok(vmm_thread_rules(hypervisor_type)?),
|
||||
|
||||
@@ -417,8 +417,8 @@ impl VmOps for VmOpsHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn physical_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>, max_phys_bits: u8) -> u8 {
|
||||
let host_phys_bits = get_host_cpu_phys_bits(hypervisor);
|
||||
pub fn physical_bits(max_phys_bits: u8) -> u8 {
|
||||
let host_phys_bits = get_host_cpu_phys_bits();
|
||||
|
||||
cmp::min(host_phys_bits, max_phys_bits)
|
||||
}
|
||||
@@ -762,7 +762,7 @@ impl Vm {
|
||||
tdx_enabled,
|
||||
)?;
|
||||
|
||||
let phys_bits = physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits);
|
||||
let phys_bits = physical_bits(vm_config.lock().unwrap().cpus.max_phys_bits);
|
||||
|
||||
let memory_manager = if let Some(snapshot) =
|
||||
snapshot_from_id(snapshot.as_ref(), MEMORY_MANAGER_SNAPSHOT_ID)
|
||||
@@ -2413,10 +2413,7 @@ impl Snapshottable for Vm {
|
||||
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
let common_cpuid = {
|
||||
let phys_bits = physical_bits(
|
||||
&self.hypervisor,
|
||||
self.config.lock().unwrap().cpus.max_phys_bits,
|
||||
);
|
||||
let phys_bits = physical_bits(self.config.lock().unwrap().cpus.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
&self.hypervisor,
|
||||
None,
|
||||
|
||||
Reference in New Issue
Block a user